| @@ -1,1700 +1,1698 @@ | | | @@ -1,1700 +1,1698 @@ |
1 | /* -*- Mode: C; tab-width: 4 -*- | | 1 | /* -*- Mode: C; tab-width: 4 -*- |
2 | * | | 2 | * |
3 | * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved. | | 3 | * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved. |
4 | * | | 4 | * |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | | 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
6 | * you may not use this file except in compliance with the License. | | 6 | * you may not use this file except in compliance with the License. |
7 | * You may obtain a copy of the License at | | 7 | * You may obtain a copy of the License at |
8 | * | | 8 | * |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | | 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
10 | * | | 10 | * |
11 | * Unless required by applicable law or agreed to in writing, software | | 11 | * Unless required by applicable law or agreed to in writing, software |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | | 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | | 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | * See the License for the specific language governing permissions and | | 14 | * See the License for the specific language governing permissions and |
15 | * limitations under the License. | | 15 | * limitations under the License. |
16 | * | | 16 | * |
17 | * This code is completely 100% portable C. It does not depend on any external header files | | 17 | * This code is completely 100% portable C. It does not depend on any external header files |
18 | * from outside the mDNS project -- all the types it expects to find are defined right here. | | 18 | * from outside the mDNS project -- all the types it expects to find are defined right here. |
19 | * | | 19 | * |
20 | * The previous point is very important: This file does not depend on any external | | 20 | * The previous point is very important: This file does not depend on any external |
21 | * header files. It should compile on *any* platform that has a C compiler, without | | 21 | * header files. It should compile on *any* platform that has a C compiler, without |
22 | * making *any* assumptions about availability of so-called "standard" C functions, | | 22 | * making *any* assumptions about availability of so-called "standard" C functions, |
23 | * routines, or types (which may or may not be present on any given platform). | | 23 | * routines, or types (which may or may not be present on any given platform). |
24 | | | 24 | |
25 | * Formatting notes: | | 25 | * Formatting notes: |
26 | * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion | | 26 | * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion |
27 | * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>, | | 27 | * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>, |
28 | * but for the sake of brevity here I will say just this: Curly braces are not syntactially | | 28 | * but for the sake of brevity here I will say just this: Curly braces are not syntactially |
29 | * part of an "if" statement; they are the beginning and ending markers of a compound statement; | | 29 | * part of an "if" statement; they are the beginning and ending markers of a compound statement; |
30 | * therefore common sense dictates that if they are part of a compound statement then they | | 30 | * therefore common sense dictates that if they are part of a compound statement then they |
31 | * should be indented to the same level as everything else in that compound statement. | | 31 | * should be indented to the same level as everything else in that compound statement. |
32 | * Indenting curly braces at the same level as the "if" implies that curly braces are | | 32 | * Indenting curly braces at the same level as the "if" implies that curly braces are |
33 | * part of the "if", which is false. (This is as misleading as people who write "char* x,y;" | | 33 | * part of the "if", which is false. (This is as misleading as people who write "char* x,y;" |
34 | * thinking that variables x and y are both of type "char*" -- and anyone who doesn't | | 34 | * thinking that variables x and y are both of type "char*" -- and anyone who doesn't |
35 | * understand why variable y is not of type "char*" just proves the point that poor code | | 35 | * understand why variable y is not of type "char*" just proves the point that poor code |
36 | * layout leads people to unfortunate misunderstandings about how the C language really works.) | | 36 | * layout leads people to unfortunate misunderstandings about how the C language really works.) |
37 | */ | | 37 | */ |
38 | | | 38 | |
39 | #include "DNSCommon.h" // Defines general DNS untility routines | | 39 | #include "DNSCommon.h" // Defines general DNS untility routines |
40 | #include "uDNS.h" // Defines entry points into unicast-specific routines | | 40 | #include "uDNS.h" // Defines entry points into unicast-specific routines |
41 | | | 41 | |
42 | // Disable certain benign warnings with Microsoft compilers | | 42 | // Disable certain benign warnings with Microsoft compilers |
43 | #if(defined(_MSC_VER)) | | 43 | #if(defined(_MSC_VER)) |
44 | // Disable "conditional expression is constant" warning for debug macros. | | 44 | // Disable "conditional expression is constant" warning for debug macros. |
45 | // Otherwise, this generates warnings for the perfectly natural construct "while(1)" | | 45 | // Otherwise, this generates warnings for the perfectly natural construct "while(1)" |
46 | // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know | | 46 | // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know |
47 | #pragma warning(disable:4127) | | 47 | #pragma warning(disable:4127) |
48 | | | 48 | |
49 | // Disable "assignment within conditional expression". | | 49 | // Disable "assignment within conditional expression". |
50 | // Other compilers understand the convention that if you place the assignment expression within an extra pair | | 50 | // Other compilers understand the convention that if you place the assignment expression within an extra pair |
51 | // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary. | | 51 | // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary. |
52 | // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal | | 52 | // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal |
53 | // to the compiler that the assignment is intentional, we have to just turn this warning off completely. | | 53 | // to the compiler that the assignment is intentional, we have to just turn this warning off completely. |
54 | #pragma warning(disable:4706) | | 54 | #pragma warning(disable:4706) |
55 | #endif | | 55 | #endif |
56 | | | 56 | |
57 | #if APPLE_OSX_mDNSResponder | | 57 | #if APPLE_OSX_mDNSResponder |
58 | | | 58 | |
59 | #include <WebFilterDNS/WebFilterDNS.h> | | 59 | #include <WebFilterDNS/WebFilterDNS.h> |
60 | | | 60 | |
61 | #if ! NO_WCF | | 61 | #if ! NO_WCF |
62 | WCFConnection *WCFConnectionNew(void) __attribute__((weak_import)); | | 62 | WCFConnection *WCFConnectionNew(void) __attribute__((weak_import)); |
63 | void WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import)); | | 63 | void WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import)); |
64 | | | 64 | |
65 | // Do we really need to define a macro for "if"? | | 65 | // Do we really need to define a macro for "if"? |
66 | #define CHECK_WCF_FUNCTION(X) if (X) | | 66 | #define CHECK_WCF_FUNCTION(X) if (X) |
67 | #endif // ! NO_WCF | | 67 | #endif // ! NO_WCF |
68 | | | 68 | |
69 | #else | | 69 | #else |
70 | | | 70 | |
71 | #define NO_WCF 1 | | 71 | #define NO_WCF 1 |
72 | #endif // APPLE_OSX_mDNSResponder | | 72 | #endif // APPLE_OSX_mDNSResponder |
73 | | | 73 | |
74 | // Forward declarations | | 74 | // Forward declarations |
75 | mDNSlocal void BeginSleepProcessing(mDNS *const m); | | 75 | mDNSlocal void BeginSleepProcessing(mDNS *const m); |
76 | mDNSlocal void RetrySPSRegistrations(mDNS *const m); | | 76 | mDNSlocal void RetrySPSRegistrations(mDNS *const m); |
77 | mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password); | | 77 | mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password); |
78 | mDNSlocal mDNSBool CacheRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q); | | 78 | mDNSlocal mDNSBool CacheRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q); |
79 | mDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q); | | 79 | mDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q); |
80 | mDNSlocal void mDNS_PurgeBeforeResolve(mDNS *const m, DNSQuestion *q); | | 80 | mDNSlocal void mDNS_PurgeBeforeResolve(mDNS *const m, DNSQuestion *q); |
81 | | | 81 | |
82 | // *************************************************************************** | | 82 | // *************************************************************************** |
83 | #if COMPILER_LIKES_PRAGMA_MARK | | 83 | #if COMPILER_LIKES_PRAGMA_MARK |
84 | #pragma mark - Program Constants | | 84 | #pragma mark - Program Constants |
85 | #endif | | 85 | #endif |
86 | | | 86 | |
87 | #define NO_HINFO 1 | | 87 | #define NO_HINFO 1 |
88 | | | 88 | |
89 | | | 89 | |
90 | // Any records bigger than this are considered 'large' records | | 90 | // Any records bigger than this are considered 'large' records |
91 | #define SmallRecordLimit 1024 | | 91 | #define SmallRecordLimit 1024 |
92 | | | 92 | |
93 | #define kMaxUpdateCredits 10 | | 93 | #define kMaxUpdateCredits 10 |
94 | #define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6) | | 94 | #define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6) |
95 | | | 95 | |
96 | mDNSexport const char *const mDNS_DomainTypeNames[] = | | 96 | mDNSexport const char *const mDNS_DomainTypeNames[] = |
97 | { | | 97 | { |
98 | "b._dns-sd._udp.", // Browse | | 98 | "b._dns-sd._udp.", // Browse |
99 | "db._dns-sd._udp.", // Default Browse | | 99 | "db._dns-sd._udp.", // Default Browse |
100 | "lb._dns-sd._udp.", // Automatic Browse | | 100 | "lb._dns-sd._udp.", // Automatic Browse |
101 | "r._dns-sd._udp.", // Registration | | 101 | "r._dns-sd._udp.", // Registration |
102 | "dr._dns-sd._udp." // Default Registration | | 102 | "dr._dns-sd._udp." // Default Registration |
103 | }; | | 103 | }; |
104 | | | 104 | |
105 | #ifdef UNICAST_DISABLED | | 105 | #ifdef UNICAST_DISABLED |
106 | #define uDNS_IsActiveQuery(q, u) mDNSfalse | | 106 | #define uDNS_IsActiveQuery(q, u) mDNSfalse |
107 | #endif | | 107 | #endif |
108 | | | 108 | |
109 | // *************************************************************************** | | 109 | // *************************************************************************** |
110 | #if COMPILER_LIKES_PRAGMA_MARK | | 110 | #if COMPILER_LIKES_PRAGMA_MARK |
111 | #pragma mark - | | 111 | #pragma mark - |
112 | #pragma mark - General Utility Functions | | 112 | #pragma mark - General Utility Functions |
113 | #endif | | 113 | #endif |
114 | | | 114 | |
115 | // If there is a authoritative LocalOnly record that answers questions of type A, AAAA and CNAME | | 115 | // If there is a authoritative LocalOnly record that answers questions of type A, AAAA and CNAME |
116 | // this returns true. Main use is to handle /etc/hosts records. | | 116 | // this returns true. Main use is to handle /etc/hosts records. |
117 | #define LORecordAnswersAddressType(rr) ((rr)->ARType == AuthRecordLocalOnly && \ | | 117 | #define LORecordAnswersAddressType(rr) ((rr)->ARType == AuthRecordLocalOnly && \ |
118 | (rr)->resrec.RecordType & kDNSRecordTypeUniqueMask && \ | | 118 | (rr)->resrec.RecordType & kDNSRecordTypeUniqueMask && \ |
119 | ((rr)->resrec.rrtype == kDNSType_A || (rr)->resrec.rrtype == kDNSType_AAAA || \ | | 119 | ((rr)->resrec.rrtype == kDNSType_A || (rr)->resrec.rrtype == kDNSType_AAAA || \ |
120 | (rr)->resrec.rrtype == kDNSType_CNAME)) | | 120 | (rr)->resrec.rrtype == kDNSType_CNAME)) |
121 | | | 121 | |
122 | #define FollowCNAME(q, rr, AddRecord) (AddRecord && (q)->qtype != kDNSType_CNAME && \ | | 122 | #define FollowCNAME(q, rr, AddRecord) (AddRecord && (q)->qtype != kDNSType_CNAME && \ |
123 | (rr)->RecordType != kDNSRecordTypePacketNegative && \ | | 123 | (rr)->RecordType != kDNSRecordTypePacketNegative && \ |
124 | (rr)->rrtype == kDNSType_CNAME) | | 124 | (rr)->rrtype == kDNSType_CNAME) |
125 | | | 125 | |
126 | mDNSlocal void SetNextQueryStopTime(mDNS *const m, const DNSQuestion *const q) | | 126 | mDNSlocal void SetNextQueryStopTime(mDNS *const m, const DNSQuestion *const q) |
127 | { | | 127 | { |
128 | if (m->mDNS_busy != m->mDNS_reentrancy+1) | | 128 | if (m->mDNS_busy != m->mDNS_reentrancy+1) |
129 | LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); | | 129 | LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); |
130 | | | 130 | |
131 | #if ForceAlerts | | 131 | #if ForceAlerts |
132 | if (m->mDNS_busy != m->mDNS_reentrancy+1) *(long*)0 = 0; | | 132 | if (m->mDNS_busy != m->mDNS_reentrancy+1) *(long*)0 = 0; |
133 | #endif | | 133 | #endif |
134 | | | 134 | |
135 | if (m->NextScheduledStopTime - q->StopTime > 0) | | 135 | if (m->NextScheduledStopTime - q->StopTime > 0) |
136 | m->NextScheduledStopTime = q->StopTime; | | 136 | m->NextScheduledStopTime = q->StopTime; |
137 | } | | 137 | } |
138 | | | 138 | |
139 | mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q) | | 139 | mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q) |
140 | { | | 140 | { |
141 | if (m->mDNS_busy != m->mDNS_reentrancy+1) | | 141 | if (m->mDNS_busy != m->mDNS_reentrancy+1) |
142 | LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); | | 142 | LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); |
143 | | | 143 | |
144 | #if ForceAlerts | | 144 | #if ForceAlerts |
145 | if (m->mDNS_busy != m->mDNS_reentrancy+1) *(long*)0 = 0; | | 145 | if (m->mDNS_busy != m->mDNS_reentrancy+1) *(long*)0 = 0; |
146 | #endif | | 146 | #endif |
147 | | | 147 | |
148 | if (ActiveQuestion(q)) | | 148 | if (ActiveQuestion(q)) |
149 | { | | 149 | { |
150 | // Depending on whether this is a multicast or unicast question we want to set either: | | 150 | // Depending on whether this is a multicast or unicast question we want to set either: |
151 | // m->NextScheduledQuery = NextQSendTime(q) or | | 151 | // m->NextScheduledQuery = NextQSendTime(q) or |
152 | // m->NextuDNSEvent = NextQSendTime(q) | | 152 | // m->NextuDNSEvent = NextQSendTime(q) |
153 | mDNSs32 *const timer = mDNSOpaque16IsZero(q->TargetQID) ? &m->NextScheduledQuery : &m->NextuDNSEvent; | | 153 | mDNSs32 *const timer = mDNSOpaque16IsZero(q->TargetQID) ? &m->NextScheduledQuery : &m->NextuDNSEvent; |
154 | if (*timer - NextQSendTime(q) > 0) | | 154 | if (*timer - NextQSendTime(q) > 0) |
155 | *timer = NextQSendTime(q); | | 155 | *timer = NextQSendTime(q); |
156 | } | | 156 | } |
157 | } | | 157 | } |
158 | | | 158 | |
159 | mDNSlocal void ReleaseAuthEntity(AuthHash *r, AuthEntity *e) | | 159 | mDNSlocal void ReleaseAuthEntity(AuthHash *r, AuthEntity *e) |
160 | { | | 160 | { |
161 | #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1 | | 161 | #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1 |
162 | unsigned int i; | | 162 | unsigned int i; |
163 | for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF; | | 163 | for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF; |
164 | #endif | | 164 | #endif |
165 | e->next = r->rrauth_free; | | 165 | e->next = r->rrauth_free; |
166 | r->rrauth_free = e; | | 166 | r->rrauth_free = e; |
167 | r->rrauth_totalused--; | | 167 | r->rrauth_totalused--; |
168 | } | | 168 | } |
169 | | | 169 | |
170 | mDNSlocal void ReleaseAuthGroup(AuthHash *r, AuthGroup **cp) | | 170 | mDNSlocal void ReleaseAuthGroup(AuthHash *r, AuthGroup **cp) |
171 | { | | 171 | { |
172 | AuthEntity *e = (AuthEntity *)(*cp); | | 172 | AuthEntity *e = (AuthEntity *)(*cp); |
173 | LogMsg("ReleaseAuthGroup: Releasing AuthGroup %##s", (*cp)->name->c); | | 173 | LogMsg("ReleaseAuthGroup: Releasing AuthGroup %##s", (*cp)->name->c); |
174 | if ((*cp)->rrauth_tail != &(*cp)->members) | | 174 | if ((*cp)->rrauth_tail != &(*cp)->members) |
175 | LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrauth_tail != &(*cp)->members)"); | | 175 | LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrauth_tail != &(*cp)->members)"); |
176 | if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name); | | 176 | if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name); |
177 | (*cp)->name = mDNSNULL; | | 177 | (*cp)->name = mDNSNULL; |
178 | *cp = (*cp)->next; // Cut record from list | | 178 | *cp = (*cp)->next; // Cut record from list |
179 | ReleaseAuthEntity(r, e); | | 179 | ReleaseAuthEntity(r, e); |
180 | } | | 180 | } |
181 | | | 181 | |
182 | mDNSlocal AuthEntity *GetAuthEntity(AuthHash *r, const AuthGroup *const PreserveAG) | | 182 | mDNSlocal AuthEntity *GetAuthEntity(AuthHash *r, const AuthGroup *const PreserveAG) |
183 | { | | 183 | { |
184 | AuthEntity *e = mDNSNULL; | | 184 | AuthEntity *e = mDNSNULL; |
185 | | | 185 | |
186 | if (r->rrauth_lock) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); } | | 186 | if (r->rrauth_lock) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); } |
187 | r->rrauth_lock = 1; | | 187 | r->rrauth_lock = 1; |
188 | | | 188 | |
189 | if (!r->rrauth_free) | | 189 | if (!r->rrauth_free) |
190 | { | | 190 | { |
191 | // We allocate just one AuthEntity at a time because we need to be able | | 191 | // We allocate just one AuthEntity at a time because we need to be able |
192 | // free them all individually which normally happens when we parse /etc/hosts into | | 192 | // free them all individually which normally happens when we parse /etc/hosts into |
193 | // AuthHash where we add the "new" entries and discard (free) the already added | | 193 | // AuthHash where we add the "new" entries and discard (free) the already added |
194 | // entries. If we allocate as chunks, we can't free them individually. | | 194 | // entries. If we allocate as chunks, we can't free them individually. |
195 | AuthEntity *storage = mDNSPlatformMemAllocate(sizeof(AuthEntity)); | | 195 | AuthEntity *storage = mDNSPlatformMemAllocate(sizeof(AuthEntity)); |
196 | storage->next = mDNSNULL; | | 196 | storage->next = mDNSNULL; |
197 | r->rrauth_free = storage; | | 197 | r->rrauth_free = storage; |
198 | } | | 198 | } |
199 | | | 199 | |
200 | // If we still have no free records, recycle all the records we can. | | 200 | // If we still have no free records, recycle all the records we can. |
201 | // Enumerating the entire auth is moderately expensive, so when we do it, we reclaim all the records we can in one pass. | | 201 | // Enumerating the entire auth is moderately expensive, so when we do it, we reclaim all the records we can in one pass. |
202 | if (!r->rrauth_free) | | 202 | if (!r->rrauth_free) |
203 | { | | 203 | { |
204 | mDNSu32 oldtotalused = r->rrauth_totalused; | | 204 | mDNSu32 oldtotalused = r->rrauth_totalused; |
205 | mDNSu32 slot; | | 205 | mDNSu32 slot; |
206 | for (slot = 0; slot < AUTH_HASH_SLOTS; slot++) | | 206 | for (slot = 0; slot < AUTH_HASH_SLOTS; slot++) |
207 | { | | 207 | { |
208 | AuthGroup **cp = &r->rrauth_hash[slot]; | | 208 | AuthGroup **cp = &r->rrauth_hash[slot]; |
209 | while (*cp) | | 209 | while (*cp) |
210 | { | | 210 | { |
211 | if ((*cp)->members || (*cp)==PreserveAG) cp=&(*cp)->next; | | 211 | if ((*cp)->members || (*cp)==PreserveAG) cp=&(*cp)->next; |
212 | else ReleaseAuthGroup(r, cp); | | 212 | else ReleaseAuthGroup(r, cp); |
213 | } | | 213 | } |
214 | } | | 214 | } |
215 | LogInfo("GetAuthEntity: Recycled %d records to reduce auth cache from %d to %d", | | 215 | LogInfo("GetAuthEntity: Recycled %d records to reduce auth cache from %d to %d", |
216 | oldtotalused - r->rrauth_totalused, oldtotalused, r->rrauth_totalused); | | 216 | oldtotalused - r->rrauth_totalused, oldtotalused, r->rrauth_totalused); |
217 | } | | 217 | } |
218 | | | 218 | |
219 | if (r->rrauth_free) // If there are records in the free list, take one | | 219 | if (r->rrauth_free) // If there are records in the free list, take one |
220 | { | | 220 | { |
221 | e = r->rrauth_free; | | 221 | e = r->rrauth_free; |
222 | r->rrauth_free = e->next; | | 222 | r->rrauth_free = e->next; |
223 | if (++r->rrauth_totalused >= r->rrauth_report) | | 223 | if (++r->rrauth_totalused >= r->rrauth_report) |
224 | { | | 224 | { |
225 | LogInfo("RR Auth now using %ld objects", r->rrauth_totalused); | | 225 | LogInfo("RR Auth now using %ld objects", r->rrauth_totalused); |
226 | if (r->rrauth_report < 100) r->rrauth_report += 10; | | 226 | if (r->rrauth_report < 100) r->rrauth_report += 10; |
227 | else if (r->rrauth_report < 1000) r->rrauth_report += 100; | | 227 | else if (r->rrauth_report < 1000) r->rrauth_report += 100; |
228 | else r->rrauth_report += 1000; | | 228 | else r->rrauth_report += 1000; |
229 | } | | 229 | } |
230 | mDNSPlatformMemZero(e, sizeof(*e)); | | 230 | mDNSPlatformMemZero(e, sizeof(*e)); |
231 | } | | 231 | } |
232 | | | 232 | |
233 | r->rrauth_lock = 0; | | 233 | r->rrauth_lock = 0; |
234 | | | 234 | |
235 | return(e); | | 235 | return(e); |
236 | } | | 236 | } |
237 | | | 237 | |
238 | mDNSexport AuthGroup *AuthGroupForName(AuthHash *r, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name) | | 238 | mDNSexport AuthGroup *AuthGroupForName(AuthHash *r, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name) |
239 | { | | 239 | { |
240 | AuthGroup *ag; | | 240 | AuthGroup *ag; |
241 | for (ag = r->rrauth_hash[slot]; ag; ag=ag->next) | | 241 | for (ag = r->rrauth_hash[slot]; ag; ag=ag->next) |
242 | if (ag->namehash == namehash && SameDomainName(ag->name, name)) | | 242 | if (ag->namehash == namehash && SameDomainName(ag->name, name)) |
243 | break; | | 243 | break; |
244 | return(ag); | | 244 | return(ag); |
245 | } | | 245 | } |
246 | | | 246 | |
247 | mDNSexport AuthGroup *AuthGroupForRecord(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr) | | 247 | mDNSexport AuthGroup *AuthGroupForRecord(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr) |
248 | { | | 248 | { |
249 | return(AuthGroupForName(r, slot, rr->namehash, rr->name)); | | 249 | return(AuthGroupForName(r, slot, rr->namehash, rr->name)); |
250 | } | | 250 | } |
251 | | | 251 | |
252 | mDNSlocal AuthGroup *GetAuthGroup(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr) | | 252 | mDNSlocal AuthGroup *GetAuthGroup(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr) |
253 | { | | 253 | { |
254 | mDNSu16 namelen = DomainNameLength(rr->name); | | 254 | mDNSu16 namelen = DomainNameLength(rr->name); |
255 | AuthGroup *ag = (AuthGroup*)GetAuthEntity(r, mDNSNULL); | | 255 | AuthGroup *ag = (AuthGroup*)GetAuthEntity(r, mDNSNULL); |
256 | if (!ag) { LogMsg("GetAuthGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); } | | 256 | if (!ag) { LogMsg("GetAuthGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); } |
257 | ag->next = r->rrauth_hash[slot]; | | 257 | ag->next = r->rrauth_hash[slot]; |
258 | ag->namehash = rr->namehash; | | 258 | ag->namehash = rr->namehash; |
259 | ag->members = mDNSNULL; | | 259 | ag->members = mDNSNULL; |
260 | ag->rrauth_tail = &ag->members; | | 260 | ag->rrauth_tail = &ag->members; |
261 | ag->name = (domainname*)ag->namestorage; | | 261 | ag->name = (domainname*)ag->namestorage; |
262 | ag->NewLocalOnlyRecords = mDNSNULL; | | 262 | ag->NewLocalOnlyRecords = mDNSNULL; |
263 | if (namelen > InlineCacheGroupNameSize) ag->name = mDNSPlatformMemAllocate(namelen); | | 263 | if (namelen > InlineCacheGroupNameSize) ag->name = mDNSPlatformMemAllocate(namelen); |
264 | if (!ag->name) | | 264 | if (!ag->name) |
265 | { | | 265 | { |
266 | LogMsg("GetAuthGroup: Failed to allocate name storage for %##s", rr->name->c); | | 266 | LogMsg("GetAuthGroup: Failed to allocate name storage for %##s", rr->name->c); |
267 | ReleaseAuthEntity(r, (AuthEntity*)ag); | | 267 | ReleaseAuthEntity(r, (AuthEntity*)ag); |
268 | return(mDNSNULL); | | 268 | return(mDNSNULL); |
269 | } | | 269 | } |
270 | AssignDomainName(ag->name, rr->name); | | 270 | AssignDomainName(ag->name, rr->name); |
271 | | | 271 | |
272 | if (AuthGroupForRecord(r, slot, rr)) LogMsg("GetAuthGroup: Already have AuthGroup for %##s", rr->name->c); | | 272 | if (AuthGroupForRecord(r, slot, rr)) LogMsg("GetAuthGroup: Already have AuthGroup for %##s", rr->name->c); |
273 | r->rrauth_hash[slot] = ag; | | 273 | r->rrauth_hash[slot] = ag; |
274 | if (AuthGroupForRecord(r, slot, rr) != ag) LogMsg("GetAuthGroup: Not finding AuthGroup for %##s", rr->name->c); | | 274 | if (AuthGroupForRecord(r, slot, rr) != ag) LogMsg("GetAuthGroup: Not finding AuthGroup for %##s", rr->name->c); |
275 | | | 275 | |
276 | return(ag); | | 276 | return(ag); |
277 | } | | 277 | } |
278 | | | 278 | |
279 | // Returns the AuthGroup in which the AuthRecord was inserted | | 279 | // Returns the AuthGroup in which the AuthRecord was inserted |
280 | mDNSexport AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr) | | 280 | mDNSexport AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr) |
281 | { | | 281 | { |
282 | AuthGroup *ag; | | 282 | AuthGroup *ag; |
283 | const mDNSu32 slot = AuthHashSlot(rr->resrec.name); | | 283 | const mDNSu32 slot = AuthHashSlot(rr->resrec.name); |
284 | ag = AuthGroupForRecord(r, slot, &rr->resrec); | | 284 | ag = AuthGroupForRecord(r, slot, &rr->resrec); |
285 | if (!ag) ag = GetAuthGroup(r, slot, &rr->resrec); // If we don't have a AuthGroup for this name, make one now | | 285 | if (!ag) ag = GetAuthGroup(r, slot, &rr->resrec); // If we don't have a AuthGroup for this name, make one now |
286 | if (ag) | | 286 | if (ag) |
287 | { | | 287 | { |
288 | LogInfo("InsertAuthRecord: inserting auth record %s from table", ARDisplayString(m, rr)); | | 288 | LogInfo("InsertAuthRecord: inserting auth record %s from table", ARDisplayString(m, rr)); |
289 | *(ag->rrauth_tail) = rr; // Append this record to tail of cache slot list | | 289 | *(ag->rrauth_tail) = rr; // Append this record to tail of cache slot list |
290 | ag->rrauth_tail = &(rr->next); // Advance tail pointer | | 290 | ag->rrauth_tail = &(rr->next); // Advance tail pointer |
291 | } | | 291 | } |
292 | return ag; | | 292 | return ag; |
293 | } | | 293 | } |
294 | | | 294 | |
295 | mDNSexport AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr) | | 295 | mDNSexport AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr) |
296 | { | | 296 | { |
297 | AuthGroup *a; | | 297 | AuthGroup *a; |
298 | AuthGroup **ag = &a; | | 298 | AuthGroup **ag = &a; |
299 | AuthRecord **rp; | | 299 | AuthRecord **rp; |
300 | const mDNSu32 slot = AuthHashSlot(rr->resrec.name); | | 300 | const mDNSu32 slot = AuthHashSlot(rr->resrec.name); |
301 | | | 301 | |
302 | a = AuthGroupForRecord(r, slot, &rr->resrec); | | 302 | a = AuthGroupForRecord(r, slot, &rr->resrec); |
303 | if (!a) { LogMsg("RemoveAuthRecord: ERROR!! AuthGroup not found for %s", ARDisplayString(m, rr)); return mDNSNULL; } | | 303 | if (!a) { LogMsg("RemoveAuthRecord: ERROR!! AuthGroup not found for %s", ARDisplayString(m, rr)); return mDNSNULL; } |
304 | rp = &(*ag)->members; | | 304 | rp = &(*ag)->members; |
305 | while (*rp) | | 305 | while (*rp) |
306 | { | | 306 | { |
307 | if (*rp != rr) | | 307 | if (*rp != rr) |
308 | rp=&(*rp)->next; | | 308 | rp=&(*rp)->next; |
309 | else | | 309 | else |
310 | { | | 310 | { |
311 | // We don't break here, so that we can set the tail below without tracking "prev" pointers | | 311 | // We don't break here, so that we can set the tail below without tracking "prev" pointers |
312 | | | 312 | |
313 | LogInfo("RemoveAuthRecord: removing auth record %s from table", ARDisplayString(m, rr)); | | 313 | LogInfo("RemoveAuthRecord: removing auth record %s from table", ARDisplayString(m, rr)); |
314 | *rp = (*rp)->next; // Cut record from list | | 314 | *rp = (*rp)->next; // Cut record from list |
315 | } | | 315 | } |
316 | } | | 316 | } |
317 | // TBD: If there are no more members, release authgroup ? | | 317 | // TBD: If there are no more members, release authgroup ? |
318 | (*ag)->rrauth_tail = rp; | | 318 | (*ag)->rrauth_tail = rp; |
319 | return a; | | 319 | return a; |
320 | } | | 320 | } |
321 | | | 321 | |
322 | mDNSexport CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name) | | 322 | mDNSexport CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name) |
323 | { | | 323 | { |
324 | CacheGroup *cg; | | 324 | CacheGroup *cg; |
325 | for (cg = m->rrcache_hash[slot]; cg; cg=cg->next) | | 325 | for (cg = m->rrcache_hash[slot]; cg; cg=cg->next) |
326 | if (cg->namehash == namehash && SameDomainName(cg->name, name)) | | 326 | if (cg->namehash == namehash && SameDomainName(cg->name, name)) |
327 | break; | | 327 | break; |
328 | return(cg); | | 328 | return(cg); |
329 | } | | 329 | } |
330 | | | 330 | |
331 | mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr) | | 331 | mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr) |
332 | { | | 332 | { |
333 | return(CacheGroupForName(m, slot, rr->namehash, rr->name)); | | 333 | return(CacheGroupForName(m, slot, rr->namehash, rr->name)); |
334 | } | | 334 | } |
335 | | | 335 | |
336 | mDNSexport mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr) | | 336 | mDNSexport mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr) |
337 | { | | 337 | { |
338 | NetworkInterfaceInfo *intf; | | 338 | NetworkInterfaceInfo *intf; |
339 | | | 339 | |
340 | if (addr->type == mDNSAddrType_IPv4) | | 340 | if (addr->type == mDNSAddrType_IPv4) |
341 | { | | 341 | { |
342 | // Normally we resist touching the NotAnInteger fields, but here we're doing tricky bitwise masking so we make an exception | | 342 | // Normally we resist touching the NotAnInteger fields, but here we're doing tricky bitwise masking so we make an exception |
343 | if (mDNSv4AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue); | | 343 | if (mDNSv4AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue); |
344 | for (intf = m->HostInterfaces; intf; intf = intf->next) | | 344 | for (intf = m->HostInterfaces; intf; intf = intf->next) |
345 | if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx) | | 345 | if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx) |
346 | if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0) | | 346 | if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0) |
347 | return(mDNStrue); | | 347 | return(mDNStrue); |
348 | } | | 348 | } |
349 | | | 349 | |
350 | if (addr->type == mDNSAddrType_IPv6) | | 350 | if (addr->type == mDNSAddrType_IPv6) |
351 | { | | 351 | { |
352 | if (mDNSv6AddressIsLinkLocal(&addr->ip.v6)) return(mDNStrue); | | 352 | if (mDNSv6AddressIsLinkLocal(&addr->ip.v6)) return(mDNStrue); |
353 | for (intf = m->HostInterfaces; intf; intf = intf->next) | | 353 | for (intf = m->HostInterfaces; intf; intf = intf->next) |
354 | if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx) | | 354 | if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx) |
355 | if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) && | | 355 | if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) && |
356 | (((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) && | | 356 | (((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) && |
357 | (((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) && | | 357 | (((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) && |
358 | (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0)) | | 358 | (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0)) |
359 | return(mDNStrue); | | 359 | return(mDNStrue); |
360 | } | | 360 | } |
361 | | | 361 | |
362 | return(mDNSfalse); | | 362 | return(mDNSfalse); |
363 | } | | 363 | } |
364 | | | 364 | |
365 | mDNSlocal NetworkInterfaceInfo *FirstInterfaceForID(mDNS *const m, const mDNSInterfaceID InterfaceID) | | 365 | mDNSlocal NetworkInterfaceInfo *FirstInterfaceForID(mDNS *const m, const mDNSInterfaceID InterfaceID) |
366 | { | | 366 | { |
367 | NetworkInterfaceInfo *intf = m->HostInterfaces; | | 367 | NetworkInterfaceInfo *intf = m->HostInterfaces; |
368 | while (intf && intf->InterfaceID != InterfaceID) intf = intf->next; | | 368 | while (intf && intf->InterfaceID != InterfaceID) intf = intf->next; |
369 | return(intf); | | 369 | return(intf); |
370 | } | | 370 | } |
371 | | | 371 | |
372 | mDNSexport char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID) | | 372 | mDNSexport char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID) |
373 | { | | 373 | { |
374 | NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); | | 374 | NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); |
375 | return(intf ? intf->ifname : mDNSNULL); | | 375 | return(intf ? intf->ifname : mDNSNULL); |
376 | } | | 376 | } |
377 | | | 377 | |
378 | // Caller should hold the lock | | 378 | // Caller should hold the lock |
379 | mDNSlocal void GenerateNegativeResponse(mDNS *const m) | | 379 | mDNSlocal void GenerateNegativeResponse(mDNS *const m) |
380 | { | | 380 | { |
381 | DNSQuestion *q; | | 381 | DNSQuestion *q; |
382 | if (!m->CurrentQuestion) { LogMsg("GenerateNegativeResponse: ERROR!! CurrentQuestion not set"); return; } | | 382 | if (!m->CurrentQuestion) { LogMsg("GenerateNegativeResponse: ERROR!! CurrentQuestion not set"); return; } |
383 | q = m->CurrentQuestion; | | 383 | q = m->CurrentQuestion; |
384 | LogInfo("GenerateNegativeResponse: Generating negative response for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); | | 384 | LogInfo("GenerateNegativeResponse: Generating negative response for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); |
385 | | | 385 | |
386 | MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, mDNSNULL); | | 386 | MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, mDNSNULL); |
387 | AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache); | | 387 | AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache); |
388 | if (m->CurrentQuestion == q) { q->ThisQInterval = 0; } // Deactivate this question | | 388 | if (m->CurrentQuestion == q) { q->ThisQInterval = 0; } // Deactivate this question |
389 | // Don't touch the question after this | | 389 | // Don't touch the question after this |
390 | m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it | | 390 | m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it |
391 | } | | 391 | } |
392 | | | 392 | |
393 | mDNSlocal void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, ResourceRecord *rr) | | 393 | mDNSlocal void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, ResourceRecord *rr) |
394 | { | | 394 | { |
395 | const mDNSBool selfref = SameDomainName(&q->qname, &rr->rdata->u.name); | | 395 | const mDNSBool selfref = SameDomainName(&q->qname, &rr->rdata->u.name); |
396 | if (q->CNAMEReferrals >= 10 || selfref) | | 396 | if (q->CNAMEReferrals >= 10 || selfref) |
397 | LogMsg("AnswerQuestionByFollowingCNAME: %p %##s (%s) NOT following CNAME referral %d%s for %s", | | 397 | LogMsg("AnswerQuestionByFollowingCNAME: %p %##s (%s) NOT following CNAME referral %d%s for %s", |
398 | q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, selfref ? " (Self-Referential)" : "", RRDisplayString(m, rr)); | | 398 | q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, selfref ? " (Self-Referential)" : "", RRDisplayString(m, rr)); |
399 | else | | 399 | else |
400 | { | | 400 | { |
401 | const mDNSu32 c = q->CNAMEReferrals + 1; // Stash a copy of the new q->CNAMEReferrals value | | 401 | const mDNSu32 c = q->CNAMEReferrals + 1; // Stash a copy of the new q->CNAMEReferrals value |
402 | | | 402 | |
403 | // The SameDomainName check above is to ignore bogus CNAME records that point right back at | | 403 | // The SameDomainName check above is to ignore bogus CNAME records that point right back at |
404 | // themselves. Without that check we can get into a case where we have two duplicate questions, | | 404 | // themselves. Without that check we can get into a case where we have two duplicate questions, |
405 | // A and B, and when we stop question A, UpdateQuestionDuplicates copies the value of CNAMEReferrals | | 405 | // A and B, and when we stop question A, UpdateQuestionDuplicates copies the value of CNAMEReferrals |
406 | // from A to B, and then A is re-appended to the end of the list as a duplicate of B (because | | 406 | // from A to B, and then A is re-appended to the end of the list as a duplicate of B (because |
407 | // the target name is still the same), and then when we stop question B, UpdateQuestionDuplicates | | 407 | // the target name is still the same), and then when we stop question B, UpdateQuestionDuplicates |
408 | // copies the B's value of CNAMEReferrals back to A, and we end up not incrementing CNAMEReferrals | | 408 | // copies the B's value of CNAMEReferrals back to A, and we end up not incrementing CNAMEReferrals |
409 | // for either of them. This is not a problem for CNAME loops of two or more records because in | | 409 | // for either of them. This is not a problem for CNAME loops of two or more records because in |
410 | // those cases the newly re-appended question A has a different target name and therefore cannot be | | 410 | // those cases the newly re-appended question A has a different target name and therefore cannot be |
411 | // a duplicate of any other question ('B') which was itself a duplicate of the previous question A. | | 411 | // a duplicate of any other question ('B') which was itself a duplicate of the previous question A. |
412 | | | 412 | |
413 | // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect, | | 413 | // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect, |
414 | // and track CNAMEs coming and going, we should really create a subordinate query here, | | 414 | // and track CNAMEs coming and going, we should really create a subordinate query here, |
415 | // which we would subsequently cancel and retract if the CNAME referral record were removed. | | 415 | // which we would subsequently cancel and retract if the CNAME referral record were removed. |
416 | // In reality this is such a corner case we'll ignore it until someone actually needs it. | | 416 | // In reality this is such a corner case we'll ignore it until someone actually needs it. |
417 | | | 417 | |
418 | LogInfo("AnswerQuestionByFollowingCNAME: %p %##s (%s) following CNAME referral %d for %s", | | 418 | LogInfo("AnswerQuestionByFollowingCNAME: %p %##s (%s) following CNAME referral %d for %s", |
419 | q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, RRDisplayString(m, rr)); | | 419 | q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, RRDisplayString(m, rr)); |
420 | | | 420 | |
421 | mDNS_StopQuery_internal(m, q); // Stop old query | | 421 | mDNS_StopQuery_internal(m, q); // Stop old query |
422 | AssignDomainName(&q->qname, &rr->rdata->u.name); // Update qname | | 422 | AssignDomainName(&q->qname, &rr->rdata->u.name); // Update qname |
423 | q->qnamehash = DomainNameHashValue(&q->qname); // and namehash | | 423 | q->qnamehash = DomainNameHashValue(&q->qname); // and namehash |
424 | // If a unicast query results in a CNAME that points to a .local, we need to re-try | | 424 | // If a unicast query results in a CNAME that points to a .local, we need to re-try |
425 | // this as unicast. Setting the mDNSInterface_Unicast tells mDNS_StartQuery_internal | | 425 | // this as unicast. Setting the mDNSInterface_Unicast tells mDNS_StartQuery_internal |
426 | // to try this as unicast query even though it is a .local name | | 426 | // to try this as unicast query even though it is a .local name |
427 | if (!mDNSOpaque16IsZero(q->TargetQID) && IsLocalDomain(&q->qname)) | | 427 | if (!mDNSOpaque16IsZero(q->TargetQID) && IsLocalDomain(&q->qname)) |
428 | { | | 428 | { |
429 | LogInfo("AnswerQuestionByFollowingCNAME: Resolving a .local CNAME %p %##s (%s) Record %s", | | 429 | LogInfo("AnswerQuestionByFollowingCNAME: Resolving a .local CNAME %p %##s (%s) Record %s", |
430 | q, q->qname.c, DNSTypeName(q->qtype), RRDisplayString(m, rr)); | | 430 | q, q->qname.c, DNSTypeName(q->qtype), RRDisplayString(m, rr)); |
431 | q->InterfaceID = mDNSInterface_Unicast; | | 431 | q->InterfaceID = mDNSInterface_Unicast; |
432 | } | | 432 | } |
433 | mDNS_StartQuery_internal(m, q); // start new query | | 433 | mDNS_StartQuery_internal(m, q); // start new query |
434 | // Record how many times we've done this. We need to do this *after* mDNS_StartQuery_internal, | | 434 | // Record how many times we've done this. We need to do this *after* mDNS_StartQuery_internal, |
435 | // because mDNS_StartQuery_internal re-initializes CNAMEReferrals to zero | | 435 | // because mDNS_StartQuery_internal re-initializes CNAMEReferrals to zero |
436 | q->CNAMEReferrals = c; | | 436 | q->CNAMEReferrals = c; |
437 | } | | 437 | } |
438 | } | | 438 | } |
439 | | | 439 | |
440 | // For a single given DNSQuestion pointed to by CurrentQuestion, deliver an add/remove result for the single given AuthRecord | | 440 | // For a single given DNSQuestion pointed to by CurrentQuestion, deliver an add/remove result for the single given AuthRecord |
441 | // Note: All the callers should use the m->CurrentQuestion to see if the question is still valid or not | | 441 | // Note: All the callers should use the m->CurrentQuestion to see if the question is still valid or not |
442 | mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord) | | 442 | mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord) |
443 | { | | 443 | { |
444 | DNSQuestion *q = m->CurrentQuestion; | | 444 | DNSQuestion *q = m->CurrentQuestion; |
445 | mDNSBool followcname; | | 445 | mDNSBool followcname; |
446 | | | 446 | |
447 | if (!q) | | 447 | if (!q) |
448 | { | | 448 | { |
449 | LogMsg("AnswerLocalQuestionWithLocalAuthRecord: ERROR!! CurrentQuestion NULL while answering with %s", ARDisplayString(m, rr)); | | 449 | LogMsg("AnswerLocalQuestionWithLocalAuthRecord: ERROR!! CurrentQuestion NULL while answering with %s", ARDisplayString(m, rr)); |
450 | return; | | 450 | return; |
451 | } | | 451 | } |
452 | | | 452 | |
453 | followcname = FollowCNAME(q, &rr->resrec, AddRecord); | | 453 | followcname = FollowCNAME(q, &rr->resrec, AddRecord); |
454 | | | 454 | |
455 | // We should not be delivering results for record types Unregistered, Deregistering, and (unverified) Unique | | 455 | // We should not be delivering results for record types Unregistered, Deregistering, and (unverified) Unique |
456 | if (!(rr->resrec.RecordType & kDNSRecordTypeActiveMask)) | | 456 | if (!(rr->resrec.RecordType & kDNSRecordTypeActiveMask)) |
457 | { | | 457 | { |
458 | LogMsg("AnswerLocalQuestionWithLocalAuthRecord: *NOT* delivering %s event for local record type %X %s", | | 458 | LogMsg("AnswerLocalQuestionWithLocalAuthRecord: *NOT* delivering %s event for local record type %X %s", |
459 | AddRecord ? "Add" : "Rmv", rr->resrec.RecordType, ARDisplayString(m, rr)); | | 459 | AddRecord ? "Add" : "Rmv", rr->resrec.RecordType, ARDisplayString(m, rr)); |
460 | return; | | 460 | return; |
461 | } | | 461 | } |
462 | | | 462 | |
463 | // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it | | 463 | // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it |
464 | if (AddRecord) rr->AnsweredLocalQ = mDNStrue; | | 464 | if (AddRecord) rr->AnsweredLocalQ = mDNStrue; |
465 | mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback | | 465 | mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback |
466 | if (q->QuestionCallback && !q->NoAnswer) | | 466 | if (q->QuestionCallback && !q->NoAnswer) |
467 | { | | 467 | { |
468 | q->CurrentAnswers += AddRecord ? 1 : -1; | | 468 | q->CurrentAnswers += AddRecord ? 1 : -1; |
469 | if (LORecordAnswersAddressType(rr)) | | 469 | if (LORecordAnswersAddressType(rr)) |
470 | { | | 470 | { |
471 | if (!followcname || q->ReturnIntermed) | | 471 | if (!followcname || q->ReturnIntermed) |
472 | { | | 472 | { |
473 | // Don't send this packet on the wire as we answered from /etc/hosts | | 473 | // Don't send this packet on the wire as we answered from /etc/hosts |
474 | q->ThisQInterval = 0; | | 474 | q->ThisQInterval = 0; |
475 | q->LOAddressAnswers += AddRecord ? 1 : -1; | | 475 | q->LOAddressAnswers += AddRecord ? 1 : -1; |
476 | q->QuestionCallback(m, q, &rr->resrec, AddRecord); | | 476 | q->QuestionCallback(m, q, &rr->resrec, AddRecord); |
477 | } | | 477 | } |
478 | mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again | | 478 | mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again |
479 | // The callback above could have caused the question to stop. Detect that | | 479 | // The callback above could have caused the question to stop. Detect that |
480 | // using m->CurrentQuestion | | 480 | // using m->CurrentQuestion |
481 | if (followcname && m->CurrentQuestion == q) | | 481 | if (followcname && m->CurrentQuestion == q) |
482 | AnswerQuestionByFollowingCNAME(m, q, &rr->resrec); | | 482 | AnswerQuestionByFollowingCNAME(m, q, &rr->resrec); |
483 | return; | | 483 | return; |
484 | } | | 484 | } |
485 | else | | 485 | else |
486 | q->QuestionCallback(m, q, &rr->resrec, AddRecord); | | 486 | q->QuestionCallback(m, q, &rr->resrec, AddRecord); |
487 | } | | 487 | } |
488 | mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again | | 488 | mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again |
489 | } | | 489 | } |
490 | | | 490 | |
491 | mDNSlocal void AnswerInterfaceAnyQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord) | | 491 | mDNSlocal void AnswerInterfaceAnyQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord) |
492 | { | | 492 | { |
493 | if (m->CurrentQuestion) | | 493 | if (m->CurrentQuestion) |
494 | LogMsg("AnswerInterfaceAnyQuestionsWithLocalAuthRecord: ERROR m->CurrentQuestion already set: %##s (%s)", | | 494 | LogMsg("AnswerInterfaceAnyQuestionsWithLocalAuthRecord: ERROR m->CurrentQuestion already set: %##s (%s)", |
495 | m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); | | 495 | m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); |
496 | m->CurrentQuestion = m->Questions; | | 496 | m->CurrentQuestion = m->Questions; |
497 | while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) | | 497 | while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) |
498 | { | | 498 | { |
499 | mDNSBool answered; | | 499 | mDNSBool answered; |
500 | DNSQuestion *q = m->CurrentQuestion; | | 500 | DNSQuestion *q = m->CurrentQuestion; |
501 | if (RRAny(rr)) | | 501 | if (RRAny(rr)) |
502 | answered = ResourceRecordAnswersQuestion(&rr->resrec, q); | | 502 | answered = ResourceRecordAnswersQuestion(&rr->resrec, q); |
503 | else | | 503 | else |
504 | answered = LocalOnlyRecordAnswersQuestion(rr, q); | | 504 | answered = LocalOnlyRecordAnswersQuestion(rr, q); |
505 | if (answered) | | 505 | if (answered) |
506 | AnswerLocalQuestionWithLocalAuthRecord(m, rr, AddRecord); // MUST NOT dereference q again | | 506 | AnswerLocalQuestionWithLocalAuthRecord(m, rr, AddRecord); // MUST NOT dereference q again |
507 | if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now | | 507 | if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now |
508 | m->CurrentQuestion = q->next; | | 508 | m->CurrentQuestion = q->next; |
509 | } | | 509 | } |
510 | m->CurrentQuestion = mDNSNULL; | | 510 | m->CurrentQuestion = mDNSNULL; |
511 | } | | 511 | } |
512 | | | 512 | |
513 | // When a new local AuthRecord is created or deleted, AnswerAllLocalQuestionsWithLocalAuthRecord() | | 513 | // When a new local AuthRecord is created or deleted, AnswerAllLocalQuestionsWithLocalAuthRecord() |
514 | // delivers the appropriate add/remove events to listening questions: | | 514 | // delivers the appropriate add/remove events to listening questions: |
515 | // 1. It runs though all our LocalOnlyQuestions delivering answers as appropriate, | | 515 | // 1. It runs though all our LocalOnlyQuestions delivering answers as appropriate, |
516 | // stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion(). | | 516 | // stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion(). |
517 | // 2. If the AuthRecord is marked mDNSInterface_LocalOnly or mDNSInterface_P2P, then it also runs though | | 517 | // 2. If the AuthRecord is marked mDNSInterface_LocalOnly or mDNSInterface_P2P, then it also runs though |
518 | // our main question list, delivering answers to mDNSInterface_Any questions as appropriate, | | 518 | // our main question list, delivering answers to mDNSInterface_Any questions as appropriate, |
519 | // stopping if it reaches a NewQuestion -- brand-new questions are handled by AnswerNewQuestion(). | | 519 | // stopping if it reaches a NewQuestion -- brand-new questions are handled by AnswerNewQuestion(). |
520 | // | | 520 | // |
521 | // AnswerAllLocalQuestionsWithLocalAuthRecord is used by the m->NewLocalRecords loop in mDNS_Execute(), | | 521 | // AnswerAllLocalQuestionsWithLocalAuthRecord is used by the m->NewLocalRecords loop in mDNS_Execute(), |
522 | // and by mDNS_Deregister_internal() | | 522 | // and by mDNS_Deregister_internal() |
523 | | | 523 | |
524 | mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord) | | 524 | mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord) |
525 | { | | 525 | { |
526 | if (m->CurrentQuestion) | | 526 | if (m->CurrentQuestion) |
527 | LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)", | | 527 | LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)", |
528 | m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); | | 528 | m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); |
529 | | | 529 | |
530 | m->CurrentQuestion = m->LocalOnlyQuestions; | | 530 | m->CurrentQuestion = m->LocalOnlyQuestions; |
531 | while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions) | | 531 | while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions) |
532 | { | | 532 | { |
533 | mDNSBool answered; | | 533 | mDNSBool answered; |
534 | DNSQuestion *q = m->CurrentQuestion; | | 534 | DNSQuestion *q = m->CurrentQuestion; |
535 | // We are called with both LocalOnly/P2P record or a regular AuthRecord | | 535 | // We are called with both LocalOnly/P2P record or a regular AuthRecord |
536 | if (RRAny(rr)) | | 536 | if (RRAny(rr)) |
537 | answered = ResourceRecordAnswersQuestion(&rr->resrec, q); | | 537 | answered = ResourceRecordAnswersQuestion(&rr->resrec, q); |
538 | else | | 538 | else |
539 | answered = LocalOnlyRecordAnswersQuestion(rr, q); | | 539 | answered = LocalOnlyRecordAnswersQuestion(rr, q); |
540 | if (answered) | | 540 | if (answered) |
541 | AnswerLocalQuestionWithLocalAuthRecord(m, rr, AddRecord); // MUST NOT dereference q again | | 541 | AnswerLocalQuestionWithLocalAuthRecord(m, rr, AddRecord); // MUST NOT dereference q again |
542 | if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now | | 542 | if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now |
543 | m->CurrentQuestion = q->next; | | 543 | m->CurrentQuestion = q->next; |
544 | } | | 544 | } |
545 | | | 545 | |
546 | m->CurrentQuestion = mDNSNULL; | | 546 | m->CurrentQuestion = mDNSNULL; |
547 | | | 547 | |
548 | // If this AuthRecord is marked LocalOnly or P2P, then we want to deliver it to all local 'mDNSInterface_Any' questions | | 548 | // If this AuthRecord is marked LocalOnly or P2P, then we want to deliver it to all local 'mDNSInterface_Any' questions |
549 | if (rr->ARType == AuthRecordLocalOnly || rr->ARType == AuthRecordP2P) | | 549 | if (rr->ARType == AuthRecordLocalOnly || rr->ARType == AuthRecordP2P) |
550 | AnswerInterfaceAnyQuestionsWithLocalAuthRecord(m, rr, AddRecord); | | 550 | AnswerInterfaceAnyQuestionsWithLocalAuthRecord(m, rr, AddRecord); |
551 | | | 551 | |
552 | } | | 552 | } |
553 | | | 553 | |
554 | // *************************************************************************** | | 554 | // *************************************************************************** |
555 | #if COMPILER_LIKES_PRAGMA_MARK | | 555 | #if COMPILER_LIKES_PRAGMA_MARK |
556 | #pragma mark - | | 556 | #pragma mark - |
557 | #pragma mark - Resource Record Utility Functions | | 557 | #pragma mark - Resource Record Utility Functions |
558 | #endif | | 558 | #endif |
559 | | | 559 | |
560 | #define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA) | | 560 | #define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA) |
561 | | | 561 | |
562 | #define ResourceRecordIsValidAnswer(RR) ( ((RR)-> resrec.RecordType & kDNSRecordTypeActiveMask) && \ | | 562 | #define ResourceRecordIsValidAnswer(RR) ( ((RR)-> resrec.RecordType & kDNSRecordTypeActiveMask) && \ |
563 | ((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \ | | 563 | ((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \ |
564 | ((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \ | | 564 | ((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \ |
565 | ((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)) ) | | 565 | ((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)) ) |
566 | | | 566 | |
567 | #define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \ | | 567 | #define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \ |
568 | (ResourceRecordIsValidAnswer(RR) && \ | | 568 | (ResourceRecordIsValidAnswer(RR) && \ |
569 | ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID))) | | 569 | ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID))) |
570 | | | 570 | |
571 | #define DefaultProbeCountForTypeUnique ((mDNSu8)3) | | 571 | #define DefaultProbeCountForTypeUnique ((mDNSu8)3) |
572 | #define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0) | | 572 | #define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0) |
573 | | | 573 | |
574 | #define InitialAnnounceCount ((mDNSu8)8) | | 574 | #define InitialAnnounceCount ((mDNSu8)8) |
575 | | | 575 | |
576 | // For goodbye packets we set the count to 3, and for wakeups we set it to 18 | | 576 | // For goodbye packets we set the count to 3, and for wakeups we set it to 18 |
577 | // (which will be up to 15 wakeup attempts over the course of 30 seconds, | | 577 | // (which will be up to 15 wakeup attempts over the course of 30 seconds, |
578 | // and then if the machine fails to wake, 3 goodbye packets). | | 578 | // and then if the machine fails to wake, 3 goodbye packets). |
579 | #define GoodbyeCount ((mDNSu8)3) | | 579 | #define GoodbyeCount ((mDNSu8)3) |
580 | #define WakeupCount ((mDNSu8)18) | | 580 | #define WakeupCount ((mDNSu8)18) |
581 | | | 581 | |
582 | // Number of wakeups we send if WakeOnResolve is set in the question | | 582 | // Number of wakeups we send if WakeOnResolve is set in the question |
583 | #define InitialWakeOnResolveCount ((mDNSu8)3) | | 583 | #define InitialWakeOnResolveCount ((mDNSu8)3) |
584 | | | 584 | |
585 | // Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not. | | 585 | // Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not. |
586 | // This means that because the announce interval is doubled after sending the first packet, the first | | 586 | // This means that because the announce interval is doubled after sending the first packet, the first |
587 | // observed on-the-wire inter-packet interval between announcements is actually one second. | | 587 | // observed on-the-wire inter-packet interval between announcements is actually one second. |
588 | // The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent. | | 588 | // The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent. |
589 | #define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4) | | 589 | #define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4) |
590 | #define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2) | | 590 | #define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2) |
591 | #define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2) | | 591 | #define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2) |
592 | | | 592 | |
593 | #define DefaultAPIntervalForRecordType(X) ((X) & kDNSRecordTypeActiveSharedMask ? DefaultAnnounceIntervalForTypeShared : \ | | 593 | #define DefaultAPIntervalForRecordType(X) ((X) & kDNSRecordTypeActiveSharedMask ? DefaultAnnounceIntervalForTypeShared : \ |
594 | (X) & kDNSRecordTypeUnique ? DefaultProbeIntervalForTypeUnique : \ | | 594 | (X) & kDNSRecordTypeUnique ? DefaultProbeIntervalForTypeUnique : \ |
595 | (X) & kDNSRecordTypeActiveUniqueMask ? DefaultAnnounceIntervalForTypeUnique : 0) | | 595 | (X) & kDNSRecordTypeActiveUniqueMask ? DefaultAnnounceIntervalForTypeUnique : 0) |
596 | | | 596 | |
597 | #define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0) | | 597 | #define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0) |
598 | #define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR)) | | 598 | #define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR)) |
599 | #define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond) | | 599 | #define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond) |
600 | #define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR)) | | 600 | #define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR)) |
601 | | | 601 | |
602 | #define MaxUnansweredQueries 4 | | 602 | #define MaxUnansweredQueries 4 |
603 | | | 603 | |
604 | // SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent | | 604 | // SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent |
605 | // (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match). | | 605 | // (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match). |
606 | // TTL and rdata may differ. | | 606 | // TTL and rdata may differ. |
607 | // This is used for cache flush management: | | 607 | // This is used for cache flush management: |
608 | // When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent | | 608 | // When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent |
609 | // When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed | | 609 | // When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed |
610 | | | 610 | |
611 | // SameResourceRecordNameClassInterface is functionally the same as SameResourceRecordSignature, except rrtype does not have to match | | 611 | // SameResourceRecordNameClassInterface is functionally the same as SameResourceRecordSignature, except rrtype does not have to match |
612 | | | 612 | |
613 | #define SameResourceRecordSignature(A,B) (A)->resrec.rrtype == (B)->resrec.rrtype && SameResourceRecordNameClassInterface((A),(B)) | | 613 | #define SameResourceRecordSignature(A,B) (A)->resrec.rrtype == (B)->resrec.rrtype && SameResourceRecordNameClassInterface((A),(B)) |
614 | | | 614 | |
615 | mDNSlocal mDNSBool SameResourceRecordNameClassInterface(const AuthRecord *const r1, const AuthRecord *const r2) | | 615 | mDNSlocal mDNSBool SameResourceRecordNameClassInterface(const AuthRecord *const r1, const AuthRecord *const r2) |
616 | { | | 616 | { |
617 | if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); } | | 617 | if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); } |
618 | if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); } | | 618 | if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); } |
619 | if (r1->resrec.InterfaceID && | | 619 | if (r1->resrec.InterfaceID && |
620 | r2->resrec.InterfaceID && | | 620 | r2->resrec.InterfaceID && |
621 | r1->resrec.InterfaceID != r2->resrec.InterfaceID) return(mDNSfalse); | | 621 | r1->resrec.InterfaceID != r2->resrec.InterfaceID) return(mDNSfalse); |
622 | return(mDNSBool)( | | 622 | return(mDNSBool)( |
623 | r1->resrec.rrclass == r2->resrec.rrclass && | | 623 | r1->resrec.rrclass == r2->resrec.rrclass && |
624 | r1->resrec.namehash == r2->resrec.namehash && | | 624 | r1->resrec.namehash == r2->resrec.namehash && |
625 | SameDomainName(r1->resrec.name, r2->resrec.name)); | | 625 | SameDomainName(r1->resrec.name, r2->resrec.name)); |
626 | } | | 626 | } |
627 | | | 627 | |
628 | // PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our | | 628 | // PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our |
629 | // authoratative record is unique (as opposed to shared). For unique records, we are supposed to have | | 629 | // authoratative record is unique (as opposed to shared). For unique records, we are supposed to have |
630 | // complete ownership of *all* types for this name, so *any* record type with the same name is a conflict. | | 630 | // complete ownership of *all* types for this name, so *any* record type with the same name is a conflict. |
631 | // In addition, when probing we send our questions with the wildcard type kDNSQType_ANY, | | 631 | // In addition, when probing we send our questions with the wildcard type kDNSQType_ANY, |
632 | // so a response of any type should match, even if it is not actually the type the client plans to use. | | 632 | // so a response of any type should match, even if it is not actually the type the client plans to use. |
633 | | | 633 | |
634 | // For now, to make it easier to avoid false conflicts, we treat SPS Proxy records like shared records, | | 634 | // For now, to make it easier to avoid false conflicts, we treat SPS Proxy records like shared records, |
635 | // and require the rrtypes to match for the rdata to be considered potentially conflicting | | 635 | // and require the rrtypes to match for the rdata to be considered potentially conflicting |
636 | mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr) | | 636 | mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr) |
637 | { | | 637 | { |
638 | if (!pktrr) { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); } | | 638 | if (!pktrr) { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); } |
639 | if (!authrr) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse); } | | 639 | if (!authrr) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse); } |
640 | if (pktrr->resrec.InterfaceID && | | 640 | if (pktrr->resrec.InterfaceID && |
641 | authrr->resrec.InterfaceID && | | 641 | authrr->resrec.InterfaceID && |
642 | pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse); | | 642 | pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse); |
643 | if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) || authrr->WakeUp.HMAC.l[0]) | | 643 | if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) || authrr->WakeUp.HMAC.l[0]) |
644 | if (pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse); | | 644 | if (pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse); |
645 | return(mDNSBool)( | | 645 | return(mDNSBool)( |
646 | pktrr->resrec.rrclass == authrr->resrec.rrclass && | | 646 | pktrr->resrec.rrclass == authrr->resrec.rrclass && |
647 | pktrr->resrec.namehash == authrr->resrec.namehash && | | 647 | pktrr->resrec.namehash == authrr->resrec.namehash && |
648 | SameDomainName(pktrr->resrec.name, authrr->resrec.name)); | | 648 | SameDomainName(pktrr->resrec.name, authrr->resrec.name)); |
649 | } | | 649 | } |
650 | | | 650 | |
651 | // CacheRecord *ka is the CacheRecord from the known answer list in the query. | | 651 | // CacheRecord *ka is the CacheRecord from the known answer list in the query. |
652 | // This is the information that the requester believes to be correct. | | 652 | // This is the information that the requester believes to be correct. |
653 | // AuthRecord *rr is the answer we are proposing to give, if not suppressed. | | 653 | // AuthRecord *rr is the answer we are proposing to give, if not suppressed. |
654 | // This is the information that we believe to be correct. | | 654 | // This is the information that we believe to be correct. |
655 | // We've already determined that we plan to give this answer on this interface | | 655 | // We've already determined that we plan to give this answer on this interface |
656 | // (either the record is non-specific, or it is specific to this interface) | | 656 | // (either the record is non-specific, or it is specific to this interface) |
657 | // so now we just need to check the name, type, class, rdata and TTL. | | 657 | // so now we just need to check the name, type, class, rdata and TTL. |
658 | mDNSlocal mDNSBool ShouldSuppressKnownAnswer(const CacheRecord *const ka, const AuthRecord *const rr) | | 658 | mDNSlocal mDNSBool ShouldSuppressKnownAnswer(const CacheRecord *const ka, const AuthRecord *const rr) |
659 | { | | 659 | { |
660 | // If RR signature is different, or data is different, then don't suppress our answer | | 660 | // If RR signature is different, or data is different, then don't suppress our answer |
661 | if (!IdenticalResourceRecord(&ka->resrec, &rr->resrec)) return(mDNSfalse); | | 661 | if (!IdenticalResourceRecord(&ka->resrec, &rr->resrec)) return(mDNSfalse); |
662 | | | 662 | |
663 | // If the requester's indicated TTL is less than half the real TTL, | | 663 | // If the requester's indicated TTL is less than half the real TTL, |
664 | // we need to give our answer before the requester's copy expires. | | 664 | // we need to give our answer before the requester's copy expires. |
665 | // If the requester's indicated TTL is at least half the real TTL, | | 665 | // If the requester's indicated TTL is at least half the real TTL, |
666 | // then we can suppress our answer this time. | | 666 | // then we can suppress our answer this time. |
667 | // If the requester's indicated TTL is greater than the TTL we believe, | | 667 | // If the requester's indicated TTL is greater than the TTL we believe, |
668 | // then that's okay, and we don't need to do anything about it. | | 668 | // then that's okay, and we don't need to do anything about it. |
669 | // (If two responders on the network are offering the same information, | | 669 | // (If two responders on the network are offering the same information, |
670 | // that's okay, and if they are offering the information with different TTLs, | | 670 | // that's okay, and if they are offering the information with different TTLs, |
671 | // the one offering the lower TTL should defer to the one offering the higher TTL.) | | 671 | // the one offering the lower TTL should defer to the one offering the higher TTL.) |
672 | return(mDNSBool)(ka->resrec.rroriginalttl >= rr->resrec.rroriginalttl / 2); | | 672 | return(mDNSBool)(ka->resrec.rroriginalttl >= rr->resrec.rroriginalttl / 2); |
673 | } | | 673 | } |
674 | | | 674 | |
675 | mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const rr) | | 675 | mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const rr) |
676 | { | | 676 | { |
677 | if (rr->resrec.RecordType == kDNSRecordTypeUnique) | | 677 | if (rr->resrec.RecordType == kDNSRecordTypeUnique) |
678 | { | | 678 | { |
679 | if ((rr->LastAPTime + rr->ThisAPInterval) - m->timenow > mDNSPlatformOneSecond * 10) | | 679 | if ((rr->LastAPTime + rr->ThisAPInterval) - m->timenow > mDNSPlatformOneSecond * 10) |
680 | { | | 680 | { |
681 | LogMsg("SetNextAnnounceProbeTime: ProbeCount %d Next in %d %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr)); | | 681 | LogMsg("SetNextAnnounceProbeTime: ProbeCount %d Next in %d %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr)); |
682 | LogMsg("SetNextAnnounceProbeTime: m->SuppressProbes %d m->timenow %d diff %d", m->SuppressProbes, m->timenow, m->SuppressProbes - m->timenow); | | 682 | LogMsg("SetNextAnnounceProbeTime: m->SuppressProbes %d m->timenow %d diff %d", m->SuppressProbes, m->timenow, m->SuppressProbes - m->timenow); |
683 | } | | 683 | } |
684 | if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0) | | 684 | if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0) |
685 | m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval); | | 685 | m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval); |
686 | // Some defensive code: | | 686 | // Some defensive code: |
687 | // If (rr->LastAPTime + rr->ThisAPInterval) happens to be far in the past, we don't want to allow | | 687 | // If (rr->LastAPTime + rr->ThisAPInterval) happens to be far in the past, we don't want to allow |
688 | // NextScheduledProbe to be set excessively in the past, because that can cause bad things to happen. | | 688 | // NextScheduledProbe to be set excessively in the past, because that can cause bad things to happen. |
689 | // See: <rdar://problem/7795434> mDNS: Sometimes advertising stops working and record interval is set to zero | | 689 | // See: <rdar://problem/7795434> mDNS: Sometimes advertising stops working and record interval is set to zero |
690 | // A future time also needs to be set to avoid spamming logs about not all probes being sent. | | 690 | if (m->NextScheduledProbe - m->timenow < 0) |
691 | if (m->NextScheduledProbe - m->timenow <= 0) | | 691 | m->NextScheduledProbe = m->timenow; |
692 | m->NextScheduledProbe = m->timenow + 1; | | | |
693 | } | | 692 | } |
694 | else if (rr->AnnounceCount && (ResourceRecordIsValidAnswer(rr) || rr->resrec.RecordType == kDNSRecordTypeDeregistering)) | | 693 | else if (rr->AnnounceCount && (ResourceRecordIsValidAnswer(rr) || rr->resrec.RecordType == kDNSRecordTypeDeregistering)) |
695 | { | | 694 | { |
696 | if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0) | | 695 | if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0) |
697 | m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval); | | 696 | m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval); |
698 | } | | 697 | } |
699 | // A future time also needs to be set to avoid spamming logs about not all responses being sent. | | 698 | if (m->NextScheduledResponse - m->timenow < 0) |
700 | if (m->NextScheduledResponse - m->timenow <= 0) | | 699 | m->NextScheduledResponse = m->timenow; |
701 | m->NextScheduledResponse = m->timenow + 1; | | | |
702 | } | | 700 | } |
703 | | | 701 | |
704 | mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr) | | 702 | mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr) |
705 | { | | 703 | { |
706 | // For reverse-mapping Sleep Proxy PTR records, probe interval is one second | | 704 | // For reverse-mapping Sleep Proxy PTR records, probe interval is one second |
707 | rr->ThisAPInterval = rr->AddressProxy.type ? mDNSPlatformOneSecond : DefaultAPIntervalForRecordType(rr->resrec.RecordType); | | 705 | rr->ThisAPInterval = rr->AddressProxy.type ? mDNSPlatformOneSecond : DefaultAPIntervalForRecordType(rr->resrec.RecordType); |
708 | | | 706 | |
709 | // * If this is a record type that's going to probe, then we use the m->SuppressProbes time. | | 707 | // * If this is a record type that's going to probe, then we use the m->SuppressProbes time. |
710 | // * Otherwise, if it's not going to probe, but m->SuppressProbes is set because we have other | | 708 | // * Otherwise, if it's not going to probe, but m->SuppressProbes is set because we have other |
711 | // records that are going to probe, then we delay its first announcement so that it will | | 709 | // records that are going to probe, then we delay its first announcement so that it will |
712 | // go out synchronized with the first announcement for the other records that *are* probing. | | 710 | // go out synchronized with the first announcement for the other records that *are* probing. |
713 | // This is a minor performance tweak that helps keep groups of related records synchronized together. | | 711 | // This is a minor performance tweak that helps keep groups of related records synchronized together. |
714 | // The addition of "interval / 2" is to make sure that, in the event that any of the probes are | | 712 | // The addition of "interval / 2" is to make sure that, in the event that any of the probes are |
715 | // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete. | | 713 | // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete. |
716 | // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated, | | 714 | // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated, |
717 | // because they will meet the criterion of being at least half-way to their scheduled announcement time. | | 715 | // because they will meet the criterion of being at least half-way to their scheduled announcement time. |
718 | // * If it's not going to probe and m->SuppressProbes is not already set then we should announce immediately. | | 716 | // * If it's not going to probe and m->SuppressProbes is not already set then we should announce immediately. |
719 | | | 717 | |
720 | if (rr->ProbeCount) | | 718 | if (rr->ProbeCount) |
721 | { | | 719 | { |
722 | // If we have no probe suppression time set, or it is in the past, set it now | | 720 | // If we have no probe suppression time set, or it is in the past, set it now |
723 | if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0) | | 721 | if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0) |
724 | { | | 722 | { |
725 | // To allow us to aggregate probes when a group of services are registered together, | | 723 | // To allow us to aggregate probes when a group of services are registered together, |
726 | // the first probe is delayed 1/4 second. This means the common-case behaviour is: | | 724 | // the first probe is delayed 1/4 second. This means the common-case behaviour is: |
727 | // 1/4 second wait; probe | | 725 | // 1/4 second wait; probe |
728 | // 1/4 second wait; probe | | 726 | // 1/4 second wait; probe |
729 | // 1/4 second wait; probe | | 727 | // 1/4 second wait; probe |
730 | // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered) | | 728 | // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered) |
731 | m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2)); | | 729 | m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2)); |
732 | | | 730 | |
733 | // If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation | | 731 | // If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation |
734 | if (m->SuppressProbes - m->NextScheduledProbe >= 0) | | 732 | if (m->SuppressProbes - m->NextScheduledProbe >= 0) |
735 | m->SuppressProbes = NonZeroTime(m->NextScheduledProbe); | | 733 | m->SuppressProbes = NonZeroTime(m->NextScheduledProbe); |
736 | if (m->SuppressProbes - m->timenow < 0) // Make sure we don't set m->SuppressProbes excessively in the past | | 734 | if (m->SuppressProbes - m->timenow < 0) // Make sure we don't set m->SuppressProbes excessively in the past |
737 | m->SuppressProbes = m->timenow; | | 735 | m->SuppressProbes = m->timenow; |
738 | | | 736 | |
739 | // If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation | | 737 | // If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation |
740 | if (m->SuppressProbes - m->NextScheduledQuery >= 0) | | 738 | if (m->SuppressProbes - m->NextScheduledQuery >= 0) |
741 | m->SuppressProbes = NonZeroTime(m->NextScheduledQuery); | | 739 | m->SuppressProbes = NonZeroTime(m->NextScheduledQuery); |
742 | if (m->SuppressProbes - m->timenow < 0) // Make sure we don't set m->SuppressProbes excessively in the past | | 740 | if (m->SuppressProbes - m->timenow < 0) // Make sure we don't set m->SuppressProbes excessively in the past |
743 | m->SuppressProbes = m->timenow; | | 741 | m->SuppressProbes = m->timenow; |
744 | | | 742 | |
745 | // except... don't expect to be able to send before the m->SuppressSending timer fires | | 743 | // except... don't expect to be able to send before the m->SuppressSending timer fires |
746 | if (m->SuppressSending && m->SuppressProbes - m->SuppressSending < 0) | | 744 | if (m->SuppressSending && m->SuppressProbes - m->SuppressSending < 0) |
747 | m->SuppressProbes = NonZeroTime(m->SuppressSending); | | 745 | m->SuppressProbes = NonZeroTime(m->SuppressSending); |
748 | | | 746 | |
749 | if (m->SuppressProbes - m->timenow > mDNSPlatformOneSecond * 8) | | 747 | if (m->SuppressProbes - m->timenow > mDNSPlatformOneSecond * 8) |
750 | { | | 748 | { |
751 | LogMsg("InitializeLastAPTime ERROR m->SuppressProbes %d m->NextScheduledProbe %d m->NextScheduledQuery %d m->SuppressSending %d %d", | | 749 | LogMsg("InitializeLastAPTime ERROR m->SuppressProbes %d m->NextScheduledProbe %d m->NextScheduledQuery %d m->SuppressSending %d %d", |
752 | m->SuppressProbes - m->timenow, | | 750 | m->SuppressProbes - m->timenow, |
753 | m->NextScheduledProbe - m->timenow, | | 751 | m->NextScheduledProbe - m->timenow, |
754 | m->NextScheduledQuery - m->timenow, | | 752 | m->NextScheduledQuery - m->timenow, |
755 | m->SuppressSending, | | 753 | m->SuppressSending, |
756 | m->SuppressSending - m->timenow); | | 754 | m->SuppressSending - m->timenow); |
757 | m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2)); | | 755 | m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2)); |
758 | } | | 756 | } |
759 | } | | 757 | } |
760 | rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval; | | 758 | rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval; |
761 | } | | 759 | } |
762 | else if (m->SuppressProbes && m->SuppressProbes - m->timenow >= 0) | | 760 | else if (m->SuppressProbes && m->SuppressProbes - m->timenow >= 0) |
763 | rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval + DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2; | | 761 | rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval + DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2; |
764 | else | | 762 | else |
765 | rr->LastAPTime = m->timenow - rr->ThisAPInterval; | | 763 | rr->LastAPTime = m->timenow - rr->ThisAPInterval; |
766 | | | 764 | |
767 | // For reverse-mapping Sleep Proxy PTR records we don't want to start probing instantly -- we | | 765 | // For reverse-mapping Sleep Proxy PTR records we don't want to start probing instantly -- we |
768 | // wait one second to give the client a chance to go to sleep, and then start our ARP/NDP probing. | | 766 | // wait one second to give the client a chance to go to sleep, and then start our ARP/NDP probing. |
769 | // After three probes one second apart with no answer, we conclude the client is now sleeping | | 767 | // After three probes one second apart with no answer, we conclude the client is now sleeping |
770 | // and we can begin broadcasting our announcements to take over ownership of that IP address. | | 768 | // and we can begin broadcasting our announcements to take over ownership of that IP address. |
771 | // If we don't wait for the client to go to sleep, then when the client sees our ARP Announcements there's a risk | | 769 | // If we don't wait for the client to go to sleep, then when the client sees our ARP Announcements there's a risk |
772 | // (depending on the OS and networking stack it's using) that it might interpret it as a conflict and change its IP address. | | 770 | // (depending on the OS and networking stack it's using) that it might interpret it as a conflict and change its IP address. |
773 | if (rr->AddressProxy.type) rr->LastAPTime = m->timenow; | | 771 | if (rr->AddressProxy.type) rr->LastAPTime = m->timenow; |
774 | | | 772 | |
775 | // Unsolicited Neighbor Advertisements (RFC 2461 Section 7.2.6) give us fast address cache updating, | | 773 | // Unsolicited Neighbor Advertisements (RFC 2461 Section 7.2.6) give us fast address cache updating, |
776 | // but some older IPv6 clients get confused by them, so for now we don't send them. Without Unsolicited | | 774 | // but some older IPv6 clients get confused by them, so for now we don't send them. Without Unsolicited |
777 | // Neighbor Advertisements we have to rely on Neighbor Unreachability Detection instead, which is slower. | | 775 | // Neighbor Advertisements we have to rely on Neighbor Unreachability Detection instead, which is slower. |
778 | // Given this, we'll do our best to wake for existing IPv6 connections, but we don't want to encourage | | 776 | // Given this, we'll do our best to wake for existing IPv6 connections, but we don't want to encourage |
779 | // new ones for sleeping clients, so we'll we send deletions for our SPS clients' AAAA records. | | 777 | // new ones for sleeping clients, so we'll we send deletions for our SPS clients' AAAA records. |
780 | if (m->KnownBugs & mDNS_KnownBug_LimitedIPv6) | | 778 | if (m->KnownBugs & mDNS_KnownBug_LimitedIPv6) |
781 | if (rr->WakeUp.HMAC.l[0] && rr->resrec.rrtype == kDNSType_AAAA) | | 779 | if (rr->WakeUp.HMAC.l[0] && rr->resrec.rrtype == kDNSType_AAAA) |
782 | rr->LastAPTime = m->timenow - rr->ThisAPInterval + mDNSPlatformOneSecond * 10; | | 780 | rr->LastAPTime = m->timenow - rr->ThisAPInterval + mDNSPlatformOneSecond * 10; |
783 | | | 781 | |
784 | // Set LastMCTime to now, to inhibit multicast responses | | 782 | // Set LastMCTime to now, to inhibit multicast responses |
785 | // (no need to send additional multicast responses when we're announcing anyway) | | 783 | // (no need to send additional multicast responses when we're announcing anyway) |
786 | rr->LastMCTime = m->timenow; | | 784 | rr->LastMCTime = m->timenow; |
787 | rr->LastMCInterface = mDNSInterfaceMark; | | 785 | rr->LastMCInterface = mDNSInterfaceMark; |
788 | | | 786 | |
789 | SetNextAnnounceProbeTime(m, rr); | | 787 | SetNextAnnounceProbeTime(m, rr); |
790 | } | | 788 | } |
791 | | | 789 | |
792 | mDNSlocal const domainname *SetUnicastTargetToHostName(mDNS *const m, AuthRecord *rr) | | 790 | mDNSlocal const domainname *SetUnicastTargetToHostName(mDNS *const m, AuthRecord *rr) |
793 | { | | 791 | { |
794 | const domainname *target; | | 792 | const domainname *target; |
795 | if (rr->AutoTarget) | | 793 | if (rr->AutoTarget) |
796 | { | | 794 | { |
797 | // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other | | 795 | // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other |
798 | // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate, | | 796 | // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate, |
799 | // with the port number in our advertised SRV record automatically tracking the external mapped port. | | 797 | // with the port number in our advertised SRV record automatically tracking the external mapped port. |
800 | DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name); | | 798 | DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name); |
801 | if (!AuthInfo || !AuthInfo->AutoTunnel) rr->AutoTarget = Target_AutoHostAndNATMAP; | | 799 | if (!AuthInfo || !AuthInfo->AutoTunnel) rr->AutoTarget = Target_AutoHostAndNATMAP; |
802 | } | | 800 | } |
803 | | | 801 | |
804 | target = GetServiceTarget(m, rr); | | 802 | target = GetServiceTarget(m, rr); |
805 | if (!target || target->c[0] == 0) | | 803 | if (!target || target->c[0] == 0) |
806 | { | | 804 | { |
807 | // defer registration until we've got a target | | 805 | // defer registration until we've got a target |
808 | LogInfo("SetUnicastTargetToHostName No target for %s", ARDisplayString(m, rr)); | | 806 | LogInfo("SetUnicastTargetToHostName No target for %s", ARDisplayString(m, rr)); |
809 | rr->state = regState_NoTarget; | | 807 | rr->state = regState_NoTarget; |
810 | return mDNSNULL; | | 808 | return mDNSNULL; |
811 | } | | 809 | } |
812 | else | | 810 | else |
813 | { | | 811 | { |
814 | LogInfo("SetUnicastTargetToHostName target %##s for resource record %s", target->c, ARDisplayString(m,rr)); | | 812 | LogInfo("SetUnicastTargetToHostName target %##s for resource record %s", target->c, ARDisplayString(m,rr)); |
815 | return target; | | 813 | return target; |
816 | } | | 814 | } |
817 | } | | 815 | } |
818 | | | 816 | |
819 | // Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname | | 817 | // Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname |
820 | // Eventually we should unify this with GetServiceTarget() in uDNS.c | | 818 | // Eventually we should unify this with GetServiceTarget() in uDNS.c |
821 | mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr) | | 819 | mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr) |
822 | { | | 820 | { |
823 | domainname *const target = GetRRDomainNameTarget(&rr->resrec); | | 821 | domainname *const target = GetRRDomainNameTarget(&rr->resrec); |
824 | const domainname *newname = &m->MulticastHostname; | | 822 | const domainname *newname = &m->MulticastHostname; |
825 | | | 823 | |
826 | if (!target) LogInfo("SetTargetToHostName: Don't know how to set the target of rrtype %s", DNSTypeName(rr->resrec.rrtype)); | | 824 | if (!target) LogInfo("SetTargetToHostName: Don't know how to set the target of rrtype %s", DNSTypeName(rr->resrec.rrtype)); |
827 | | | 825 | |
828 | if (!(rr->ForceMCast || rr->ARType == AuthRecordLocalOnly || rr->ARType == AuthRecordP2P || IsLocalDomain(&rr->namestorage))) | | 826 | if (!(rr->ForceMCast || rr->ARType == AuthRecordLocalOnly || rr->ARType == AuthRecordP2P || IsLocalDomain(&rr->namestorage))) |
829 | { | | 827 | { |
830 | const domainname *const n = SetUnicastTargetToHostName(m, rr); | | 828 | const domainname *const n = SetUnicastTargetToHostName(m, rr); |
831 | if (n) newname = n; | | 829 | if (n) newname = n; |
832 | else { target->c[0] = 0; SetNewRData(&rr->resrec, mDNSNULL, 0); return; } | | 830 | else { target->c[0] = 0; SetNewRData(&rr->resrec, mDNSNULL, 0); return; } |
833 | } | | 831 | } |
834 | | | 832 | |
835 | if (target && SameDomainName(target, newname)) | | 833 | if (target && SameDomainName(target, newname)) |
836 | debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name->c, target->c); | | 834 | debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name->c, target->c); |
837 | | | 835 | |
838 | if (target && !SameDomainName(target, newname)) | | 836 | if (target && !SameDomainName(target, newname)) |
839 | { | | 837 | { |
840 | AssignDomainName(target, newname); | | 838 | AssignDomainName(target, newname); |
841 | SetNewRData(&rr->resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash | | 839 | SetNewRData(&rr->resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash |
842 | | | 840 | |
843 | // If we're in the middle of probing this record, we need to start again, | | 841 | // If we're in the middle of probing this record, we need to start again, |
844 | // because changing its rdata may change the outcome of the tie-breaker. | | 842 | // because changing its rdata may change the outcome of the tie-breaker. |
845 | // (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.) | | 843 | // (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.) |
846 | rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); | | 844 | rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); |
847 | | | 845 | |
848 | // If we've announced this record, we really should send a goodbye packet for the old rdata before | | 846 | // If we've announced this record, we really should send a goodbye packet for the old rdata before |
849 | // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records, | | 847 | // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records, |
850 | // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way. | | 848 | // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way. |
851 | if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared) | | 849 | if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared) |
852 | debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating", | | 850 | debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating", |
853 | rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); | | 851 | rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); |
854 | | | 852 | |
855 | rr->AnnounceCount = InitialAnnounceCount; | | 853 | rr->AnnounceCount = InitialAnnounceCount; |
856 | rr->RequireGoodbye = mDNSfalse; | | 854 | rr->RequireGoodbye = mDNSfalse; |
857 | InitializeLastAPTime(m, rr); | | 855 | InitializeLastAPTime(m, rr); |
858 | } | | 856 | } |
859 | } | | 857 | } |
860 | | | 858 | |
861 | mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr) | | 859 | mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr) |
862 | { | | 860 | { |
863 | if (rr->RecordCallback) | | 861 | if (rr->RecordCallback) |
864 | { | | 862 | { |
865 | // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function | | 863 | // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function |
866 | // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. | | 864 | // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. |
867 | rr->Acknowledged = mDNStrue; | | 865 | rr->Acknowledged = mDNStrue; |
868 | mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback | | 866 | mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback |
869 | rr->RecordCallback(m, rr, mStatus_NoError); | | 867 | rr->RecordCallback(m, rr, mStatus_NoError); |
870 | mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again | | 868 | mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again |
871 | } | | 869 | } |
872 | } | | 870 | } |
873 | | | 871 | |
874 | mDNSexport void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr) | | 872 | mDNSexport void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr) |
875 | { | | 873 | { |
876 | // Make sure that we don't activate the SRV record and associated service records, if it is in | | 874 | // Make sure that we don't activate the SRV record and associated service records, if it is in |
877 | // NoTarget state. First time when a service is being instantiated, SRV record may be in NoTarget state. | | 875 | // NoTarget state. First time when a service is being instantiated, SRV record may be in NoTarget state. |
878 | // We should not activate any of the other reords (PTR, TXT) that are part of the service. When | | 876 | // We should not activate any of the other reords (PTR, TXT) that are part of the service. When |
879 | // the target becomes available, the records will be reregistered. | | 877 | // the target becomes available, the records will be reregistered. |
880 | if (rr->resrec.rrtype != kDNSType_SRV) | | 878 | if (rr->resrec.rrtype != kDNSType_SRV) |
881 | { | | 879 | { |
882 | AuthRecord *srvRR = mDNSNULL; | | 880 | AuthRecord *srvRR = mDNSNULL; |
883 | if (rr->resrec.rrtype == kDNSType_PTR) | | 881 | if (rr->resrec.rrtype == kDNSType_PTR) |
884 | srvRR = rr->Additional1; | | 882 | srvRR = rr->Additional1; |
885 | else if (rr->resrec.rrtype == kDNSType_TXT) | | 883 | else if (rr->resrec.rrtype == kDNSType_TXT) |
886 | srvRR = rr->DependentOn; | | 884 | srvRR = rr->DependentOn; |
887 | if (srvRR) | | 885 | if (srvRR) |
888 | { | | 886 | { |
889 | if (srvRR->resrec.rrtype != kDNSType_SRV) | | 887 | if (srvRR->resrec.rrtype != kDNSType_SRV) |
890 | { | | 888 | { |
891 | LogMsg("ActivateUnicastRegistration: ERROR!! Resource record %s wrong, expecting SRV type", ARDisplayString(m, srvRR)); | | 889 | LogMsg("ActivateUnicastRegistration: ERROR!! Resource record %s wrong, expecting SRV type", ARDisplayString(m, srvRR)); |
892 | } | | 890 | } |
893 | else | | 891 | else |
894 | { | | 892 | { |
895 | LogInfo("ActivateUnicastRegistration: Found Service Record %s in state %d for %##s (%s)", | | 893 | LogInfo("ActivateUnicastRegistration: Found Service Record %s in state %d for %##s (%s)", |
896 | ARDisplayString(m, srvRR), srvRR->state, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); | | 894 | ARDisplayString(m, srvRR), srvRR->state, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); |
897 | rr->state = srvRR->state; | | 895 | rr->state = srvRR->state; |
898 | } | | 896 | } |
899 | } | | 897 | } |
900 | } | | 898 | } |
901 | | | 899 | |
902 | if (rr->state == regState_NoTarget) | | 900 | if (rr->state == regState_NoTarget) |
903 | { | | 901 | { |
904 | LogInfo("ActivateUnicastRegistration record %s in regState_NoTarget, not activating", ARDisplayString(m, rr)); | | 902 | LogInfo("ActivateUnicastRegistration record %s in regState_NoTarget, not activating", ARDisplayString(m, rr)); |
905 | return; | | 903 | return; |
906 | } | | 904 | } |
907 | // When we wake up from sleep, we call ActivateUnicastRegistration. It is possible that just before we went to sleep, | | 905 | // When we wake up from sleep, we call ActivateUnicastRegistration. It is possible that just before we went to sleep, |
908 | // the service/record was being deregistered. In that case, we should not try to register again. For the cases where | | 906 | // the service/record was being deregistered. In that case, we should not try to register again. For the cases where |
909 | // the records are deregistered due to e.g., no target for the SRV record, we would have returned from above if it | | 907 | // the records are deregistered due to e.g., no target for the SRV record, we would have returned from above if it |
910 | // was already in NoTarget state. If it was in the process of deregistration but did not complete fully before we went | | 908 | // was already in NoTarget state. If it was in the process of deregistration but did not complete fully before we went |
911 | // to sleep, then it is okay to start in Pending state as we will go back to NoTarget state if we don't have a target. | | 909 | // to sleep, then it is okay to start in Pending state as we will go back to NoTarget state if we don't have a target. |
912 | if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) | | 910 | if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) |
913 | { | | 911 | { |
914 | LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to DeregPending", ARDisplayString(m, rr), rr->state); | | 912 | LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to DeregPending", ARDisplayString(m, rr), rr->state); |
915 | rr->state = regState_DeregPending; | | 913 | rr->state = regState_DeregPending; |
916 | } | | 914 | } |
917 | else | | 915 | else |
918 | { | | 916 | { |
919 | LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to Pending", ARDisplayString(m, rr), rr->state); | | 917 | LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to Pending", ARDisplayString(m, rr), rr->state); |
920 | rr->state = regState_Pending; | | 918 | rr->state = regState_Pending; |
921 | } | | 919 | } |
922 | rr->ProbeCount = 0; | | 920 | rr->ProbeCount = 0; |
923 | rr->AnnounceCount = 0; | | 921 | rr->AnnounceCount = 0; |
924 | rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL; | | 922 | rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL; |
925 | rr->LastAPTime = m->timenow - rr->ThisAPInterval; | | 923 | rr->LastAPTime = m->timenow - rr->ThisAPInterval; |
926 | rr->expire = 0; // Forget about all the leases, start fresh | | 924 | rr->expire = 0; // Forget about all the leases, start fresh |
927 | rr->uselease = mDNStrue; | | 925 | rr->uselease = mDNStrue; |
928 | rr->updateid = zeroID; | | 926 | rr->updateid = zeroID; |
929 | rr->SRVChanged = mDNSfalse; | | 927 | rr->SRVChanged = mDNSfalse; |
930 | rr->updateError = mStatus_NoError; | | 928 | rr->updateError = mStatus_NoError; |
931 | // RestartRecordGetZoneData calls this function whenever a new interface gets registered with core. | | 929 | // RestartRecordGetZoneData calls this function whenever a new interface gets registered with core. |
932 | // The records might already be registered with the server and hence could have NAT state. | | 930 | // The records might already be registered with the server and hence could have NAT state. |
933 | if (rr->NATinfo.clientContext) | | 931 | if (rr->NATinfo.clientContext) |
934 | { | | 932 | { |
935 | mDNS_StopNATOperation_internal(m, &rr->NATinfo); | | 933 | mDNS_StopNATOperation_internal(m, &rr->NATinfo); |
936 | rr->NATinfo.clientContext = mDNSNULL; | | 934 | rr->NATinfo.clientContext = mDNSNULL; |
937 | } | | 935 | } |
938 | if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; } | | 936 | if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; } |
939 | if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } | | 937 | if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } |
940 | if (m->NextuDNSEvent - (rr->LastAPTime + rr->ThisAPInterval) >= 0) | | 938 | if (m->NextuDNSEvent - (rr->LastAPTime + rr->ThisAPInterval) >= 0) |
941 | m->NextuDNSEvent = (rr->LastAPTime + rr->ThisAPInterval); | | 939 | m->NextuDNSEvent = (rr->LastAPTime + rr->ThisAPInterval); |
942 | } | | 940 | } |
943 | | | 941 | |
944 | // Two records qualify to be local duplicates if: | | 942 | // Two records qualify to be local duplicates if: |
945 | // (a) the RecordTypes are the same, or | | 943 | // (a) the RecordTypes are the same, or |
946 | // (b) one is Unique and the other Verified | | 944 | // (b) one is Unique and the other Verified |
947 | // (c) either is in the process of deregistering | | 945 | // (c) either is in the process of deregistering |
948 | #define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \ | | 946 | #define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \ |
949 | ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified) || \ | | 947 | ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified) || \ |
950 | ((A)->resrec.RecordType == kDNSRecordTypeDeregistering || (B)->resrec.RecordType == kDNSRecordTypeDeregistering)) | | 948 | ((A)->resrec.RecordType == kDNSRecordTypeDeregistering || (B)->resrec.RecordType == kDNSRecordTypeDeregistering)) |
951 | | | 949 | |
952 | #define RecordIsLocalDuplicate(A,B) \ | | 950 | #define RecordIsLocalDuplicate(A,B) \ |
953 | ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec)) | | 951 | ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec)) |
954 | | | 952 | |
955 | mDNSlocal AuthRecord *CheckAuthIdenticalRecord(AuthHash *r, AuthRecord *rr) | | 953 | mDNSlocal AuthRecord *CheckAuthIdenticalRecord(AuthHash *r, AuthRecord *rr) |
956 | { | | 954 | { |
957 | AuthGroup *a; | | 955 | AuthGroup *a; |
958 | AuthGroup **ag = &a; | | 956 | AuthGroup **ag = &a; |
959 | AuthRecord **rp; | | 957 | AuthRecord **rp; |
960 | const mDNSu32 slot = AuthHashSlot(rr->resrec.name); | | 958 | const mDNSu32 slot = AuthHashSlot(rr->resrec.name); |
961 | | | 959 | |
962 | a = AuthGroupForRecord(r, slot, &rr->resrec); | | 960 | a = AuthGroupForRecord(r, slot, &rr->resrec); |
963 | if (!a) return mDNSNULL; | | 961 | if (!a) return mDNSNULL; |
964 | rp = &(*ag)->members; | | 962 | rp = &(*ag)->members; |
965 | while (*rp) | | 963 | while (*rp) |
966 | { | | 964 | { |
967 | if (!RecordIsLocalDuplicate(*rp, rr)) | | 965 | if (!RecordIsLocalDuplicate(*rp, rr)) |
968 | rp=&(*rp)->next; | | 966 | rp=&(*rp)->next; |
969 | else | | 967 | else |
970 | { | | 968 | { |
971 | if ((*rp)->resrec.RecordType == kDNSRecordTypeDeregistering) | | 969 | if ((*rp)->resrec.RecordType == kDNSRecordTypeDeregistering) |
972 | { | | 970 | { |
973 | (*rp)->AnnounceCount = 0; | | 971 | (*rp)->AnnounceCount = 0; |
974 | rp=&(*rp)->next; | | 972 | rp=&(*rp)->next; |
975 | } | | 973 | } |
976 | else return *rp; | | 974 | else return *rp; |
977 | } | | 975 | } |
978 | } | | 976 | } |
979 | return (mDNSNULL); | | 977 | return (mDNSNULL); |
980 | } | | 978 | } |
981 | | | 979 | |
982 | mDNSlocal mDNSBool CheckAuthRecordConflict(AuthHash *r, AuthRecord *rr) | | 980 | mDNSlocal mDNSBool CheckAuthRecordConflict(AuthHash *r, AuthRecord *rr) |
983 | { | | 981 | { |
984 | AuthGroup *a; | | 982 | AuthGroup *a; |
985 | AuthGroup **ag = &a; | | 983 | AuthGroup **ag = &a; |
986 | AuthRecord **rp; | | 984 | AuthRecord **rp; |
987 | const mDNSu32 slot = AuthHashSlot(rr->resrec.name); | | 985 | const mDNSu32 slot = AuthHashSlot(rr->resrec.name); |
988 | | | 986 | |
989 | a = AuthGroupForRecord(r, slot, &rr->resrec); | | 987 | a = AuthGroupForRecord(r, slot, &rr->resrec); |
990 | if (!a) return mDNSfalse; | | 988 | if (!a) return mDNSfalse; |
991 | rp = &(*ag)->members; | | 989 | rp = &(*ag)->members; |
992 | while (*rp) | | 990 | while (*rp) |
993 | { | | 991 | { |
994 | const AuthRecord *s1 = rr->RRSet ? rr->RRSet : rr; | | 992 | const AuthRecord *s1 = rr->RRSet ? rr->RRSet : rr; |
995 | const AuthRecord *s2 = (*rp)->RRSet ? (*rp)->RRSet : *rp; | | 993 | const AuthRecord *s2 = (*rp)->RRSet ? (*rp)->RRSet : *rp; |
996 | if (s1 != s2 && SameResourceRecordSignature((*rp), rr) && !IdenticalSameNameRecord(&(*rp)->resrec, &rr->resrec)) | | 994 | if (s1 != s2 && SameResourceRecordSignature((*rp), rr) && !IdenticalSameNameRecord(&(*rp)->resrec, &rr->resrec)) |
997 | return mDNStrue; | | 995 | return mDNStrue; |
998 | else | | 996 | else |
999 | rp=&(*rp)->next; | | 997 | rp=&(*rp)->next; |
1000 | } | | 998 | } |
1001 | return (mDNSfalse); | | 999 | return (mDNSfalse); |
1002 | } | | 1000 | } |
1003 | | | 1001 | |
1004 | // checks to see if "rr" is already present | | 1002 | // checks to see if "rr" is already present |
1005 | mDNSlocal AuthRecord *CheckAuthSameRecord(AuthHash *r, AuthRecord *rr) | | 1003 | mDNSlocal AuthRecord *CheckAuthSameRecord(AuthHash *r, AuthRecord *rr) |
1006 | { | | 1004 | { |
1007 | AuthGroup *a; | | 1005 | AuthGroup *a; |
1008 | AuthGroup **ag = &a; | | 1006 | AuthGroup **ag = &a; |
1009 | AuthRecord **rp; | | 1007 | AuthRecord **rp; |
1010 | const mDNSu32 slot = AuthHashSlot(rr->resrec.name); | | 1008 | const mDNSu32 slot = AuthHashSlot(rr->resrec.name); |
1011 | | | 1009 | |
1012 | a = AuthGroupForRecord(r, slot, &rr->resrec); | | 1010 | a = AuthGroupForRecord(r, slot, &rr->resrec); |
1013 | if (!a) return mDNSNULL; | | 1011 | if (!a) return mDNSNULL; |
1014 | rp = &(*ag)->members; | | 1012 | rp = &(*ag)->members; |
1015 | while (*rp) | | 1013 | while (*rp) |
1016 | { | | 1014 | { |
1017 | if (*rp != rr) | | 1015 | if (*rp != rr) |
1018 | rp=&(*rp)->next; | | 1016 | rp=&(*rp)->next; |
1019 | else | | 1017 | else |
1020 | { | | 1018 | { |
1021 | return *rp; | | 1019 | return *rp; |
1022 | } | | 1020 | } |
1023 | } | | 1021 | } |
1024 | return (mDNSNULL); | | 1022 | return (mDNSNULL); |
1025 | } | | 1023 | } |
1026 | | | 1024 | |
1027 | // Exported so uDNS.c can call this | | 1025 | // Exported so uDNS.c can call this |
1028 | mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) | | 1026 | mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) |
1029 | { | | 1027 | { |
1030 | domainname *target = GetRRDomainNameTarget(&rr->resrec); | | 1028 | domainname *target = GetRRDomainNameTarget(&rr->resrec); |
1031 | AuthRecord *r; | | 1029 | AuthRecord *r; |
1032 | AuthRecord **p = &m->ResourceRecords; | | 1030 | AuthRecord **p = &m->ResourceRecords; |
1033 | AuthRecord **d = &m->DuplicateRecords; | | 1031 | AuthRecord **d = &m->DuplicateRecords; |
1034 | | | 1032 | |
1035 | if ((mDNSs32)rr->resrec.rroriginalttl <= 0) | | 1033 | if ((mDNSs32)rr->resrec.rroriginalttl <= 0) |
1036 | { LogMsg("mDNS_Register_internal: TTL %X should be 1 - 0x7FFFFFFF %s", rr->resrec.rroriginalttl, ARDisplayString(m, rr)); return(mStatus_BadParamErr); } | | 1034 | { LogMsg("mDNS_Register_internal: TTL %X should be 1 - 0x7FFFFFFF %s", rr->resrec.rroriginalttl, ARDisplayString(m, rr)); return(mStatus_BadParamErr); } |
1037 | | | 1035 | |
1038 | if (!rr->resrec.RecordType) | | 1036 | if (!rr->resrec.RecordType) |
1039 | { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); } | | 1037 | { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); } |
1040 | | | 1038 | |
1041 | if (m->ShutdownTime) | | 1039 | if (m->ShutdownTime) |
1042 | { LogMsg("mDNS_Register_internal: Shutting down, can't register %s", ARDisplayString(m, rr)); return(mStatus_ServiceNotRunning); } | | 1040 | { LogMsg("mDNS_Register_internal: Shutting down, can't register %s", ARDisplayString(m, rr)); return(mStatus_ServiceNotRunning); } |
1043 | | | 1041 | |
1044 | if (m->DivertMulticastAdvertisements && !AuthRecord_uDNS(rr)) | | 1042 | if (m->DivertMulticastAdvertisements && !AuthRecord_uDNS(rr)) |
1045 | { | | 1043 | { |
1046 | mDNSInterfaceID previousID = rr->resrec.InterfaceID; | | 1044 | mDNSInterfaceID previousID = rr->resrec.InterfaceID; |
1047 | if (rr->resrec.InterfaceID == mDNSInterface_Any || rr->resrec.InterfaceID == mDNSInterface_P2P) | | 1045 | if (rr->resrec.InterfaceID == mDNSInterface_Any || rr->resrec.InterfaceID == mDNSInterface_P2P) |
1048 | { | | 1046 | { |
1049 | rr->resrec.InterfaceID = mDNSInterface_LocalOnly; | | 1047 | rr->resrec.InterfaceID = mDNSInterface_LocalOnly; |
1050 | rr->ARType = AuthRecordLocalOnly; | | 1048 | rr->ARType = AuthRecordLocalOnly; |
1051 | } | | 1049 | } |
1052 | if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly) | | 1050 | if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly) |
1053 | { | | 1051 | { |
1054 | NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID); | | 1052 | NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID); |
1055 | if (intf && !intf->Advertise){ rr->resrec.InterfaceID = mDNSInterface_LocalOnly; rr->ARType = AuthRecordLocalOnly; } | | 1053 | if (intf && !intf->Advertise){ rr->resrec.InterfaceID = mDNSInterface_LocalOnly; rr->ARType = AuthRecordLocalOnly; } |
1056 | } | | 1054 | } |
1057 | if (rr->resrec.InterfaceID != previousID) | | 1055 | if (rr->resrec.InterfaceID != previousID) |
1058 | LogInfo("mDNS_Register_internal: Diverting record to local-only %s", ARDisplayString(m, rr)); | | 1056 | LogInfo("mDNS_Register_internal: Diverting record to local-only %s", ARDisplayString(m, rr)); |
1059 | } | | 1057 | } |
1060 | | | 1058 | |
1061 | if (RRLocalOnly(rr)) | | 1059 | if (RRLocalOnly(rr)) |
1062 | { | | 1060 | { |
1063 | if (CheckAuthSameRecord(&m->rrauth, rr)) | | 1061 | if (CheckAuthSameRecord(&m->rrauth, rr)) |
1064 | { | | 1062 | { |
1065 | LogMsg("mDNS_Register_internal: ERROR!! Tried to register LocalOnly AuthRecord %p %##s (%s) that's already in the list", | | 1063 | LogMsg("mDNS_Register_internal: ERROR!! Tried to register LocalOnly AuthRecord %p %##s (%s) that's already in the list", |
1066 | rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); | | 1064 | rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); |
1067 | return(mStatus_AlreadyRegistered); | | 1065 | return(mStatus_AlreadyRegistered); |
1068 | } | | 1066 | } |
1069 | } | | 1067 | } |
1070 | else | | 1068 | else |
1071 | { | | 1069 | { |
1072 | while (*p && *p != rr) p=&(*p)->next; | | 1070 | while (*p && *p != rr) p=&(*p)->next; |
1073 | if (*p) | | 1071 | if (*p) |
1074 | { | | 1072 | { |
1075 | LogMsg("mDNS_Register_internal: ERROR!! Tried to register AuthRecord %p %##s (%s) that's already in the list", | | 1073 | LogMsg("mDNS_Register_internal: ERROR!! Tried to register AuthRecord %p %##s (%s) that's already in the list", |
1076 | rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); | | 1074 | rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); |
1077 | return(mStatus_AlreadyRegistered); | | 1075 | return(mStatus_AlreadyRegistered); |
1078 | } | | 1076 | } |
1079 | } | | 1077 | } |
1080 | | | 1078 | |
1081 | while (*d && *d != rr) d=&(*d)->next; | | 1079 | while (*d && *d != rr) d=&(*d)->next; |
1082 | if (*d) | | 1080 | if (*d) |
1083 | { | | 1081 | { |
1084 | LogMsg("mDNS_Register_internal: ERROR!! Tried to register AuthRecord %p %##s (%s) that's already in the Duplicate list", | | 1082 | LogMsg("mDNS_Register_internal: ERROR!! Tried to register AuthRecord %p %##s (%s) that's already in the Duplicate list", |
1085 | rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); | | 1083 | rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); |
1086 | return(mStatus_AlreadyRegistered); | | 1084 | return(mStatus_AlreadyRegistered); |
1087 | } | | 1085 | } |
1088 | | | 1086 | |
1089 | if (rr->DependentOn) | | 1087 | if (rr->DependentOn) |
1090 | { | | 1088 | { |
1091 | if (rr->resrec.RecordType == kDNSRecordTypeUnique) | | 1089 | if (rr->resrec.RecordType == kDNSRecordTypeUnique) |
1092 | rr->resrec.RecordType = kDNSRecordTypeVerified; | | 1090 | rr->resrec.RecordType = kDNSRecordTypeVerified; |
1093 | else | | 1091 | else |
1094 | { | | 1092 | { |
1095 | LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique", | | 1093 | LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique", |
1096 | rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); | | 1094 | rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); |
1097 | return(mStatus_Invalid); | | 1095 | return(mStatus_Invalid); |
1098 | } | | 1096 | } |
1099 | if (!(rr->DependentOn->resrec.RecordType & (kDNSRecordTypeUnique | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique))) | | 1097 | if (!(rr->DependentOn->resrec.RecordType & (kDNSRecordTypeUnique | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique))) |
1100 | { | | 1098 | { |
1101 | LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X", | | 1099 | LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X", |
1102 | rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->DependentOn->resrec.RecordType); | | 1100 | rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->DependentOn->resrec.RecordType); |
1103 | return(mStatus_Invalid); | | 1101 | return(mStatus_Invalid); |
1104 | } | | 1102 | } |
1105 | } | | 1103 | } |
1106 | | | 1104 | |
1107 | // If this resource record is referencing a specific interface, make sure it exists. | | 1105 | // If this resource record is referencing a specific interface, make sure it exists. |
1108 | // Skip checks for LocalOnly and P2P as they are not valid InterfaceIDs. Also, for scoped | | 1106 | // Skip checks for LocalOnly and P2P as they are not valid InterfaceIDs. Also, for scoped |
1109 | // entries in /etc/hosts skip that check as that interface may not be valid at this time. | | 1107 | // entries in /etc/hosts skip that check as that interface may not be valid at this time. |
1110 | if (rr->resrec.InterfaceID && rr->ARType != AuthRecordLocalOnly && rr->ARType != AuthRecordP2P) | | 1108 | if (rr->resrec.InterfaceID && rr->ARType != AuthRecordLocalOnly && rr->ARType != AuthRecordP2P) |
1111 | { | | 1109 | { |
1112 | NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID); | | 1110 | NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID); |
1113 | if (!intf) | | 1111 | if (!intf) |
1114 | { | | 1112 | { |
1115 | debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr->resrec.InterfaceID); | | 1113 | debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr->resrec.InterfaceID); |
1116 | return(mStatus_BadReferenceErr); | | 1114 | return(mStatus_BadReferenceErr); |
1117 | } | | 1115 | } |
1118 | } | | 1116 | } |
1119 | | | 1117 | |
1120 | rr->next = mDNSNULL; | | 1118 | rr->next = mDNSNULL; |
1121 | | | 1119 | |
1122 | // Field Group 1: The actual information pertaining to this resource record | | 1120 | // Field Group 1: The actual information pertaining to this resource record |
1123 | // Set up by client prior to call | | 1121 | // Set up by client prior to call |
1124 | | | 1122 | |
1125 | // Field Group 2: Persistent metadata for Authoritative Records | | 1123 | // Field Group 2: Persistent metadata for Authoritative Records |
1126 | // rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client | | 1124 | // rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client |
1127 | // rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client | | 1125 | // rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client |
1128 | // rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client | | 1126 | // rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client |
1129 | // rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client | | 1127 | // rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client |
1130 | // rr->Callback = already set in mDNS_SetupResourceRecord | | 1128 | // rr->Callback = already set in mDNS_SetupResourceRecord |
1131 | // rr->Context = already set in mDNS_SetupResourceRecord | | 1129 | // rr->Context = already set in mDNS_SetupResourceRecord |
1132 | // rr->RecordType = already set in mDNS_SetupResourceRecord | | 1130 | // rr->RecordType = already set in mDNS_SetupResourceRecord |
1133 | // rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client | | 1131 | // rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client |
1134 | // rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client | | 1132 | // rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client |
1135 | // Make sure target is not uninitialized data, or we may crash writing debugging log messages | | 1133 | // Make sure target is not uninitialized data, or we may crash writing debugging log messages |
1136 | if (rr->AutoTarget && target) target->c[0] = 0; | | 1134 | if (rr->AutoTarget && target) target->c[0] = 0; |
1137 | | | 1135 | |
1138 | // Field Group 3: Transient state for Authoritative Records | | 1136 | // Field Group 3: Transient state for Authoritative Records |
1139 | rr->Acknowledged = mDNSfalse; | | 1137 | rr->Acknowledged = mDNSfalse; |
1140 | rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); | | 1138 | rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); |
1141 | rr->AnnounceCount = InitialAnnounceCount; | | 1139 | rr->AnnounceCount = InitialAnnounceCount; |
1142 | rr->RequireGoodbye = mDNSfalse; | | 1140 | rr->RequireGoodbye = mDNSfalse; |
1143 | rr->AnsweredLocalQ = mDNSfalse; | | 1141 | rr->AnsweredLocalQ = mDNSfalse; |
1144 | rr->IncludeInProbe = mDNSfalse; | | 1142 | rr->IncludeInProbe = mDNSfalse; |
1145 | rr->ImmedUnicast = mDNSfalse; | | 1143 | rr->ImmedUnicast = mDNSfalse; |
1146 | rr->SendNSECNow = mDNSNULL; | | 1144 | rr->SendNSECNow = mDNSNULL; |
1147 | rr->ImmedAnswer = mDNSNULL; | | 1145 | rr->ImmedAnswer = mDNSNULL; |
1148 | rr->ImmedAdditional = mDNSNULL; | | 1146 | rr->ImmedAdditional = mDNSNULL; |
1149 | rr->SendRNow = mDNSNULL; | | 1147 | rr->SendRNow = mDNSNULL; |
1150 | rr->v4Requester = zerov4Addr; | | 1148 | rr->v4Requester = zerov4Addr; |
1151 | rr->v6Requester = zerov6Addr; | | 1149 | rr->v6Requester = zerov6Addr; |
1152 | rr->NextResponse = mDNSNULL; | | 1150 | rr->NextResponse = mDNSNULL; |
1153 | rr->NR_AnswerTo = mDNSNULL; | | 1151 | rr->NR_AnswerTo = mDNSNULL; |
1154 | rr->NR_AdditionalTo = mDNSNULL; | | 1152 | rr->NR_AdditionalTo = mDNSNULL; |
1155 | if (!rr->AutoTarget) InitializeLastAPTime(m, rr); | | 1153 | if (!rr->AutoTarget) InitializeLastAPTime(m, rr); |
1156 | // rr->LastAPTime = Set for us in InitializeLastAPTime() | | 1154 | // rr->LastAPTime = Set for us in InitializeLastAPTime() |
1157 | // rr->LastMCTime = Set for us in InitializeLastAPTime() | | 1155 | // rr->LastMCTime = Set for us in InitializeLastAPTime() |
1158 | // rr->LastMCInterface = Set for us in InitializeLastAPTime() | | 1156 | // rr->LastMCInterface = Set for us in InitializeLastAPTime() |
1159 | rr->NewRData = mDNSNULL; | | 1157 | rr->NewRData = mDNSNULL; |
1160 | rr->newrdlength = 0; | | 1158 | rr->newrdlength = 0; |
1161 | rr->UpdateCallback = mDNSNULL; | | 1159 | rr->UpdateCallback = mDNSNULL; |
1162 | rr->UpdateCredits = kMaxUpdateCredits; | | 1160 | rr->UpdateCredits = kMaxUpdateCredits; |
1163 | rr->NextUpdateCredit = 0; | | 1161 | rr->NextUpdateCredit = 0; |
1164 | rr->UpdateBlocked = 0; | | 1162 | rr->UpdateBlocked = 0; |
1165 | | | 1163 | |
1166 | // For records we're holding as proxy (except reverse-mapping PTR records) two announcements is sufficient | | 1164 | // For records we're holding as proxy (except reverse-mapping PTR records) two announcements is sufficient |
1167 | if (rr->WakeUp.HMAC.l[0] && !rr->AddressProxy.type) rr->AnnounceCount = 2; | | 1165 | if (rr->WakeUp.HMAC.l[0] && !rr->AddressProxy.type) rr->AnnounceCount = 2; |
1168 | | | 1166 | |
1169 | // Field Group 4: Transient uDNS state for Authoritative Records | | 1167 | // Field Group 4: Transient uDNS state for Authoritative Records |
1170 | rr->state = regState_Zero; | | 1168 | rr->state = regState_Zero; |
1171 | rr->uselease = 0; | | 1169 | rr->uselease = 0; |
1172 | rr->expire = 0; | | 1170 | rr->expire = 0; |
1173 | rr->Private = 0; | | 1171 | rr->Private = 0; |
1174 | rr->updateid = zeroID; | | 1172 | rr->updateid = zeroID; |
1175 | rr->zone = rr->resrec.name; | | 1173 | rr->zone = rr->resrec.name; |
1176 | rr->nta = mDNSNULL; | | 1174 | rr->nta = mDNSNULL; |
1177 | rr->tcp = mDNSNULL; | | 1175 | rr->tcp = mDNSNULL; |
1178 | rr->OrigRData = 0; | | 1176 | rr->OrigRData = 0; |
1179 | rr->OrigRDLen = 0; | | 1177 | rr->OrigRDLen = 0; |
1180 | rr->InFlightRData = 0; | | 1178 | rr->InFlightRData = 0; |
1181 | rr->InFlightRDLen = 0; | | 1179 | rr->InFlightRDLen = 0; |
1182 | rr->QueuedRData = 0; | | 1180 | rr->QueuedRData = 0; |
1183 | rr->QueuedRDLen = 0; | | 1181 | rr->QueuedRDLen = 0; |
1184 | //mDNSPlatformMemZero(&rr->NATinfo, sizeof(rr->NATinfo)); | | 1182 | //mDNSPlatformMemZero(&rr->NATinfo, sizeof(rr->NATinfo)); |
1185 | // We should be recording the actual internal port for this service record here. Once we initiate our NAT mapping | | 1183 | // We should be recording the actual internal port for this service record here. Once we initiate our NAT mapping |
1186 | // request we'll subsequently overwrite srv.port with the allocated external NAT port -- potentially multiple | | 1184 | // request we'll subsequently overwrite srv.port with the allocated external NAT port -- potentially multiple |
1187 | // times with different values if the external NAT port changes during the lifetime of the service registration. | | 1185 | // times with different values if the external NAT port changes during the lifetime of the service registration. |
1188 | //if (rr->resrec.rrtype == kDNSType_SRV) rr->NATinfo.IntPort = rr->resrec.rdata->u.srv.port; | | 1186 | //if (rr->resrec.rrtype == kDNSType_SRV) rr->NATinfo.IntPort = rr->resrec.rdata->u.srv.port; |
1189 | | | 1187 | |
1190 | // rr->resrec.interface = already set in mDNS_SetupResourceRecord | | 1188 | // rr->resrec.interface = already set in mDNS_SetupResourceRecord |
1191 | // rr->resrec.name->c = MUST be set by client | | 1189 | // rr->resrec.name->c = MUST be set by client |
1192 | // rr->resrec.rrtype = already set in mDNS_SetupResourceRecord | | 1190 | // rr->resrec.rrtype = already set in mDNS_SetupResourceRecord |
1193 | // rr->resrec.rrclass = already set in mDNS_SetupResourceRecord | | 1191 | // rr->resrec.rrclass = already set in mDNS_SetupResourceRecord |
1194 | // rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord | | 1192 | // rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord |
1195 | // rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set | | 1193 | // rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set |
1196 | | | 1194 | |
1197 | // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct, | | 1195 | // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct, |
1198 | // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s". | | 1196 | // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s". |
1199 | // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here. | | 1197 | // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here. |
1200 | if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; } | | 1198 | if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; } |
1201 | | | 1199 | |
1202 | if (rr->AutoTarget) | | 1200 | if (rr->AutoTarget) |
1203 | { | | 1201 | { |
1204 | SetTargetToHostName(m, rr); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime(); | | 1202 | SetTargetToHostName(m, rr); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime(); |
1205 | #ifndef UNICAST_DISABLED | | 1203 | #ifndef UNICAST_DISABLED |
1206 | // If we have no target record yet, SetTargetToHostName will set rr->state == regState_NoTarget | | 1204 | // If we have no target record yet, SetTargetToHostName will set rr->state == regState_NoTarget |
1207 | // In this case we leave the record half-formed in the list, and later we'll remove it from the list and re-add it properly. | | 1205 | // In this case we leave the record half-formed in the list, and later we'll remove it from the list and re-add it properly. |
1208 | if (rr->state == regState_NoTarget) | | 1206 | if (rr->state == regState_NoTarget) |
1209 | { | | 1207 | { |
1210 | // Initialize the target so that we don't crash while logging etc. | | 1208 | // Initialize the target so that we don't crash while logging etc. |
1211 | domainname *tar = GetRRDomainNameTarget(&rr->resrec); | | 1209 | domainname *tar = GetRRDomainNameTarget(&rr->resrec); |
1212 | if (tar) tar->c[0] = 0; | | 1210 | if (tar) tar->c[0] = 0; |
1213 | LogInfo("mDNS_Register_internal: record %s in NoTarget state", ARDisplayString(m, rr)); | | 1211 | LogInfo("mDNS_Register_internal: record %s in NoTarget state", ARDisplayString(m, rr)); |
1214 | } | | 1212 | } |
1215 | #endif | | 1213 | #endif |
1216 | } | | 1214 | } |
1217 | else | | 1215 | else |
1218 | { | | 1216 | { |
1219 | rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse); | | 1217 | rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse); |
1220 | rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue); | | 1218 | rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue); |
1221 | } | | 1219 | } |
1222 | | | 1220 | |
1223 | if (!ValidateDomainName(rr->resrec.name)) | | 1221 | if (!ValidateDomainName(rr->resrec.name)) |
1224 | { LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); } | | 1222 | { LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); } |
1225 | | | 1223 | |
1226 | // Don't do this until *after* we've set rr->resrec.rdlength | | 1224 | // Don't do this until *after* we've set rr->resrec.rdlength |
1227 | if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata)) | | 1225 | if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata)) |
1228 | { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); } | | 1226 | { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); } |
1229 | | | 1227 | |
1230 | rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); | | 1228 | rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); |
1231 | rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(&rr->resrec); | | 1229 | rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(&rr->resrec); |
1232 | | | 1230 | |
1233 | if (RRLocalOnly(rr)) | | 1231 | if (RRLocalOnly(rr)) |
1234 | { | | 1232 | { |
1235 | // If this is supposed to be unique, make sure we don't have any name conflicts. | | 1233 | // If this is supposed to be unique, make sure we don't have any name conflicts. |
1236 | // If we found a conflict, we may still want to insert the record in the list but mark it appropriately | | 1234 | // If we found a conflict, we may still want to insert the record in the list but mark it appropriately |
1237 | // (kDNSRecordTypeDeregistering) so that we deliver RMV events to the application. But this causes more | | 1235 | // (kDNSRecordTypeDeregistering) so that we deliver RMV events to the application. But this causes more |
1238 | // complications and not clear whether there are any benefits. See rdar:9304275 for details. | | 1236 | // complications and not clear whether there are any benefits. See rdar:9304275 for details. |
1239 | // Hence, just bail out. | | 1237 | // Hence, just bail out. |
1240 | if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) | | 1238 | if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) |
1241 | { | | 1239 | { |
1242 | if (CheckAuthRecordConflict(&m->rrauth, rr)) | | 1240 | if (CheckAuthRecordConflict(&m->rrauth, rr)) |
1243 | { | | 1241 | { |
1244 | LogInfo("mDNS_Register_internal: Name conflict %s (%p), InterfaceID %p", ARDisplayString(m, rr), rr, rr->resrec.InterfaceID); | | 1242 | LogInfo("mDNS_Register_internal: Name conflict %s (%p), InterfaceID %p", ARDisplayString(m, rr), rr, rr->resrec.InterfaceID); |
1245 | return mStatus_NameConflict; | | 1243 | return mStatus_NameConflict; |
1246 | } | | 1244 | } |
1247 | } | | 1245 | } |
1248 | } | | 1246 | } |
1249 | | | 1247 | |
1250 | // For uDNS records, we don't support duplicate checks at this time. | | 1248 | // For uDNS records, we don't support duplicate checks at this time. |
1251 | #ifndef UNICAST_DISABLED | | 1249 | #ifndef UNICAST_DISABLED |
1252 | if (AuthRecord_uDNS(rr)) | | 1250 | if (AuthRecord_uDNS(rr)) |
1253 | { | | 1251 | { |
1254 | if (!m->NewLocalRecords) m->NewLocalRecords = rr; | | 1252 | if (!m->NewLocalRecords) m->NewLocalRecords = rr; |
1255 | // When we called SetTargetToHostName, it may have caused mDNS_Register_internal to be re-entered, appending new | | 1253 | // When we called SetTargetToHostName, it may have caused mDNS_Register_internal to be re-entered, appending new |
1256 | // records to the list, so we now need to update p to advance to the new end to the list before appending our new record. | | 1254 | // records to the list, so we now need to update p to advance to the new end to the list before appending our new record. |
1257 | // Note that for AutoTunnel this should never happen, but this check makes the code future-proof. | | 1255 | // Note that for AutoTunnel this should never happen, but this check makes the code future-proof. |
1258 | while (*p) p=&(*p)->next; | | 1256 | while (*p) p=&(*p)->next; |
1259 | *p = rr; | | 1257 | *p = rr; |
1260 | if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified; | | 1258 | if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified; |
1261 | rr->ProbeCount = 0; | | 1259 | rr->ProbeCount = 0; |
1262 | rr->AnnounceCount = 0; | | 1260 | rr->AnnounceCount = 0; |
1263 | if (rr->state != regState_NoTarget) ActivateUnicastRegistration(m, rr); | | 1261 | if (rr->state != regState_NoTarget) ActivateUnicastRegistration(m, rr); |
1264 | return(mStatus_NoError); // <--- Note: For unicast records, code currently bails out at this point | | 1262 | return(mStatus_NoError); // <--- Note: For unicast records, code currently bails out at this point |
1265 | } | | 1263 | } |
1266 | #endif | | 1264 | #endif |
1267 | | | 1265 | |
1268 | // Now that we've finished building our new record, make sure it's not identical to one we already have | | 1266 | // Now that we've finished building our new record, make sure it's not identical to one we already have |
1269 | if (RRLocalOnly(rr)) | | 1267 | if (RRLocalOnly(rr)) |
1270 | { | | 1268 | { |
1271 | rr->ProbeCount = 0; | | 1269 | rr->ProbeCount = 0; |
1272 | rr->AnnounceCount = 0; | | 1270 | rr->AnnounceCount = 0; |
1273 | r = CheckAuthIdenticalRecord(&m->rrauth, rr); | | 1271 | r = CheckAuthIdenticalRecord(&m->rrauth, rr); |
1274 | } | | 1272 | } |
1275 | else | | 1273 | else |
1276 | { | | 1274 | { |
1277 | for (r = m->ResourceRecords; r; r=r->next) | | 1275 | for (r = m->ResourceRecords; r; r=r->next) |
1278 | if (RecordIsLocalDuplicate(r, rr)) | | 1276 | if (RecordIsLocalDuplicate(r, rr)) |
1279 | { | | 1277 | { |
1280 | if (r->resrec.RecordType == kDNSRecordTypeDeregistering) r->AnnounceCount = 0; | | 1278 | if (r->resrec.RecordType == kDNSRecordTypeDeregistering) r->AnnounceCount = 0; |
1281 | else break; | | 1279 | else break; |
1282 | } | | 1280 | } |
1283 | } | | 1281 | } |
1284 | | | 1282 | |
1285 | if (r) | | 1283 | if (r) |
1286 | { | | 1284 | { |
1287 | debugf("mDNS_Register_internal:Adding to duplicate list %s", ARDisplayString(m,rr)); | | 1285 | debugf("mDNS_Register_internal:Adding to duplicate list %s", ARDisplayString(m,rr)); |
1288 | *d = rr; | | 1286 | *d = rr; |
1289 | // If the previous copy of this record is already verified unique, | | 1287 | // If the previous copy of this record is already verified unique, |
1290 | // then indicate that we should move this record promptly to kDNSRecordTypeUnique state. | | 1288 | // then indicate that we should move this record promptly to kDNSRecordTypeUnique state. |
1291 | // Setting ProbeCount to zero will cause SendQueries() to advance this record to | | 1289 | // Setting ProbeCount to zero will cause SendQueries() to advance this record to |
1292 | // kDNSRecordTypeVerified state and call the client callback at the next appropriate time. | | 1290 | // kDNSRecordTypeVerified state and call the client callback at the next appropriate time. |
1293 | if (rr->resrec.RecordType == kDNSRecordTypeUnique && r->resrec.RecordType == kDNSRecordTypeVerified) | | 1291 | if (rr->resrec.RecordType == kDNSRecordTypeUnique && r->resrec.RecordType == kDNSRecordTypeVerified) |
1294 | rr->ProbeCount = 0; | | 1292 | rr->ProbeCount = 0; |
1295 | } | | 1293 | } |
1296 | else | | 1294 | else |
1297 | { | | 1295 | { |
1298 | debugf("mDNS_Register_internal: Adding to active record list %s", ARDisplayString(m,rr)); | | 1296 | debugf("mDNS_Register_internal: Adding to active record list %s", ARDisplayString(m,rr)); |
1299 | if (RRLocalOnly(rr)) | | 1297 | if (RRLocalOnly(rr)) |
1300 | { | | 1298 | { |
1301 | AuthGroup *ag; | | 1299 | AuthGroup *ag; |
1302 | ag = InsertAuthRecord(m, &m->rrauth, rr); | | 1300 | ag = InsertAuthRecord(m, &m->rrauth, rr); |
1303 | if (ag && !ag->NewLocalOnlyRecords) { | | 1301 | if (ag && !ag->NewLocalOnlyRecords) { |
1304 | m->NewLocalOnlyRecords = mDNStrue; | | 1302 | m->NewLocalOnlyRecords = mDNStrue; |
1305 | ag->NewLocalOnlyRecords = rr; | | 1303 | ag->NewLocalOnlyRecords = rr; |
1306 | } | | 1304 | } |
1307 | // No probing for LocalOnly records, Acknowledge them right away | | 1305 | // No probing for LocalOnly records, Acknowledge them right away |
1308 | if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified; | | 1306 | if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified; |
1309 | AcknowledgeRecord(m, rr); | | 1307 | AcknowledgeRecord(m, rr); |
1310 | return(mStatus_NoError); | | 1308 | return(mStatus_NoError); |
1311 | } | | 1309 | } |
1312 | else | | 1310 | else |
1313 | { | | 1311 | { |
1314 | if (!m->NewLocalRecords) m->NewLocalRecords = rr; | | 1312 | if (!m->NewLocalRecords) m->NewLocalRecords = rr; |
1315 | *p = rr; | | 1313 | *p = rr; |
1316 | } | | 1314 | } |
1317 | } | | 1315 | } |
1318 | | | 1316 | |
1319 | if (!AuthRecord_uDNS(rr)) // This check is superfluous, given that for unicast records we (currently) bail out above | | 1317 | if (!AuthRecord_uDNS(rr)) // This check is superfluous, given that for unicast records we (currently) bail out above |
1320 | { | | 1318 | { |
1321 | // For records that are not going to probe, acknowledge them right away | | 1319 | // For records that are not going to probe, acknowledge them right away |
1322 | if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering) | | 1320 | if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering) |
1323 | AcknowledgeRecord(m, rr); | | 1321 | AcknowledgeRecord(m, rr); |
1324 | | | 1322 | |
1325 | // Adding a record may affect whether or not we should sleep | | 1323 | // Adding a record may affect whether or not we should sleep |
1326 | mDNS_UpdateAllowSleep(m); | | 1324 | mDNS_UpdateAllowSleep(m); |
1327 | } | | 1325 | } |
1328 | | | 1326 | |
1329 | return(mStatus_NoError); | | 1327 | return(mStatus_NoError); |
1330 | } | | 1328 | } |
1331 | | | 1329 | |
1332 | mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr) | | 1330 | mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr) |
1333 | { | | 1331 | { |
1334 | m->ProbeFailTime = m->timenow; | | 1332 | m->ProbeFailTime = m->timenow; |
1335 | m->NumFailedProbes++; | | 1333 | m->NumFailedProbes++; |
1336 | // If we've had fifteen or more probe failures, rate-limit to one every five seconds. | | 1334 | // If we've had fifteen or more probe failures, rate-limit to one every five seconds. |
1337 | // If a bunch of hosts have all been configured with the same name, then they'll all | | 1335 | // If a bunch of hosts have all been configured with the same name, then they'll all |
1338 | // conflict and run through the same series of names: name-2, name-3, name-4, etc., | | 1336 | // conflict and run through the same series of names: name-2, name-3, name-4, etc., |
1339 | // up to name-10. After that they'll start adding random increments in the range 1-100, | | 1337 | // up to name-10. After that they'll start adding random increments in the range 1-100, |
1340 | // so they're more likely to branch out in the available namespace and settle on a set of | | 1338 | // so they're more likely to branch out in the available namespace and settle on a set of |
1341 | // unique names quickly. If after five more tries the host is still conflicting, then we | | 1339 | // unique names quickly. If after five more tries the host is still conflicting, then we |
1342 | // may have a serious problem, so we start rate-limiting so we don't melt down the network. | | 1340 | // may have a serious problem, so we start rate-limiting so we don't melt down the network. |
1343 | if (m->NumFailedProbes >= 15) | | 1341 | if (m->NumFailedProbes >= 15) |
1344 | { | | 1342 | { |
1345 | m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5); | | 1343 | m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5); |
1346 | LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect", | | 1344 | LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect", |
1347 | m->NumFailedProbes, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); | | 1345 | m->NumFailedProbes, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); |
1348 | } | | 1346 | } |
1349 | } | | 1347 | } |
1350 | | | 1348 | |
1351 | mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr) | | 1349 | mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr) |
1352 | { | | 1350 | { |
1353 | RData *OldRData = rr->resrec.rdata; | | 1351 | RData *OldRData = rr->resrec.rdata; |
1354 | mDNSu16 OldRDLen = rr->resrec.rdlength; | | 1352 | mDNSu16 OldRDLen = rr->resrec.rdlength; |
1355 | SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); // Update our rdata | | 1353 | SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); // Update our rdata |
1356 | rr->NewRData = mDNSNULL; // Clear the NewRData pointer ... | | 1354 | rr->NewRData = mDNSNULL; // Clear the NewRData pointer ... |
1357 | if (rr->UpdateCallback) | | 1355 | if (rr->UpdateCallback) |
1358 | rr->UpdateCallback(m, rr, OldRData, OldRDLen); // ... and let the client know | | 1356 | rr->UpdateCallback(m, rr, OldRData, OldRDLen); // ... and let the client know |
1359 | } | | 1357 | } |
1360 | | | 1358 | |
1361 | // Note: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list. | | 1359 | // Note: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list. |
1362 | // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. | | 1360 | // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. |
1363 | // Exported so uDNS.c can call this | | 1361 | // Exported so uDNS.c can call this |
1364 | mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt) | | 1362 | mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt) |
1365 | { | | 1363 | { |
1366 | AuthRecord *r2; | | 1364 | AuthRecord *r2; |
1367 | mDNSu8 RecordType = rr->resrec.RecordType; | | 1365 | mDNSu8 RecordType = rr->resrec.RecordType; |
1368 | AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records | | 1366 | AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records |
1369 | mDNSBool dupList = mDNSfalse; | | 1367 | mDNSBool dupList = mDNSfalse; |
1370 | | | 1368 | |
1371 | if (RRLocalOnly(rr)) | | 1369 | if (RRLocalOnly(rr)) |
1372 | { | | 1370 | { |
1373 | AuthGroup *a; | | 1371 | AuthGroup *a; |
1374 | AuthGroup **ag = &a; | | 1372 | AuthGroup **ag = &a; |
1375 | AuthRecord **rp; | | 1373 | AuthRecord **rp; |
1376 | const mDNSu32 slot = AuthHashSlot(rr->resrec.name); | | 1374 | const mDNSu32 slot = AuthHashSlot(rr->resrec.name); |
1377 | | | 1375 | |
1378 | a = AuthGroupForRecord(&m->rrauth, slot, &rr->resrec); | | 1376 | a = AuthGroupForRecord(&m->rrauth, slot, &rr->resrec); |
1379 | if (!a) return mDNSfalse; | | 1377 | if (!a) return mDNSfalse; |
1380 | rp = &(*ag)->members; | | 1378 | rp = &(*ag)->members; |
1381 | while (*rp && *rp != rr) rp=&(*rp)->next; | | 1379 | while (*rp && *rp != rr) rp=&(*rp)->next; |
1382 | p = rp; | | 1380 | p = rp; |
1383 | } | | 1381 | } |
1384 | else | | 1382 | else |
1385 | { | | 1383 | { |
1386 | while (*p && *p != rr) p=&(*p)->next; | | 1384 | while (*p && *p != rr) p=&(*p)->next; |
1387 | } | | 1385 | } |
1388 | | | 1386 | |
1389 | if (*p) | | 1387 | if (*p) |
1390 | { | | 1388 | { |
1391 | // We found our record on the main list. See if there are any duplicates that need special handling. | | 1389 | // We found our record on the main list. See if there are any duplicates that need special handling. |
1392 | if (drt == mDNS_Dereg_conflict) // If this was a conflict, see that all duplicates get the same treatment | | 1390 | if (drt == mDNS_Dereg_conflict) // If this was a conflict, see that all duplicates get the same treatment |
1393 | { | | 1391 | { |
1394 | // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished | | 1392 | // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished |
1395 | // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory. | | 1393 | // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory. |
1396 | for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF; | | 1394 | for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF; |
1397 | } | | 1395 | } |
1398 | else | | 1396 | else |
1399 | { | | 1397 | { |
1400 | // Before we delete the record (and potentially send a goodbye packet) | | 1398 | // Before we delete the record (and potentially send a goodbye packet) |
1401 | // first see if we have a record on the duplicate list ready to take over from it. | | 1399 | // first see if we have a record on the duplicate list ready to take over from it. |
1402 | AuthRecord **d = &m->DuplicateRecords; | | 1400 | AuthRecord **d = &m->DuplicateRecords; |
1403 | while (*d && !RecordIsLocalDuplicate(*d, rr)) d=&(*d)->next; | | 1401 | while (*d && !RecordIsLocalDuplicate(*d, rr)) d=&(*d)->next; |
1404 | if (*d) | | 1402 | if (*d) |
1405 | { | | 1403 | { |
1406 | AuthRecord *dup = *d; | | 1404 | AuthRecord *dup = *d; |
1407 | debugf("mDNS_Register_internal: Duplicate record %p taking over from %p %##s (%s)", | | 1405 | debugf("mDNS_Register_internal: Duplicate record %p taking over from %p %##s (%s)", |
1408 | dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); | | 1406 | dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); |
1409 | *d = dup->next; // Cut replacement record from DuplicateRecords list | | 1407 | *d = dup->next; // Cut replacement record from DuplicateRecords list |
1410 | if (RRLocalOnly(rr)) | | 1408 | if (RRLocalOnly(rr)) |
1411 | { | | 1409 | { |
1412 | dup->next = mDNSNULL; | | 1410 | dup->next = mDNSNULL; |
1413 | if (!InsertAuthRecord(m, &m->rrauth, dup)) LogMsg("mDNS_Deregister_internal: ERROR!! cannot insert %s", ARDisplayString(m, dup)); | | 1411 | if (!InsertAuthRecord(m, &m->rrauth, dup)) LogMsg("mDNS_Deregister_internal: ERROR!! cannot insert %s", ARDisplayString(m, dup)); |
1414 | } | | 1412 | } |
1415 | else | | 1413 | else |
1416 | { | | 1414 | { |
1417 | dup->next = rr->next; // And then... | | 1415 | dup->next = rr->next; // And then... |
1418 | rr->next = dup; // ... splice it in right after the record we're about to delete | | 1416 | rr->next = dup; // ... splice it in right after the record we're about to delete |
1419 | } | | 1417 | } |
1420 | dup->resrec.RecordType = rr->resrec.RecordType; | | 1418 | dup->resrec.RecordType = rr->resrec.RecordType; |
1421 | dup->ProbeCount = rr->ProbeCount; | | 1419 | dup->ProbeCount = rr->ProbeCount; |
1422 | dup->AnnounceCount = rr->AnnounceCount; | | 1420 | dup->AnnounceCount = rr->AnnounceCount; |
1423 | dup->RequireGoodbye = rr->RequireGoodbye; | | 1421 | dup->RequireGoodbye = rr->RequireGoodbye; |
1424 | dup->AnsweredLocalQ = rr->AnsweredLocalQ; | | 1422 | dup->AnsweredLocalQ = rr->AnsweredLocalQ; |
1425 | dup->ImmedAnswer = rr->ImmedAnswer; | | 1423 | dup->ImmedAnswer = rr->ImmedAnswer; |
1426 | dup->ImmedUnicast = rr->ImmedUnicast; | | 1424 | dup->ImmedUnicast = rr->ImmedUnicast; |
1427 | dup->ImmedAdditional = rr->ImmedAdditional; | | 1425 | dup->ImmedAdditional = rr->ImmedAdditional; |
1428 | dup->v4Requester = rr->v4Requester; | | 1426 | dup->v4Requester = rr->v4Requester; |
1429 | dup->v6Requester = rr->v6Requester; | | 1427 | dup->v6Requester = rr->v6Requester; |
1430 | dup->ThisAPInterval = rr->ThisAPInterval; | | 1428 | dup->ThisAPInterval = rr->ThisAPInterval; |
1431 | dup->LastAPTime = rr->LastAPTime; | | 1429 | dup->LastAPTime = rr->LastAPTime; |
1432 | dup->LastMCTime = rr->LastMCTime; | | 1430 | dup->LastMCTime = rr->LastMCTime; |
1433 | dup->LastMCInterface = rr->LastMCInterface; | | 1431 | dup->LastMCInterface = rr->LastMCInterface; |
1434 | dup->Private = rr->Private; | | 1432 | dup->Private = rr->Private; |
1435 | dup->state = rr->state; | | 1433 | dup->state = rr->state; |
1436 | rr->RequireGoodbye = mDNSfalse; | | 1434 | rr->RequireGoodbye = mDNSfalse; |
1437 | rr->AnsweredLocalQ = mDNSfalse; | | 1435 | rr->AnsweredLocalQ = mDNSfalse; |
1438 | } | | 1436 | } |
1439 | } | | 1437 | } |
1440 | } | | 1438 | } |
1441 | else | | 1439 | else |
1442 | { | | 1440 | { |
1443 | // We didn't find our record on the main list; try the DuplicateRecords list instead. | | 1441 | // We didn't find our record on the main list; try the DuplicateRecords list instead. |
1444 | p = &m->DuplicateRecords; | | 1442 | p = &m->DuplicateRecords; |
1445 | while (*p && *p != rr) p=&(*p)->next; | | 1443 | while (*p && *p != rr) p=&(*p)->next; |
1446 | // If we found our record on the duplicate list, then make sure we don't send a goodbye for it | | 1444 | // If we found our record on the duplicate list, then make sure we don't send a goodbye for it |
1447 | if (*p) { rr->RequireGoodbye = mDNSfalse; dupList = mDNStrue; } | | 1445 | if (*p) { rr->RequireGoodbye = mDNSfalse; dupList = mDNStrue; } |
1448 | if (*p) debugf("mDNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)", | | 1446 | if (*p) debugf("mDNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)", |
1449 | rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); | | 1447 | rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); |
1450 | } | | 1448 | } |
1451 | | | 1449 | |
1452 | if (!*p) | | 1450 | if (!*p) |
1453 | { | | 1451 | { |
1454 | // No need to log an error message if we already know this is a potentially repeated deregistration | | 1452 | // No need to log an error message if we already know this is a potentially repeated deregistration |
1455 | if (drt != mDNS_Dereg_repeat) | | 1453 | if (drt != mDNS_Dereg_repeat) |
1456 | LogMsg("mDNS_Deregister_internal: Record %p not found in list %s", rr, ARDisplayString(m,rr)); | | 1454 | LogMsg("mDNS_Deregister_internal: Record %p not found in list %s", rr, ARDisplayString(m,rr)); |
1457 | return(mStatus_BadReferenceErr); | | 1455 | return(mStatus_BadReferenceErr); |
1458 | } | | 1456 | } |
1459 | | | 1457 | |
1460 | // If this is a shared record and we've announced it at least once, | | 1458 | // If this is a shared record and we've announced it at least once, |
1461 | // we need to retract that announcement before we delete the record | | 1459 | // we need to retract that announcement before we delete the record |
1462 | | | 1460 | |
1463 | // If this is a record (including mDNSInterface_LocalOnly records) for which we've given local-only answers then | | 1461 | // If this is a record (including mDNSInterface_LocalOnly records) for which we've given local-only answers then |
1464 | // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse)" here, but that would not not be safe. | | 1462 | // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse)" here, but that would not not be safe. |
1465 | // The AnswerAllLocalQuestionsWithLocalAuthRecord routine walks the question list invoking client callbacks, using the "m->CurrentQuestion" | | 1463 | // The AnswerAllLocalQuestionsWithLocalAuthRecord routine walks the question list invoking client callbacks, using the "m->CurrentQuestion" |
1466 | // mechanism to cope with the client callback modifying the question list while that's happening. | | 1464 | // mechanism to cope with the client callback modifying the question list while that's happening. |
1467 | // However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain) | | 1465 | // However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain) |
1468 | // which means that the "m->CurrentQuestion" mechanism is already in use to protect that list, so we can't use it twice. | | 1466 | // which means that the "m->CurrentQuestion" mechanism is already in use to protect that list, so we can't use it twice. |
1469 | // More generally, if we invoke callbacks from within a client callback, then those callbacks could deregister other | | 1467 | // More generally, if we invoke callbacks from within a client callback, then those callbacks could deregister other |
1470 | // records, thereby invoking yet more callbacks, without limit. | | 1468 | // records, thereby invoking yet more callbacks, without limit. |
1471 | // The solution is to defer delivering the "Remove" events until mDNS_Execute time, just like we do for sending | | 1469 | // The solution is to defer delivering the "Remove" events until mDNS_Execute time, just like we do for sending |
1472 | // actual goodbye packets. | | 1470 | // actual goodbye packets. |
1473 | | | 1471 | |
1474 | #ifndef UNICAST_DISABLED | | 1472 | #ifndef UNICAST_DISABLED |
1475 | if (AuthRecord_uDNS(rr)) | | 1473 | if (AuthRecord_uDNS(rr)) |
1476 | { | | 1474 | { |
1477 | if (rr->RequireGoodbye) | | 1475 | if (rr->RequireGoodbye) |
1478 | { | | 1476 | { |
1479 | if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } | | 1477 | if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } |
1480 | rr->resrec.RecordType = kDNSRecordTypeDeregistering; | | 1478 | rr->resrec.RecordType = kDNSRecordTypeDeregistering; |
1481 | m->LocalRemoveEvents = mDNStrue; | | 1479 | m->LocalRemoveEvents = mDNStrue; |
1482 | uDNS_DeregisterRecord(m, rr); | | 1480 | uDNS_DeregisterRecord(m, rr); |
1483 | // At this point unconditionally we bail out | | 1481 | // At this point unconditionally we bail out |
1484 | // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration, | | 1482 | // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration, |
1485 | // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration | | 1483 | // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration |
1486 | // process and will complete asynchronously. Either way we don't need to do anything more here. | | 1484 | // process and will complete asynchronously. Either way we don't need to do anything more here. |
1487 | return(mStatus_NoError); | | 1485 | return(mStatus_NoError); |
1488 | } | | 1486 | } |
1489 | // Sometimes the records don't complete proper deregistration i.e., don't wait for a response | | 1487 | // Sometimes the records don't complete proper deregistration i.e., don't wait for a response |
1490 | // from the server. In that case, if the records have been part of a group update, clear the | | 1488 | // from the server. In that case, if the records have been part of a group update, clear the |
1491 | // state here. Some recors e.g., AutoTunnel gets reused without ever being completely initialized | | 1489 | // state here. Some recors e.g., AutoTunnel gets reused without ever being completely initialized |
1492 | rr->updateid = zeroID; | | 1490 | rr->updateid = zeroID; |
1493 | | | 1491 | |
1494 | // We defer cleaning up NAT state only after sending goodbyes. This is important because | | 1492 | // We defer cleaning up NAT state only after sending goodbyes. This is important because |
1495 | // RecordRegistrationGotZoneData guards against creating NAT state if clientContext is non-NULL. | | 1493 | // RecordRegistrationGotZoneData guards against creating NAT state if clientContext is non-NULL. |
1496 | // This happens today when we turn on/off interface where we get multiple network transitions | | 1494 | // This happens today when we turn on/off interface where we get multiple network transitions |
1497 | // and RestartRecordGetZoneData triggers re-registration of the resource records even though | | 1495 | // and RestartRecordGetZoneData triggers re-registration of the resource records even though |
1498 | // they may be in Registered state which causes NAT information to be setup multiple times. Defering | | 1496 | // they may be in Registered state which causes NAT information to be setup multiple times. Defering |
1499 | // the cleanup here keeps clientContext non-NULL and hence prevents that. Note that cleaning up | | 1497 | // the cleanup here keeps clientContext non-NULL and hence prevents that. Note that cleaning up |
1500 | // NAT state here takes care of the case where we did not send goodbyes at all. | | 1498 | // NAT state here takes care of the case where we did not send goodbyes at all. |
1501 | if (rr->NATinfo.clientContext) | | 1499 | if (rr->NATinfo.clientContext) |
1502 | { | | 1500 | { |
1503 | mDNS_StopNATOperation_internal(m, &rr->NATinfo); | | 1501 | mDNS_StopNATOperation_internal(m, &rr->NATinfo); |
1504 | rr->NATinfo.clientContext = mDNSNULL; | | 1502 | rr->NATinfo.clientContext = mDNSNULL; |
1505 | } | | 1503 | } |
1506 | if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; } | | 1504 | if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; } |
1507 | if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } | | 1505 | if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } |
1508 | } | | 1506 | } |
1509 | #endif // UNICAST_DISABLED | | 1507 | #endif // UNICAST_DISABLED |
1510 | | | 1508 | |
1511 | if (RecordType == kDNSRecordTypeUnregistered) | | 1509 | if (RecordType == kDNSRecordTypeUnregistered) |
1512 | LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m, rr)); | | 1510 | LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m, rr)); |
1513 | else if (RecordType == kDNSRecordTypeDeregistering) | | 1511 | else if (RecordType == kDNSRecordTypeDeregistering) |
1514 | { | | 1512 | { |
1515 | LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m, rr)); | | 1513 | LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m, rr)); |
1516 | return(mStatus_BadReferenceErr); | | 1514 | return(mStatus_BadReferenceErr); |
1517 | } | | 1515 | } |
1518 | | | 1516 | |
1519 | // <rdar://problem/7457925> Local-only questions don't get remove events for unique records | | 1517 | // <rdar://problem/7457925> Local-only questions don't get remove events for unique records |
1520 | // We may want to consider changing this code so that we generate local-only question "rmv" | | 1518 | // We may want to consider changing this code so that we generate local-only question "rmv" |
1521 | // events (and maybe goodbye packets too) for unique records as well as for shared records | | 1519 | // events (and maybe goodbye packets too) for unique records as well as for shared records |
1522 | // Note: If we change the logic for this "if" statement, need to ensure that the code in | | 1520 | // Note: If we change the logic for this "if" statement, need to ensure that the code in |
1523 | // CompleteDeregistration() sets the appropriate state variables to gaurantee that "else" | | 1521 | // CompleteDeregistration() sets the appropriate state variables to gaurantee that "else" |
1524 | // clause will execute here and the record will be cut from the list. | | 1522 | // clause will execute here and the record will be cut from the list. |
1525 | if (rr->WakeUp.HMAC.l[0] || | | 1523 | if (rr->WakeUp.HMAC.l[0] || |
1526 | (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ))) | | 1524 | (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ))) |
1527 | { | | 1525 | { |
1528 | verbosedebugf("mDNS_Deregister_internal: Starting deregistration for %s", ARDisplayString(m, rr)); | | 1526 | verbosedebugf("mDNS_Deregister_internal: Starting deregistration for %s", ARDisplayString(m, rr)); |
1529 | rr->resrec.RecordType = kDNSRecordTypeDeregistering; | | 1527 | rr->resrec.RecordType = kDNSRecordTypeDeregistering; |
1530 | rr->resrec.rroriginalttl = 0; | | 1528 | rr->resrec.rroriginalttl = 0; |
1531 | rr->AnnounceCount = rr->WakeUp.HMAC.l[0] ? WakeupCount : (drt == mDNS_Dereg_rapid) ? 1 : GoodbyeCount; | | 1529 | rr->AnnounceCount = rr->WakeUp.HMAC.l[0] ? WakeupCount : (drt == mDNS_Dereg_rapid) ? 1 : GoodbyeCount; |
1532 | rr->ThisAPInterval = mDNSPlatformOneSecond * 2; | | 1530 | rr->ThisAPInterval = mDNSPlatformOneSecond * 2; |
1533 | rr->LastAPTime = m->timenow - rr->ThisAPInterval; | | 1531 | rr->LastAPTime = m->timenow - rr->ThisAPInterval; |
1534 | m->LocalRemoveEvents = mDNStrue; | | 1532 | m->LocalRemoveEvents = mDNStrue; |
1535 | if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0) | | 1533 | if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0) |
1536 | m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10); | | 1534 | m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10); |
1537 | } | | 1535 | } |
1538 | else | | 1536 | else |
1539 | { | | 1537 | { |
1540 | if (!dupList && RRLocalOnly(rr)) | | 1538 | if (!dupList && RRLocalOnly(rr)) |
1541 | { | | 1539 | { |
1542 | AuthGroup *ag = RemoveAuthRecord(m, &m->rrauth, rr); | | 1540 | AuthGroup *ag = RemoveAuthRecord(m, &m->rrauth, rr); |
1543 | if (ag->NewLocalOnlyRecords == rr) ag->NewLocalOnlyRecords = rr->next; | | 1541 | if (ag->NewLocalOnlyRecords == rr) ag->NewLocalOnlyRecords = rr->next; |
1544 | } | | 1542 | } |
1545 | else | | 1543 | else |
1546 | { | | 1544 | { |
1547 | *p = rr->next; // Cut this record from the list | | 1545 | *p = rr->next; // Cut this record from the list |
1548 | if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next; | | 1546 | if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next; |
1549 | } | | 1547 | } |
1550 | // If someone is about to look at this, bump the pointer forward | | 1548 | // If someone is about to look at this, bump the pointer forward |
1551 | if (m->CurrentRecord == rr) m->CurrentRecord = rr->next; | | 1549 | if (m->CurrentRecord == rr) m->CurrentRecord = rr->next; |
1552 | rr->next = mDNSNULL; | | 1550 | rr->next = mDNSNULL; |
1553 | | | 1551 | |
1554 | // Should we generate local remove events here? | | 1552 | // Should we generate local remove events here? |
1555 | // i.e. something like: | | 1553 | // i.e. something like: |
1556 | // if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; } | | 1554 | // if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; } |
1557 | | | 1555 | |
1558 | verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr)); | | 1556 | verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr)); |
1559 | rr->resrec.RecordType = kDNSRecordTypeUnregistered; | | 1557 | rr->resrec.RecordType = kDNSRecordTypeUnregistered; |
1560 | | | 1558 | |
1561 | if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared) | | 1559 | if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared) |
1562 | debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)", | | 1560 | debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)", |
1563 | rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); | | 1561 | rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); |
1564 | | | 1562 | |
1565 | // If we have an update queued up which never executed, give the client a chance to free that memory | | 1563 | // If we have an update queued up which never executed, give the client a chance to free that memory |
1566 | if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client | | 1564 | if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client |
1567 | | | 1565 | |
1568 | | | 1566 | |
1569 | // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function | | 1567 | // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function |
1570 | // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. | | 1568 | // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. |
1571 | // In this case the likely client action to the mStatus_MemFree message is to free the memory, | | 1569 | // In this case the likely client action to the mStatus_MemFree message is to free the memory, |
1572 | // so any attempt to touch rr after this is likely to lead to a crash. | | 1570 | // so any attempt to touch rr after this is likely to lead to a crash. |
1573 | if (drt != mDNS_Dereg_conflict) | | 1571 | if (drt != mDNS_Dereg_conflict) |
1574 | { | | 1572 | { |
1575 | mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback | | 1573 | mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback |
1576 | LogInfo("mDNS_Deregister_internal: mStatus_MemFree for %s", ARDisplayString(m, rr)); | | 1574 | LogInfo("mDNS_Deregister_internal: mStatus_MemFree for %s", ARDisplayString(m, rr)); |
1577 | if (rr->RecordCallback) | | 1575 | if (rr->RecordCallback) |
1578 | rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this | | 1576 | rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this |
1579 | mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again | | 1577 | mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again |
1580 | } | | 1578 | } |
1581 | else | | 1579 | else |
1582 | { | | 1580 | { |
1583 | RecordProbeFailure(m, rr); | | 1581 | RecordProbeFailure(m, rr); |
1584 | mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback | | 1582 | mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback |
1585 | if (rr->RecordCallback) | | 1583 | if (rr->RecordCallback) |
1586 | rr->RecordCallback(m, rr, mStatus_NameConflict); // MUST NOT touch rr after this | | 1584 | rr->RecordCallback(m, rr, mStatus_NameConflict); // MUST NOT touch rr after this |
1587 | mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again | | 1585 | mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again |
1588 | // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously. | | 1586 | // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously. |
1589 | // Note that with all the client callbacks going on, by the time we get here all the | | 1587 | // Note that with all the client callbacks going on, by the time we get here all the |
1590 | // records we marked may have been explicitly deregistered by the client anyway. | | 1588 | // records we marked may have been explicitly deregistered by the client anyway. |
1591 | r2 = m->DuplicateRecords; | | 1589 | r2 = m->DuplicateRecords; |
1592 | while (r2) | | 1590 | while (r2) |
1593 | { | | 1591 | { |
1594 | if (r2->ProbeCount != 0xFF) r2 = r2->next; | | 1592 | if (r2->ProbeCount != 0xFF) r2 = r2->next; |
1595 | else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; } | | 1593 | else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; } |
1596 | } | | 1594 | } |
1597 | } | | 1595 | } |
1598 | } | | 1596 | } |
1599 | mDNS_UpdateAllowSleep(m); | | 1597 | mDNS_UpdateAllowSleep(m); |
1600 | return(mStatus_NoError); | | 1598 | return(mStatus_NoError); |
1601 | } | | 1599 | } |
1602 | | | 1600 | |
1603 | // *************************************************************************** | | 1601 | // *************************************************************************** |
1604 | #if COMPILER_LIKES_PRAGMA_MARK | | 1602 | #if COMPILER_LIKES_PRAGMA_MARK |
1605 | #pragma mark - | | 1603 | #pragma mark - |
1606 | #pragma mark - Packet Sending Functions | | 1604 | #pragma mark - Packet Sending Functions |
1607 | #endif | | 1605 | #endif |
1608 | | | 1606 | |
1609 | mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *add) | | 1607 | mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *add) |
1610 | { | | 1608 | { |
1611 | if (rr->NextResponse == mDNSNULL && *nrpp != &rr->NextResponse) | | 1609 | if (rr->NextResponse == mDNSNULL && *nrpp != &rr->NextResponse) |
1612 | { | | 1610 | { |
1613 | **nrpp = rr; | | 1611 | **nrpp = rr; |
1614 | // NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo) | | 1612 | // NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo) |
1615 | // If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does | | 1613 | // If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does |
1616 | // The referenced record will definitely be acceptable (by recursive application of this rule) | | 1614 | // The referenced record will definitely be acceptable (by recursive application of this rule) |
1617 | if (add && add->NR_AdditionalTo) add = add->NR_AdditionalTo; | | 1615 | if (add && add->NR_AdditionalTo) add = add->NR_AdditionalTo; |
1618 | rr->NR_AdditionalTo = add; | | 1616 | rr->NR_AdditionalTo = add; |
1619 | *nrpp = &rr->NextResponse; | | 1617 | *nrpp = &rr->NextResponse; |
1620 | } | | 1618 | } |
1621 | debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); | | 1619 | debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); |
1622 | } | | 1620 | } |
1623 | | | 1621 | |
1624 | mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID) | | 1622 | mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID) |
1625 | { | | 1623 | { |
1626 | AuthRecord *rr, *rr2; | | 1624 | AuthRecord *rr, *rr2; |
1627 | for (rr=ResponseRecords; rr; rr=rr->NextResponse) // For each record we plan to put | | 1625 | for (rr=ResponseRecords; rr; rr=rr->NextResponse) // For each record we plan to put |
1628 | { | | 1626 | { |
1629 | // (Note: This is an "if", not a "while". If we add a record, we'll find it again | | 1627 | // (Note: This is an "if", not a "while". If we add a record, we'll find it again |
1630 | // later in the "for" loop, and we will follow further "additional" links then.) | | 1628 | // later in the "for" loop, and we will follow further "additional" links then.) |
1631 | if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID)) | | 1629 | if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID)) |
1632 | AddRecordToResponseList(nrpp, rr->Additional1, rr); | | 1630 | AddRecordToResponseList(nrpp, rr->Additional1, rr); |
1633 | | | 1631 | |
1634 | if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID)) | | 1632 | if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID)) |
1635 | AddRecordToResponseList(nrpp, rr->Additional2, rr); | | 1633 | AddRecordToResponseList(nrpp, rr->Additional2, rr); |
1636 | | | 1634 | |
1637 | // For SRV records, automatically add the Address record(s) for the target host | | 1635 | // For SRV records, automatically add the Address record(s) for the target host |
1638 | if (rr->resrec.rrtype == kDNSType_SRV) | | 1636 | if (rr->resrec.rrtype == kDNSType_SRV) |
1639 | { | | 1637 | { |
1640 | for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records | | 1638 | for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records |
1641 | if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ... | | 1639 | if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ... |
1642 | ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ... | | 1640 | ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ... |
1643 | rr->resrec.rdatahash == rr2->resrec.namehash && // ... whose name is the name of the SRV target | | 1641 | rr->resrec.rdatahash == rr2->resrec.namehash && // ... whose name is the name of the SRV target |
1644 | SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name)) | | 1642 | SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name)) |
1645 | AddRecordToResponseList(nrpp, rr2, rr); | | 1643 | AddRecordToResponseList(nrpp, rr2, rr); |
1646 | } | | 1644 | } |
1647 | else if (RRTypeIsAddressType(rr->resrec.rrtype)) // For A or AAAA, put counterpart as additional | | 1645 | else if (RRTypeIsAddressType(rr->resrec.rrtype)) // For A or AAAA, put counterpart as additional |
1648 | { | | 1646 | { |
1649 | for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records | | 1647 | for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records |
1650 | if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ... | | 1648 | if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ... |
1651 | ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ... | | 1649 | ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ... |
1652 | rr->resrec.namehash == rr2->resrec.namehash && // ... and have the same name | | 1650 | rr->resrec.namehash == rr2->resrec.namehash && // ... and have the same name |
1653 | SameDomainName(rr->resrec.name, rr2->resrec.name)) | | 1651 | SameDomainName(rr->resrec.name, rr2->resrec.name)) |
1654 | AddRecordToResponseList(nrpp, rr2, rr); | | 1652 | AddRecordToResponseList(nrpp, rr2, rr); |
1655 | } | | 1653 | } |
1656 | else if (rr->resrec.rrtype == kDNSType_PTR) // For service PTR, see if we want to add DeviceInfo record | | 1654 | else if (rr->resrec.rrtype == kDNSType_PTR) // For service PTR, see if we want to add DeviceInfo record |
1657 | { | | 1655 | { |
1658 | if (ResourceRecordIsValidInterfaceAnswer(&m->DeviceInfo, InterfaceID) && | | 1656 | if (ResourceRecordIsValidInterfaceAnswer(&m->DeviceInfo, InterfaceID) && |
1659 | SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c)) | | 1657 | SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c)) |
1660 | AddRecordToResponseList(nrpp, &m->DeviceInfo, rr); | | 1658 | AddRecordToResponseList(nrpp, &m->DeviceInfo, rr); |
1661 | } | | 1659 | } |
1662 | } | | 1660 | } |
1663 | } | | 1661 | } |
1664 | | | 1662 | |
1665 | mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID) | | 1663 | mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID) |
1666 | { | | 1664 | { |
1667 | AuthRecord *rr; | | 1665 | AuthRecord *rr; |
1668 | AuthRecord *ResponseRecords = mDNSNULL; | | 1666 | AuthRecord *ResponseRecords = mDNSNULL; |
1669 | AuthRecord **nrp = &ResponseRecords; | | 1667 | AuthRecord **nrp = &ResponseRecords; |
1670 | NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); | | 1668 | NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); |
1671 | | | 1669 | |
1672 | // Make a list of all our records that need to be unicast to this destination | | 1670 | // Make a list of all our records that need to be unicast to this destination |
1673 | for (rr = m->ResourceRecords; rr; rr=rr->next) | | 1671 | for (rr = m->ResourceRecords; rr; rr=rr->next) |
1674 | { | | 1672 | { |
1675 | // If we find we can no longer unicast this answer, clear ImmedUnicast | | 1673 | // If we find we can no longer unicast this answer, clear ImmedUnicast |
1676 | if (rr->ImmedAnswer == mDNSInterfaceMark || | | 1674 | if (rr->ImmedAnswer == mDNSInterfaceMark || |
1677 | mDNSSameIPv4Address(rr->v4Requester, onesIPv4Addr) || | | 1675 | mDNSSameIPv4Address(rr->v4Requester, onesIPv4Addr) || |
1678 | mDNSSameIPv6Address(rr->v6Requester, onesIPv6Addr) ) | | 1676 | mDNSSameIPv6Address(rr->v6Requester, onesIPv6Addr) ) |
1679 | rr->ImmedUnicast = mDNSfalse; | | 1677 | rr->ImmedUnicast = mDNSfalse; |
1680 | | | 1678 | |
1681 | if (rr->ImmedUnicast && rr->ImmedAnswer == InterfaceID) | | 1679 | if (rr->ImmedUnicast && rr->ImmedAnswer == InterfaceID) |
1682 | { | | 1680 | { |
1683 | if ((dest->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->v4Requester, dest->ip.v4)) || | | 1681 | if ((dest->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->v4Requester, dest->ip.v4)) || |
1684 | (dest->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->v6Requester, dest->ip.v6))) | | 1682 | (dest->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->v6Requester, dest->ip.v6))) |
1685 | { | | 1683 | { |
1686 | rr->ImmedAnswer = mDNSNULL; // Clear the state fields | | 1684 | rr->ImmedAnswer = mDNSNULL; // Clear the state fields |
1687 | rr->ImmedUnicast = mDNSfalse; | | 1685 | rr->ImmedUnicast = mDNSfalse; |
1688 | rr->v4Requester = zerov4Addr; | | 1686 | rr->v4Requester = zerov4Addr; |
1689 | rr->v6Requester = zerov6Addr; | | 1687 | rr->v6Requester = zerov6Addr; |
1690 | | | 1688 | |
1691 | // Only sent records registered for P2P over P2P interfaces | | 1689 | // Only sent records registered for P2P over P2P interfaces |
1692 | if (intf && !mDNSPlatformValidRecordForInterface(rr, intf)) | | 1690 | if (intf && !mDNSPlatformValidRecordForInterface(rr, intf)) |
1693 | { | | 1691 | { |
1694 | LogInfo("SendDelayedUnicastResponse: Not sending %s, on %s", ARDisplayString(m, rr), InterfaceNameForID(m, InterfaceID)); | | 1692 | LogInfo("SendDelayedUnicastResponse: Not sending %s, on %s", ARDisplayString(m, rr), InterfaceNameForID(m, InterfaceID)); |
1695 | continue; | | 1693 | continue; |
1696 | } | | 1694 | } |
1697 | | | 1695 | |
1698 | if (rr->NextResponse == mDNSNULL && nrp != &rr->NextResponse) // rr->NR_AnswerTo | | 1696 | if (rr->NextResponse == mDNSNULL && nrp != &rr->NextResponse) // rr->NR_AnswerTo |
1699 | { rr->NR_AnswerTo = (mDNSu8*)~0; *nrp = rr; nrp = &rr->NextResponse; } | | 1697 | { rr->NR_AnswerTo = (mDNSu8*)~0; *nrp = rr; nrp = &rr->NextResponse; } |
1700 | } | | 1698 | } |
| @@ -3503,2008 +3501,2008 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRe | | | @@ -3503,2008 +3501,2008 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRe |
3503 | } | | 3501 | } |
3504 | | | 3502 | |
3505 | // CacheRecordAdd is only called from CreateNewCacheEntry, *never* directly as a result of a client API call. | | 3503 | // CacheRecordAdd is only called from CreateNewCacheEntry, *never* directly as a result of a client API call. |
3506 | // If new questions are created as a result of invoking client callbacks, they will be added to | | 3504 | // If new questions are created as a result of invoking client callbacks, they will be added to |
3507 | // the end of the question list, and m->NewQuestions will be set to indicate the first new question. | | 3505 | // the end of the question list, and m->NewQuestions will be set to indicate the first new question. |
3508 | // rr is a new CacheRecord just received into our cache | | 3506 | // rr is a new CacheRecord just received into our cache |
3509 | // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique). | | 3507 | // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique). |
3510 | // Note: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord which can call a user callback, | | 3508 | // Note: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord which can call a user callback, |
3511 | // which may change the record list and/or question list. | | 3509 | // which may change the record list and/or question list. |
3512 | // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. | | 3510 | // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. |
3513 | mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr) | | 3511 | mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr) |
3514 | { | | 3512 | { |
3515 | DNSQuestion *q; | | 3513 | DNSQuestion *q; |
3516 | | | 3514 | |
3517 | // We stop when we get to NewQuestions -- if we increment their CurrentAnswers/LargeAnswers/UniqueAnswers | | 3515 | // We stop when we get to NewQuestions -- if we increment their CurrentAnswers/LargeAnswers/UniqueAnswers |
3518 | // counters here we'll end up double-incrementing them when we do it again in AnswerNewQuestion(). | | 3516 | // counters here we'll end up double-incrementing them when we do it again in AnswerNewQuestion(). |
3519 | for (q = m->Questions; q && q != m->NewQuestions; q=q->next) | | 3517 | for (q = m->Questions; q && q != m->NewQuestions; q=q->next) |
3520 | { | | 3518 | { |
3521 | if (ResourceRecordAnswersQuestion(&rr->resrec, q)) | | 3519 | if (ResourceRecordAnswersQuestion(&rr->resrec, q)) |
3522 | { | | 3520 | { |
3523 | // If this question is one that's actively sending queries, and it's received ten answers within one | | 3521 | // If this question is one that's actively sending queries, and it's received ten answers within one |
3524 | // second of sending the last query packet, then that indicates some radical network topology change, | | 3522 | // second of sending the last query packet, then that indicates some radical network topology change, |
3525 | // so reset its exponential backoff back to the start. We must be at least at the eight-second interval | | 3523 | // so reset its exponential backoff back to the start. We must be at least at the eight-second interval |
3526 | // to do this. If we're at the four-second interval, or less, there's not much benefit accelerating | | 3524 | // to do this. If we're at the four-second interval, or less, there's not much benefit accelerating |
3527 | // because we will anyway send another query within a few seconds. The first reset query is sent out | | 3525 | // because we will anyway send another query within a few seconds. The first reset query is sent out |
3528 | // randomized over the next four seconds to reduce possible synchronization between machines. | | 3526 | // randomized over the next four seconds to reduce possible synchronization between machines. |
3529 | if (q->LastAnswerPktNum != m->PktNum) | | 3527 | if (q->LastAnswerPktNum != m->PktNum) |
3530 | { | | 3528 | { |
3531 | q->LastAnswerPktNum = m->PktNum; | | 3529 | q->LastAnswerPktNum = m->PktNum; |
3532 | if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 && | | 3530 | if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 && |
3533 | q->ThisQInterval > InitialQuestionInterval * QuestionIntervalStep3 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond) | | 3531 | q->ThisQInterval > InitialQuestionInterval * QuestionIntervalStep3 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond) |
3534 | { | | 3532 | { |
3535 | LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst (%d); restarting exponential backoff sequence (%d)", | | 3533 | LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst (%d); restarting exponential backoff sequence (%d)", |
3536 | q->qname.c, DNSTypeName(q->qtype), q->RecentAnswerPkts, q->ThisQInterval); | | 3534 | q->qname.c, DNSTypeName(q->qtype), q->RecentAnswerPkts, q->ThisQInterval); |
3537 | q->LastQTime = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4); | | 3535 | q->LastQTime = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4); |
3538 | q->ThisQInterval = InitialQuestionInterval; | | 3536 | q->ThisQInterval = InitialQuestionInterval; |
3539 | SetNextQueryTime(m,q); | | 3537 | SetNextQueryTime(m,q); |
3540 | } | | 3538 | } |
3541 | } | | 3539 | } |
3542 | verbosedebugf("CacheRecordAdd %p %##s (%s) %lu %#a:%d question %p", rr, rr->resrec.name->c, | | 3540 | verbosedebugf("CacheRecordAdd %p %##s (%s) %lu %#a:%d question %p", rr, rr->resrec.name->c, |
3543 | DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl, rr->resrec.rDNSServer ? | | 3541 | DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl, rr->resrec.rDNSServer ? |
3544 | &rr->resrec.rDNSServer->addr : mDNSNULL, mDNSVal16(rr->resrec.rDNSServer ? | | 3542 | &rr->resrec.rDNSServer->addr : mDNSNULL, mDNSVal16(rr->resrec.rDNSServer ? |
3545 | rr->resrec.rDNSServer->port : zeroIPPort), q); | | 3543 | rr->resrec.rDNSServer->port : zeroIPPort), q); |
3546 | q->CurrentAnswers++; | | 3544 | q->CurrentAnswers++; |
3547 | q->unansweredQueries = 0; | | 3545 | q->unansweredQueries = 0; |
3548 | if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++; | | 3546 | if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++; |
3549 | if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++; | | 3547 | if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++; |
3550 | if (q->CurrentAnswers > 4000) | | 3548 | if (q->CurrentAnswers > 4000) |
3551 | { | | 3549 | { |
3552 | static int msgcount = 0; | | 3550 | static int msgcount = 0; |
3553 | if (msgcount++ < 10) | | 3551 | if (msgcount++ < 10) |
3554 | LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack", | | 3552 | LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack", |
3555 | q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers); | | 3553 | q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers); |
3556 | rr->resrec.rroriginalttl = 0; | | 3554 | rr->resrec.rroriginalttl = 0; |
3557 | rr->UnansweredQueries = MaxUnansweredQueries; | | 3555 | rr->UnansweredQueries = MaxUnansweredQueries; |
3558 | } | | 3556 | } |
3559 | } | | 3557 | } |
3560 | } | | 3558 | } |
3561 | | | 3559 | |
3562 | if (!rr->DelayDelivery) | | 3560 | if (!rr->DelayDelivery) |
3563 | { | | 3561 | { |
3564 | if (m->CurrentQuestion) | | 3562 | if (m->CurrentQuestion) |
3565 | LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); | | 3563 | LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); |
3566 | m->CurrentQuestion = m->Questions; | | 3564 | m->CurrentQuestion = m->Questions; |
3567 | while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) | | 3565 | while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) |
3568 | { | | 3566 | { |
3569 | q = m->CurrentQuestion; | | 3567 | q = m->CurrentQuestion; |
3570 | if (ResourceRecordAnswersQuestion(&rr->resrec, q)) | | 3568 | if (ResourceRecordAnswersQuestion(&rr->resrec, q)) |
3571 | AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); | | 3569 | AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); |
3572 | if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now | | 3570 | if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now |
3573 | m->CurrentQuestion = q->next; | | 3571 | m->CurrentQuestion = q->next; |
3574 | } | | 3572 | } |
3575 | m->CurrentQuestion = mDNSNULL; | | 3573 | m->CurrentQuestion = mDNSNULL; |
3576 | } | | 3574 | } |
3577 | | | 3575 | |
3578 | SetNextCacheCheckTimeForRecord(m, rr); | | 3576 | SetNextCacheCheckTimeForRecord(m, rr); |
3579 | } | | 3577 | } |
3580 | | | 3578 | |
3581 | // NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call. | | 3579 | // NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call. |
3582 | // If new questions are created as a result of invoking client callbacks, they will be added to | | 3580 | // If new questions are created as a result of invoking client callbacks, they will be added to |
3583 | // the end of the question list, and m->NewQuestions will be set to indicate the first new question. | | 3581 | // the end of the question list, and m->NewQuestions will be set to indicate the first new question. |
3584 | // rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique) | | 3582 | // rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique) |
3585 | // but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any | | 3583 | // but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any |
3586 | // way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists, | | 3584 | // way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists, |
3587 | // so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network. | | 3585 | // so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network. |
3588 | // Note: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord which can call a user callback, | | 3586 | // Note: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord which can call a user callback, |
3589 | // which may change the record list and/or question list. | | 3587 | // which may change the record list and/or question list. |
3590 | // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. | | 3588 | // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. |
3591 | mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr) | | 3589 | mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr) |
3592 | { | | 3590 | { |
3593 | LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c); | | 3591 | LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c); |
3594 | if (m->CurrentQuestion) | | 3592 | if (m->CurrentQuestion) |
3595 | LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); | | 3593 | LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); |
3596 | m->CurrentQuestion = m->Questions; | | 3594 | m->CurrentQuestion = m->Questions; |
3597 | // We do this for *all* questions, not stopping when we get to m->NewQuestions, | | 3595 | // We do this for *all* questions, not stopping when we get to m->NewQuestions, |
3598 | // since we're not caching the record and we'll get no opportunity to do this later | | 3596 | // since we're not caching the record and we'll get no opportunity to do this later |
3599 | while (m->CurrentQuestion) | | 3597 | while (m->CurrentQuestion) |
3600 | { | | 3598 | { |
3601 | DNSQuestion *q = m->CurrentQuestion; | | 3599 | DNSQuestion *q = m->CurrentQuestion; |
3602 | if (ResourceRecordAnswersQuestion(&rr->resrec, q)) | | 3600 | if (ResourceRecordAnswersQuestion(&rr->resrec, q)) |
3603 | AnswerCurrentQuestionWithResourceRecord(m, rr, QC_addnocache); // QC_addnocache means "don't expect remove events for this" | | 3601 | AnswerCurrentQuestionWithResourceRecord(m, rr, QC_addnocache); // QC_addnocache means "don't expect remove events for this" |
3604 | if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now | | 3602 | if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now |
3605 | m->CurrentQuestion = q->next; | | 3603 | m->CurrentQuestion = q->next; |
3606 | } | | 3604 | } |
3607 | m->CurrentQuestion = mDNSNULL; | | 3605 | m->CurrentQuestion = mDNSNULL; |
3608 | } | | 3606 | } |
3609 | | | 3607 | |
3610 | // CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute. | | 3608 | // CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute. |
3611 | // Note that CacheRecordRmv is *only* called for records that are referenced by at least one active question. | | 3609 | // Note that CacheRecordRmv is *only* called for records that are referenced by at least one active question. |
3612 | // If new questions are created as a result of invoking client callbacks, they will be added to | | 3610 | // If new questions are created as a result of invoking client callbacks, they will be added to |
3613 | // the end of the question list, and m->NewQuestions will be set to indicate the first new question. | | 3611 | // the end of the question list, and m->NewQuestions will be set to indicate the first new question. |
3614 | // rr is an existing cache CacheRecord that just expired and is being deleted | | 3612 | // rr is an existing cache CacheRecord that just expired and is being deleted |
3615 | // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique). | | 3613 | // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique). |
3616 | // Note: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord which can call a user callback, | | 3614 | // Note: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord which can call a user callback, |
3617 | // which may change the record list and/or question list. | | 3615 | // which may change the record list and/or question list. |
3618 | // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. | | 3616 | // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. |
3619 | mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr) | | 3617 | mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr) |
3620 | { | | 3618 | { |
3621 | if (m->CurrentQuestion) | | 3619 | if (m->CurrentQuestion) |
3622 | LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)", | | 3620 | LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)", |
3623 | m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); | | 3621 | m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); |
3624 | m->CurrentQuestion = m->Questions; | | 3622 | m->CurrentQuestion = m->Questions; |
3625 | | | 3623 | |
3626 | // We stop when we get to NewQuestions -- for new questions their CurrentAnswers/LargeAnswers/UniqueAnswers counters | | 3624 | // We stop when we get to NewQuestions -- for new questions their CurrentAnswers/LargeAnswers/UniqueAnswers counters |
3627 | // will all still be zero because we haven't yet gone through the cache counting how many answers we have for them. | | 3625 | // will all still be zero because we haven't yet gone through the cache counting how many answers we have for them. |
3628 | while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) | | 3626 | while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) |
3629 | { | | 3627 | { |
3630 | DNSQuestion *q = m->CurrentQuestion; | | 3628 | DNSQuestion *q = m->CurrentQuestion; |
3631 | // When a question enters suppressed state, we generate RMV events and generate a negative | | 3629 | // When a question enters suppressed state, we generate RMV events and generate a negative |
3632 | // response. A cache may be present that answers this question e.g., cache entry generated | | 3630 | // response. A cache may be present that answers this question e.g., cache entry generated |
3633 | // before the question became suppressed. We need to skip the suppressed questions here as | | 3631 | // before the question became suppressed. We need to skip the suppressed questions here as |
3634 | // the RMV event has already been generated. | | 3632 | // the RMV event has already been generated. |
3635 | if (!QuerySuppressed(q) && ResourceRecordAnswersQuestion(&rr->resrec, q)) | | 3633 | if (!QuerySuppressed(q) && ResourceRecordAnswersQuestion(&rr->resrec, q)) |
3636 | { | | 3634 | { |
3637 | verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr)); | | 3635 | verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr)); |
3638 | q->FlappingInterface1 = mDNSNULL; | | 3636 | q->FlappingInterface1 = mDNSNULL; |
3639 | q->FlappingInterface2 = mDNSNULL; | | 3637 | q->FlappingInterface2 = mDNSNULL; |
3640 | | | 3638 | |
3641 | // When a question changes DNS server, it is marked with deliverAddEvents if we find any | | 3639 | // When a question changes DNS server, it is marked with deliverAddEvents if we find any |
3642 | // cache entry corresponding to the new DNS server. Before we deliver the ADD event, the | | 3640 | // cache entry corresponding to the new DNS server. Before we deliver the ADD event, the |
3643 | // cache entry may be removed in which case CurrentAnswers can be zero. | | 3641 | // cache entry may be removed in which case CurrentAnswers can be zero. |
3644 | if (q->deliverAddEvents && !q->CurrentAnswers) | | 3642 | if (q->deliverAddEvents && !q->CurrentAnswers) |
3645 | { | | 3643 | { |
3646 | LogInfo("CacheRecordRmv: Question %p %##s (%s) deliverAddEvents set, DNSServer %#a:%d", | | 3644 | LogInfo("CacheRecordRmv: Question %p %##s (%s) deliverAddEvents set, DNSServer %#a:%d", |
3647 | q, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, | | 3645 | q, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, |
3648 | mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort)); | | 3646 | mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort)); |
3649 | m->CurrentQuestion = q->next; | | 3647 | m->CurrentQuestion = q->next; |
3650 | continue; | | 3648 | continue; |
3651 | } | | 3649 | } |
3652 | if (q->CurrentAnswers == 0) | | 3650 | if (q->CurrentAnswers == 0) |
3653 | LogMsg("CacheRecordRmv ERROR!!: How can CurrentAnswers already be zero for %p %##s (%s) DNSServer %#a:%d", | | 3651 | LogMsg("CacheRecordRmv ERROR!!: How can CurrentAnswers already be zero for %p %##s (%s) DNSServer %#a:%d", |
3654 | q, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, | | 3652 | q, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, |
3655 | mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort)); | | 3653 | mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort)); |
3656 | else | | 3654 | else |
3657 | { | | 3655 | { |
3658 | q->CurrentAnswers--; | | 3656 | q->CurrentAnswers--; |
3659 | if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--; | | 3657 | if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--; |
3660 | if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--; | | 3658 | if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--; |
3661 | } | | 3659 | } |
3662 | if (rr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results | | 3660 | if (rr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results |
3663 | { | | 3661 | { |
3664 | if (q->CurrentAnswers == 0) | | 3662 | if (q->CurrentAnswers == 0) |
3665 | { | | 3663 | { |
3666 | LogInfo("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents", | | 3664 | LogInfo("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents", |
3667 | q->qname.c, DNSTypeName(q->qtype)); | | 3665 | q->qname.c, DNSTypeName(q->qtype)); |
3668 | ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0); | | 3666 | ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0); |
3669 | } | | 3667 | } |
3670 | AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv); | | 3668 | AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv); |
3671 | } | | 3669 | } |
3672 | } | | 3670 | } |
3673 | if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now | | 3671 | if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now |
3674 | m->CurrentQuestion = q->next; | | 3672 | m->CurrentQuestion = q->next; |
3675 | } | | 3673 | } |
3676 | m->CurrentQuestion = mDNSNULL; | | 3674 | m->CurrentQuestion = mDNSNULL; |
3677 | } | | 3675 | } |
3678 | | | 3676 | |
3679 | mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e) | | 3677 | mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e) |
3680 | { | | 3678 | { |
3681 | #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1 | | 3679 | #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1 |
3682 | unsigned int i; | | 3680 | unsigned int i; |
3683 | for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF; | | 3681 | for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF; |
3684 | #endif | | 3682 | #endif |
3685 | e->next = m->rrcache_free; | | 3683 | e->next = m->rrcache_free; |
3686 | m->rrcache_free = e; | | 3684 | m->rrcache_free = e; |
3687 | m->rrcache_totalused--; | | 3685 | m->rrcache_totalused--; |
3688 | } | | 3686 | } |
3689 | | | 3687 | |
3690 | mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp) | | 3688 | mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp) |
3691 | { | | 3689 | { |
3692 | CacheEntity *e = (CacheEntity *)(*cp); | | 3690 | CacheEntity *e = (CacheEntity *)(*cp); |
3693 | //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c); | | 3691 | //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c); |
3694 | if ((*cp)->rrcache_tail != &(*cp)->members) | | 3692 | if ((*cp)->rrcache_tail != &(*cp)->members) |
3695 | LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)"); | | 3693 | LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)"); |
3696 | //if ((*cp)->name != (domainname*)((*cp)->namestorage)) | | 3694 | //if ((*cp)->name != (domainname*)((*cp)->namestorage)) |
3697 | // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage)); | | 3695 | // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage)); |
3698 | if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name); | | 3696 | if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name); |
3699 | (*cp)->name = mDNSNULL; | | 3697 | (*cp)->name = mDNSNULL; |
3700 | *cp = (*cp)->next; // Cut record from list | | 3698 | *cp = (*cp)->next; // Cut record from list |
3701 | ReleaseCacheEntity(m, e); | | 3699 | ReleaseCacheEntity(m, e); |
3702 | } | | 3700 | } |
3703 | | | 3701 | |
3704 | mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r) | | 3702 | mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r) |
3705 | { | | 3703 | { |
3706 | //LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r)); | | 3704 | //LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r)); |
3707 | if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->smallrdatastorage) mDNSPlatformMemFree(r->resrec.rdata); | | 3705 | if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->smallrdatastorage) mDNSPlatformMemFree(r->resrec.rdata); |
3708 | r->resrec.rdata = mDNSNULL; | | 3706 | r->resrec.rdata = mDNSNULL; |
3709 | ReleaseCacheEntity(m, (CacheEntity *)r); | | 3707 | ReleaseCacheEntity(m, (CacheEntity *)r); |
3710 | } | | 3708 | } |
3711 | | | 3709 | |
3712 | // Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering | | 3710 | // Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering |
3713 | // CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all | | 3711 | // CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all |
3714 | // callbacks for old records are delivered before callbacks for newer records. | | 3712 | // callbacks for old records are delivered before callbacks for newer records. |
3715 | mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGroup *const cg) | | 3713 | mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGroup *const cg) |
3716 | { | | 3714 | { |
3717 | CacheRecord **rp = &cg->members; | | 3715 | CacheRecord **rp = &cg->members; |
3718 | | | 3716 | |
3719 | if (m->lock_rrcache) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; } | | 3717 | if (m->lock_rrcache) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; } |
3720 | m->lock_rrcache = 1; | | 3718 | m->lock_rrcache = 1; |
3721 | | | 3719 | |
3722 | while (*rp) | | 3720 | while (*rp) |
3723 | { | | 3721 | { |
3724 | CacheRecord *const rr = *rp; | | 3722 | CacheRecord *const rr = *rp; |
3725 | mDNSs32 event = RRExpireTime(rr); | | 3723 | mDNSs32 event = RRExpireTime(rr); |
3726 | if (m->timenow - event >= 0) // If expired, delete it | | 3724 | if (m->timenow - event >= 0) // If expired, delete it |
3727 | { | | 3725 | { |
3728 | *rp = rr->next; // Cut it from the list | | 3726 | *rp = rr->next; // Cut it from the list |
3729 | verbosedebugf("CheckCacheExpiration: Deleting%7d %7d %p %s", | | 3727 | verbosedebugf("CheckCacheExpiration: Deleting%7d %7d %p %s", |
3730 | m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr)); | | 3728 | m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr)); |
3731 | if (rr->CRActiveQuestion) // If this record has one or more active questions, tell them it's going away | | 3729 | if (rr->CRActiveQuestion) // If this record has one or more active questions, tell them it's going away |
3732 | { | | 3730 | { |
3733 | DNSQuestion *q = rr->CRActiveQuestion; | | 3731 | DNSQuestion *q = rr->CRActiveQuestion; |
3734 | // When a cache record is about to expire, we expect to do four queries at 80-82%, 85-87%, 90-92% and | | 3732 | // When a cache record is about to expire, we expect to do four queries at 80-82%, 85-87%, 90-92% and |
3735 | // then 95-97% of the TTL. If the DNS server does not respond, then we will remove the cache entry | | 3733 | // then 95-97% of the TTL. If the DNS server does not respond, then we will remove the cache entry |
3736 | // before we pick a new DNS server. As the question interval is set to MaxQuestionInterval, we may | | 3734 | // before we pick a new DNS server. As the question interval is set to MaxQuestionInterval, we may |
3737 | // not send out a query anytime soon. Hence, we need to reset the question interval. If this is | | 3735 | // not send out a query anytime soon. Hence, we need to reset the question interval. If this is |
3738 | // a normal deferred ADD case, then AnswerCurrentQuestionWithResourceRecord will reset it to | | 3736 | // a normal deferred ADD case, then AnswerCurrentQuestionWithResourceRecord will reset it to |
3739 | // MaxQuestionInterval. If we have inactive questions referring to negative cache entries, | | 3737 | // MaxQuestionInterval. If we have inactive questions referring to negative cache entries, |
3740 | // don't ressurect them as they will deliver duplicate "No such Record" ADD events | | 3738 | // don't ressurect them as they will deliver duplicate "No such Record" ADD events |
3741 | if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && ActiveQuestion(q)) | | 3739 | if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && ActiveQuestion(q)) |
3742 | { | | 3740 | { |
3743 | q->ThisQInterval = InitialQuestionInterval; | | 3741 | q->ThisQInterval = InitialQuestionInterval; |
3744 | q->LastQTime = m->timenow - q->ThisQInterval; | | 3742 | q->LastQTime = m->timenow - q->ThisQInterval; |
3745 | SetNextQueryTime(m, q); | | 3743 | SetNextQueryTime(m, q); |
3746 | } | | 3744 | } |
3747 | CacheRecordRmv(m, rr); | | 3745 | CacheRecordRmv(m, rr); |
3748 | m->rrcache_active--; | | 3746 | m->rrcache_active--; |
3749 | } | | 3747 | } |
3750 | ReleaseCacheRecord(m, rr); | | 3748 | ReleaseCacheRecord(m, rr); |
3751 | } | | 3749 | } |
3752 | else // else, not expired; see if we need to query | | 3750 | else // else, not expired; see if we need to query |
3753 | { | | 3751 | { |
3754 | // If waiting to delay delivery, do nothing until then | | 3752 | // If waiting to delay delivery, do nothing until then |
3755 | if (rr->DelayDelivery && rr->DelayDelivery - m->timenow > 0) | | 3753 | if (rr->DelayDelivery && rr->DelayDelivery - m->timenow > 0) |
3756 | event = rr->DelayDelivery; | | 3754 | event = rr->DelayDelivery; |
3757 | else | | 3755 | else |
3758 | { | | 3756 | { |
3759 | if (rr->DelayDelivery) CacheRecordDeferredAdd(m, rr); | | 3757 | if (rr->DelayDelivery) CacheRecordDeferredAdd(m, rr); |
3760 | if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries) | | 3758 | if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries) |
3761 | { | | 3759 | { |
3762 | if (m->timenow - rr->NextRequiredQuery < 0) // If not yet time for next query | | 3760 | if (m->timenow - rr->NextRequiredQuery < 0) // If not yet time for next query |
3763 | event = NextCacheCheckEvent(rr); // then just record when we want the next query | | 3761 | event = NextCacheCheckEvent(rr); // then just record when we want the next query |
3764 | else // else trigger our question to go out now | | 3762 | else // else trigger our question to go out now |
3765 | { | | 3763 | { |
3766 | // Set NextScheduledQuery to timenow so that SendQueries() will run. | | 3764 | // Set NextScheduledQuery to timenow so that SendQueries() will run. |
3767 | // SendQueries() will see that we have records close to expiration, and send FEQs for them. | | 3765 | // SendQueries() will see that we have records close to expiration, and send FEQs for them. |
3768 | m->NextScheduledQuery = m->timenow; | | 3766 | m->NextScheduledQuery = m->timenow; |
3769 | // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTimeForRecord(), | | 3767 | // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTimeForRecord(), |
3770 | // which will correctly update m->NextCacheCheck for us. | | 3768 | // which will correctly update m->NextCacheCheck for us. |
3771 | event = m->timenow + 0x3FFFFFFF; | | 3769 | event = m->timenow + 0x3FFFFFFF; |
3772 | } | | 3770 | } |
3773 | } | | 3771 | } |
3774 | } | | 3772 | } |
3775 | verbosedebugf("CheckCacheExpiration:%6d %5d %s", | | 3773 | verbosedebugf("CheckCacheExpiration:%6d %5d %s", |
3776 | (event - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr)); | | 3774 | (event - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr)); |
3777 | if (m->rrcache_nextcheck[slot] - event > 0) | | 3775 | if (m->rrcache_nextcheck[slot] - event > 0) |
3778 | m->rrcache_nextcheck[slot] = event; | | 3776 | m->rrcache_nextcheck[slot] = event; |
3779 | rp = &rr->next; | | 3777 | rp = &rr->next; |
3780 | } | | 3778 | } |
3781 | } | | 3779 | } |
3782 | if (cg->rrcache_tail != rp) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg->rrcache_tail, rp); | | 3780 | if (cg->rrcache_tail != rp) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg->rrcache_tail, rp); |
3783 | cg->rrcache_tail = rp; | | 3781 | cg->rrcache_tail = rp; |
3784 | m->lock_rrcache = 0; | | 3782 | m->lock_rrcache = 0; |
3785 | } | | 3783 | } |
3786 | | | 3784 | |
3787 | mDNSlocal void AnswerNewQuestion(mDNS *const m) | | 3785 | mDNSlocal void AnswerNewQuestion(mDNS *const m) |
3788 | { | | 3786 | { |
3789 | mDNSBool ShouldQueryImmediately = mDNStrue; | | 3787 | mDNSBool ShouldQueryImmediately = mDNStrue; |
3790 | DNSQuestion *const q = m->NewQuestions; // Grab the question we're going to answer | | 3788 | DNSQuestion *const q = m->NewQuestions; // Grab the question we're going to answer |
3791 | mDNSu32 slot = HashSlot(&q->qname); | | 3789 | mDNSu32 slot = HashSlot(&q->qname); |
3792 | CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); | | 3790 | CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); |
3793 | AuthRecord *lr; | | 3791 | AuthRecord *lr; |
3794 | AuthGroup *ag; | | 3792 | AuthGroup *ag; |
3795 | mDNSBool AnsweredFromCache = mDNSfalse; | | 3793 | mDNSBool AnsweredFromCache = mDNSfalse; |
3796 | | | 3794 | |
3797 | verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); | | 3795 | verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); |
3798 | | | 3796 | |
3799 | if (cg) CheckCacheExpiration(m, slot, cg); | | 3797 | if (cg) CheckCacheExpiration(m, slot, cg); |
3800 | if (m->NewQuestions != q) { LogInfo("AnswerNewQuestion: Question deleted while doing CheckCacheExpiration"); goto exit; } | | 3798 | if (m->NewQuestions != q) { LogInfo("AnswerNewQuestion: Question deleted while doing CheckCacheExpiration"); goto exit; } |
3801 | m->NewQuestions = q->next; | | 3799 | m->NewQuestions = q->next; |
3802 | // Advance NewQuestions to the next *after* calling CheckCacheExpiration, because if we advance it first | | 3800 | // Advance NewQuestions to the next *after* calling CheckCacheExpiration, because if we advance it first |
3803 | // then CheckCacheExpiration may give this question add/remove callbacks, and it's not yet ready for that. | | 3801 | // then CheckCacheExpiration may give this question add/remove callbacks, and it's not yet ready for that. |
3804 | // | | 3802 | // |
3805 | // Also, CheckCacheExpiration() calls CacheRecordDeferredAdd() and CacheRecordRmv(), which invoke | | 3803 | // Also, CheckCacheExpiration() calls CacheRecordDeferredAdd() and CacheRecordRmv(), which invoke |
3806 | // client callbacks, which may delete their own or any other question. Our mechanism for detecting | | 3804 | // client callbacks, which may delete their own or any other question. Our mechanism for detecting |
3807 | // whether our current m->NewQuestions question got deleted by one of these callbacks is to store the | | 3805 | // whether our current m->NewQuestions question got deleted by one of these callbacks is to store the |
3808 | // value of m->NewQuestions in 'q' before calling CheckCacheExpiration(), and then verify afterwards | | 3806 | // value of m->NewQuestions in 'q' before calling CheckCacheExpiration(), and then verify afterwards |
3809 | // that they're still the same. If m->NewQuestions has changed (because mDNS_StopQuery_internal | | 3807 | // that they're still the same. If m->NewQuestions has changed (because mDNS_StopQuery_internal |
3810 | // advanced it), that means the question was deleted, so we no longer need to worry about answering | | 3808 | // advanced it), that means the question was deleted, so we no longer need to worry about answering |
3811 | // it (and indeed 'q' is now a dangling pointer, so dereferencing it at all would be bad, and the | | 3809 | // it (and indeed 'q' is now a dangling pointer, so dereferencing it at all would be bad, and the |
3812 | // values we computed for slot and cg are now stale and relate to a question that no longer exists). | | 3810 | // values we computed for slot and cg are now stale and relate to a question that no longer exists). |
3813 | // | | 3811 | // |
3814 | // We can't use the usual m->CurrentQuestion mechanism for this because CacheRecordDeferredAdd() and | | 3812 | // We can't use the usual m->CurrentQuestion mechanism for this because CacheRecordDeferredAdd() and |
3815 | // CacheRecordRmv() both use that themselves when walking the list of (non-new) questions generating callbacks. | | 3813 | // CacheRecordRmv() both use that themselves when walking the list of (non-new) questions generating callbacks. |
3816 | // Fortunately mDNS_StopQuery_internal auto-advances both m->CurrentQuestion *AND* m->NewQuestions when | | 3814 | // Fortunately mDNS_StopQuery_internal auto-advances both m->CurrentQuestion *AND* m->NewQuestions when |
3817 | // deleting a question, so luckily we have an easy alternative way of detecting if our question got deleted. | | 3815 | // deleting a question, so luckily we have an easy alternative way of detecting if our question got deleted. |
3818 | | | 3816 | |
3819 | if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!"); | | 3817 | if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!"); |
3820 | // This should be safe, because calling the client's question callback may cause the | | 3818 | // This should be safe, because calling the client's question callback may cause the |
3821 | // question list to be modified, but should not ever cause the rrcache list to be modified. | | 3819 | // question list to be modified, but should not ever cause the rrcache list to be modified. |
3822 | // If the client's question callback deletes the question, then m->CurrentQuestion will | | 3820 | // If the client's question callback deletes the question, then m->CurrentQuestion will |
3823 | // be advanced, and we'll exit out of the loop | | 3821 | // be advanced, and we'll exit out of the loop |
3824 | m->lock_rrcache = 1; | | 3822 | m->lock_rrcache = 1; |
3825 | if (m->CurrentQuestion) | | 3823 | if (m->CurrentQuestion) |
3826 | LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)", | | 3824 | LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)", |
3827 | m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); | | 3825 | m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); |
3828 | m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted | | 3826 | m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted |
3829 | | | 3827 | |
3830 | if (q->NoAnswer == NoAnswer_Fail) | | 3828 | if (q->NoAnswer == NoAnswer_Fail) |
3831 | { | | 3829 | { |
3832 | LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); | | 3830 | LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); |
3833 | MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, q->qDNSServer); | | 3831 | MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, q->qDNSServer); |
3834 | q->NoAnswer = NoAnswer_Normal; // Temporarily turn off answer suppression | | 3832 | q->NoAnswer = NoAnswer_Normal; // Temporarily turn off answer suppression |
3835 | AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache); | | 3833 | AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache); |
3836 | // Don't touch the question if it has been stopped already | | 3834 | // Don't touch the question if it has been stopped already |
3837 | if (m->CurrentQuestion == q) q->NoAnswer = NoAnswer_Fail; // Restore NoAnswer state | | 3835 | if (m->CurrentQuestion == q) q->NoAnswer = NoAnswer_Fail; // Restore NoAnswer state |
3838 | m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it | | 3836 | m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it |
3839 | } | | 3837 | } |
3840 | if (m->CurrentQuestion != q) { LogInfo("AnswerNewQuestion: Question deleted while generating NoAnswer_Fail response"); goto exit; } | | 3838 | if (m->CurrentQuestion != q) { LogInfo("AnswerNewQuestion: Question deleted while generating NoAnswer_Fail response"); goto exit; } |
3841 | | | 3839 | |
3842 | // See if we want to tell it about LocalOnly records | | 3840 | // See if we want to tell it about LocalOnly records |
3843 | if (m->CurrentRecord) | | 3841 | if (m->CurrentRecord) |
3844 | LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); | | 3842 | LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); |
3845 | slot = AuthHashSlot(&q->qname); | | 3843 | slot = AuthHashSlot(&q->qname); |
3846 | ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname); | | 3844 | ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname); |
3847 | if (ag) | | 3845 | if (ag) |
3848 | { | | 3846 | { |
3849 | m->CurrentRecord = ag->members; | | 3847 | m->CurrentRecord = ag->members; |
3850 | while (m->CurrentRecord && m->CurrentRecord != ag->NewLocalOnlyRecords) | | 3848 | while (m->CurrentRecord && m->CurrentRecord != ag->NewLocalOnlyRecords) |
3851 | { | | 3849 | { |
3852 | AuthRecord *rr = m->CurrentRecord; | | 3850 | AuthRecord *rr = m->CurrentRecord; |
3853 | m->CurrentRecord = rr->next; | | 3851 | m->CurrentRecord = rr->next; |
3854 | // | | 3852 | // |
3855 | // If the question is mDNSInterface_LocalOnly, all records local to the machine should be used | | 3853 | // If the question is mDNSInterface_LocalOnly, all records local to the machine should be used |
3856 | // to answer the query. This is handled in AnswerNewLocalOnlyQuestion. | | 3854 | // to answer the query. This is handled in AnswerNewLocalOnlyQuestion. |
3857 | // | | 3855 | // |
3858 | // We handle mDNSInterface_Any and scoped questions here. See LocalOnlyRecordAnswersQuestion for more | | 3856 | // We handle mDNSInterface_Any and scoped questions here. See LocalOnlyRecordAnswersQuestion for more |
3859 | // details on how we handle this case. For P2P we just handle "Interface_Any" questions. For LocalOnly | | 3857 | // details on how we handle this case. For P2P we just handle "Interface_Any" questions. For LocalOnly |
3860 | // we handle both mDNSInterface_Any and scoped questions. | | 3858 | // we handle both mDNSInterface_Any and scoped questions. |
3861 | | | 3859 | |
3862 | if (rr->ARType == AuthRecordLocalOnly || (rr->ARType == AuthRecordP2P && q->InterfaceID == mDNSInterface_Any)) | | 3860 | if (rr->ARType == AuthRecordLocalOnly || (rr->ARType == AuthRecordP2P && q->InterfaceID == mDNSInterface_Any)) |
3863 | if (LocalOnlyRecordAnswersQuestion(rr, q)) | | 3861 | if (LocalOnlyRecordAnswersQuestion(rr, q)) |
3864 | { | | 3862 | { |
3865 | AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue); | | 3863 | AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue); |
3866 | if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here | | 3864 | if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here |
3867 | } | | 3865 | } |
3868 | } | | 3866 | } |
3869 | } | | 3867 | } |
3870 | m->CurrentRecord = mDNSNULL; | | 3868 | m->CurrentRecord = mDNSNULL; |
3871 | | | 3869 | |
3872 | if (m->CurrentQuestion != q) { LogInfo("AnswerNewQuestion: Question deleted while while giving LocalOnly record answers"); goto exit; } | | 3870 | if (m->CurrentQuestion != q) { LogInfo("AnswerNewQuestion: Question deleted while while giving LocalOnly record answers"); goto exit; } |
3873 | | | 3871 | |
3874 | if (q->LOAddressAnswers) | | 3872 | if (q->LOAddressAnswers) |
3875 | { | | 3873 | { |
3876 | LogInfo("AnswerNewQuestion: Question %p %##s (%s) answered using local auth records LOAddressAnswers %d", | | 3874 | LogInfo("AnswerNewQuestion: Question %p %##s (%s) answered using local auth records LOAddressAnswers %d", |
3877 | q, q->qname.c, DNSTypeName(q->qtype), q->LOAddressAnswers); | | 3875 | q, q->qname.c, DNSTypeName(q->qtype), q->LOAddressAnswers); |
3878 | goto exit; | | 3876 | goto exit; |
3879 | } | | 3877 | } |
3880 | | | 3878 | |
3881 | // Before we go check the cache and ship this query on the wire, we have to be sure that there are | | 3879 | // Before we go check the cache and ship this query on the wire, we have to be sure that there are |
3882 | // no local records that could possibly answer this question. As we did not check the NewLocalRecords, we | | 3880 | // no local records that could possibly answer this question. As we did not check the NewLocalRecords, we |
3883 | // need to just peek at them to see whether it will answer this question. If it would answer, pretend | | 3881 | // need to just peek at them to see whether it will answer this question. If it would answer, pretend |
3884 | // that we answered. AnswerAllLocalQuestionsWithLocalAuthRecord will answer shortly. This happens normally | | 3882 | // that we answered. AnswerAllLocalQuestionsWithLocalAuthRecord will answer shortly. This happens normally |
3885 | // when we add new /etc/hosts entries and restart the question. It is a new question and also a new record. | | 3883 | // when we add new /etc/hosts entries and restart the question. It is a new question and also a new record. |
3886 | if (ag) | | 3884 | if (ag) |
3887 | { | | 3885 | { |
3888 | lr = ag->NewLocalOnlyRecords; | | 3886 | lr = ag->NewLocalOnlyRecords; |
3889 | while (lr) | | 3887 | while (lr) |
3890 | { | | 3888 | { |
3891 | if (LORecordAnswersAddressType(lr) && LocalOnlyRecordAnswersQuestion(lr, q)) | | 3889 | if (LORecordAnswersAddressType(lr) && LocalOnlyRecordAnswersQuestion(lr, q)) |
3892 | { | | 3890 | { |
3893 | LogInfo("AnswerNewQuestion: Question %p %##s (%s) will be answered using new local auth records " | | 3891 | LogInfo("AnswerNewQuestion: Question %p %##s (%s) will be answered using new local auth records " |
3894 | " LOAddressAnswers %d", q, q->qname.c, DNSTypeName(q->qtype), q->LOAddressAnswers); | | 3892 | " LOAddressAnswers %d", q, q->qname.c, DNSTypeName(q->qtype), q->LOAddressAnswers); |
3895 | goto exit; | | 3893 | goto exit; |
3896 | } | | 3894 | } |
3897 | lr = lr->next; | | 3895 | lr = lr->next; |
3898 | } | | 3896 | } |
3899 | } | | 3897 | } |
3900 | | | 3898 | |
3901 | | | 3899 | |
3902 | // If we are not supposed to answer this question, generate a negative response. | | 3900 | // If we are not supposed to answer this question, generate a negative response. |
3903 | // Temporarily suspend the SuppressQuery so that AnswerCurrentQuestionWithResourceRecord can answer the question | | 3901 | // Temporarily suspend the SuppressQuery so that AnswerCurrentQuestionWithResourceRecord can answer the question |
3904 | if (QuerySuppressed(q)) { q->SuppressQuery = mDNSfalse; GenerateNegativeResponse(m); q->SuppressQuery = mDNStrue; } | | 3902 | if (QuerySuppressed(q)) { q->SuppressQuery = mDNSfalse; GenerateNegativeResponse(m); q->SuppressQuery = mDNStrue; } |
3905 | else | | 3903 | else |
3906 | { | | 3904 | { |
3907 | CacheRecord *rr; | | 3905 | CacheRecord *rr; |
3908 | for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) | | 3906 | for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) |
3909 | if (SameNameRecordAnswersQuestion(&rr->resrec, q)) | | 3907 | if (SameNameRecordAnswersQuestion(&rr->resrec, q)) |
3910 | { | | 3908 | { |
3911 | // SecsSinceRcvd is whole number of elapsed seconds, rounded down | | 3909 | // SecsSinceRcvd is whole number of elapsed seconds, rounded down |
3912 | mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond; | | 3910 | mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond; |
3913 | if (rr->resrec.rroriginalttl <= SecsSinceRcvd) | | 3911 | if (rr->resrec.rroriginalttl <= SecsSinceRcvd) |
3914 | { | | 3912 | { |
3915 | LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %s %d %d", | | 3913 | LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %s %d %d", |
3916 | rr->resrec.rroriginalttl, SecsSinceRcvd, CRDisplayString(m, rr), m->timenow, rr->TimeRcvd); | | 3914 | rr->resrec.rroriginalttl, SecsSinceRcvd, CRDisplayString(m, rr), m->timenow, rr->TimeRcvd); |
3917 | continue; // Go to next one in loop | | 3915 | continue; // Go to next one in loop |
3918 | } | | 3916 | } |
3919 | | | 3917 | |
3920 | // If this record set is marked unique, then that means we can reasonably assume we have the whole set | | 3918 | // If this record set is marked unique, then that means we can reasonably assume we have the whole set |
3921 | // -- we don't need to rush out on the network and query immediately to see if there are more answers out there | | 3919 | // -- we don't need to rush out on the network and query immediately to see if there are more answers out there |
3922 | if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique)) | | 3920 | if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique)) |
3923 | ShouldQueryImmediately = mDNSfalse; | | 3921 | ShouldQueryImmediately = mDNSfalse; |
3924 | q->CurrentAnswers++; | | 3922 | q->CurrentAnswers++; |
3925 | if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++; | | 3923 | if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++; |
3926 | if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++; | | 3924 | if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++; |
3927 | AnsweredFromCache = mDNStrue; | | 3925 | AnsweredFromCache = mDNStrue; |
3928 | AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); | | 3926 | AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); |
3929 | if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here | | 3927 | if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here |
3930 | } | | 3928 | } |
3931 | else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype)) | | 3929 | else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype)) |
3932 | ShouldQueryImmediately = mDNSfalse; | | 3930 | ShouldQueryImmediately = mDNSfalse; |
3933 | } | | 3931 | } |
3934 | // We don't use LogInfo for this "Question deleted" message because it happens so routinely that | | 3932 | // We don't use LogInfo for this "Question deleted" message because it happens so routinely that |
3935 | // it's not remotely remarkable, and therefore unlikely to be of much help tracking down bugs. | | 3933 | // it's not remotely remarkable, and therefore unlikely to be of much help tracking down bugs. |
3936 | if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving cache answers"); goto exit; } | | 3934 | if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving cache answers"); goto exit; } |
3937 | | | 3935 | |
3938 | // Neither a local record nor a cache entry could answer this question. If this question need to be retried | | 3936 | // Neither a local record nor a cache entry could answer this question. If this question need to be retried |
3939 | // with search domains, generate a negative response which will now retry after appending search domains. | | 3937 | // with search domains, generate a negative response which will now retry after appending search domains. |
3940 | // If the query was suppressed above, we already generated a negative response. When it gets unsuppressed, | | 3938 | // If the query was suppressed above, we already generated a negative response. When it gets unsuppressed, |
3941 | // we will retry with search domains. | | 3939 | // we will retry with search domains. |
3942 | if (!QuerySuppressed(q) && !AnsweredFromCache && q->RetryWithSearchDomains) | | 3940 | if (!QuerySuppressed(q) && !AnsweredFromCache && q->RetryWithSearchDomains) |
3943 | { | | 3941 | { |
3944 | LogInfo("AnswerNewQuestion: Generating response for retrying with search domains %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); | | 3942 | LogInfo("AnswerNewQuestion: Generating response for retrying with search domains %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); |
3945 | GenerateNegativeResponse(m); | | 3943 | GenerateNegativeResponse(m); |
3946 | } | | 3944 | } |
3947 | | | 3945 | |
3948 | if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving negative answer"); goto exit; } | | 3946 | if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving negative answer"); goto exit; } |
3949 | | | 3947 | |
3950 | // Note: When a query gets suppressed or retried with search domains, we de-activate the question. | | 3948 | // Note: When a query gets suppressed or retried with search domains, we de-activate the question. |
3951 | // Hence we don't execute the following block of code for those cases. | | 3949 | // Hence we don't execute the following block of code for those cases. |
3952 | if (ShouldQueryImmediately && ActiveQuestion(q)) | | 3950 | if (ShouldQueryImmediately && ActiveQuestion(q)) |
3953 | { | | 3951 | { |
3954 | debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); | | 3952 | debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); |
3955 | q->ThisQInterval = InitialQuestionInterval; | | 3953 | q->ThisQInterval = InitialQuestionInterval; |
3956 | q->LastQTime = m->timenow - q->ThisQInterval; | | 3954 | q->LastQTime = m->timenow - q->ThisQInterval; |
3957 | if (mDNSOpaque16IsZero(q->TargetQID)) // For mDNS, spread packets to avoid a burst of simultaneous queries | | 3955 | if (mDNSOpaque16IsZero(q->TargetQID)) // For mDNS, spread packets to avoid a burst of simultaneous queries |
3958 | { | | 3956 | { |
3959 | // Compute random delay in the range 1-6 seconds, then divide by 50 to get 20-120ms | | 3957 | // Compute random delay in the range 1-6 seconds, then divide by 50 to get 20-120ms |
3960 | if (!m->RandomQueryDelay) | | 3958 | if (!m->RandomQueryDelay) |
3961 | m->RandomQueryDelay = (mDNSPlatformOneSecond + mDNSRandom(mDNSPlatformOneSecond*5) - 1) / 50 + 1; | | 3959 | m->RandomQueryDelay = (mDNSPlatformOneSecond + mDNSRandom(mDNSPlatformOneSecond*5) - 1) / 50 + 1; |
3962 | q->LastQTime += m->RandomQueryDelay; | | 3960 | q->LastQTime += m->RandomQueryDelay; |
3963 | } | | 3961 | } |
3964 | } | | 3962 | } |
3965 | | | 3963 | |
3966 | // IN ALL CASES make sure that m->NextScheduledQuery is set appropriately. | | 3964 | // IN ALL CASES make sure that m->NextScheduledQuery is set appropriately. |
3967 | // In cases where m->NewQuestions->DelayAnswering is set, we may have delayed generating our | | 3965 | // In cases where m->NewQuestions->DelayAnswering is set, we may have delayed generating our |
3968 | // answers for this question until *after* its scheduled transmission time, in which case | | 3966 | // answers for this question until *after* its scheduled transmission time, in which case |
3969 | // m->NextScheduledQuery may now be set to 'never', and in that case -- even though we're *not* doing | | 3967 | // m->NextScheduledQuery may now be set to 'never', and in that case -- even though we're *not* doing |
3970 | // ShouldQueryImmediately -- we still need to make sure we set m->NextScheduledQuery correctly. | | 3968 | // ShouldQueryImmediately -- we still need to make sure we set m->NextScheduledQuery correctly. |
3971 | SetNextQueryTime(m,q); | | 3969 | SetNextQueryTime(m,q); |
3972 | | | 3970 | |
3973 | exit: | | 3971 | exit: |
3974 | m->CurrentQuestion = mDNSNULL; | | 3972 | m->CurrentQuestion = mDNSNULL; |
3975 | m->lock_rrcache = 0; | | 3973 | m->lock_rrcache = 0; |
3976 | } | | 3974 | } |
3977 | | | 3975 | |
3978 | // When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any | | 3976 | // When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any |
3979 | // appropriate answers, stopping if it reaches a NewLocalOnlyRecord -- these will be handled by AnswerAllLocalQuestionsWithLocalAuthRecord | | 3977 | // appropriate answers, stopping if it reaches a NewLocalOnlyRecord -- these will be handled by AnswerAllLocalQuestionsWithLocalAuthRecord |
3980 | mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m) | | 3978 | mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m) |
3981 | { | | 3979 | { |
3982 | mDNSu32 slot; | | 3980 | mDNSu32 slot; |
3983 | AuthGroup *ag; | | 3981 | AuthGroup *ag; |
3984 | DNSQuestion *q = m->NewLocalOnlyQuestions; // Grab the question we're going to answer | | 3982 | DNSQuestion *q = m->NewLocalOnlyQuestions; // Grab the question we're going to answer |
3985 | m->NewLocalOnlyQuestions = q->next; // Advance NewLocalOnlyQuestions to the next (if any) | | 3983 | m->NewLocalOnlyQuestions = q->next; // Advance NewLocalOnlyQuestions to the next (if any) |
3986 | | | 3984 | |
3987 | debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); | | 3985 | debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); |
3988 | | | 3986 | |
3989 | if (m->CurrentQuestion) | | 3987 | if (m->CurrentQuestion) |
3990 | LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)", | | 3988 | LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)", |
3991 | m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); | | 3989 | m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); |
3992 | m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted | | 3990 | m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted |
3993 | | | 3991 | |
3994 | if (m->CurrentRecord) | | 3992 | if (m->CurrentRecord) |
3995 | LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); | | 3993 | LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); |
3996 | | | 3994 | |
3997 | // 1. First walk the LocalOnly records answering the LocalOnly question | | 3995 | // 1. First walk the LocalOnly records answering the LocalOnly question |
3998 | // 2. As LocalOnly questions should also be answered by any other Auth records local to the machine, | | 3996 | // 2. As LocalOnly questions should also be answered by any other Auth records local to the machine, |
3999 | // walk the ResourceRecords list delivering the answers | | 3997 | // walk the ResourceRecords list delivering the answers |
4000 | slot = AuthHashSlot(&q->qname); | | 3998 | slot = AuthHashSlot(&q->qname); |
4001 | ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname); | | 3999 | ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname); |
4002 | if (ag) | | 4000 | if (ag) |
4003 | { | | 4001 | { |
4004 | m->CurrentRecord = ag->members; | | 4002 | m->CurrentRecord = ag->members; |
4005 | while (m->CurrentRecord && m->CurrentRecord != ag->NewLocalOnlyRecords) | | 4003 | while (m->CurrentRecord && m->CurrentRecord != ag->NewLocalOnlyRecords) |
4006 | { | | 4004 | { |
4007 | AuthRecord *rr = m->CurrentRecord; | | 4005 | AuthRecord *rr = m->CurrentRecord; |
4008 | m->CurrentRecord = rr->next; | | 4006 | m->CurrentRecord = rr->next; |
4009 | if (LocalOnlyRecordAnswersQuestion(rr, q)) | | 4007 | if (LocalOnlyRecordAnswersQuestion(rr, q)) |
4010 | { | | 4008 | { |
4011 | AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue); | | 4009 | AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue); |
4012 | if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here | | 4010 | if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here |
4013 | } | | 4011 | } |
4014 | } | | 4012 | } |
4015 | } | | 4013 | } |
4016 | | | 4014 | |
4017 | if (m->CurrentQuestion == q) | | 4015 | if (m->CurrentQuestion == q) |
4018 | { | | 4016 | { |
4019 | m->CurrentRecord = m->ResourceRecords; | | 4017 | m->CurrentRecord = m->ResourceRecords; |
4020 | | | 4018 | |
4021 | while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords) | | 4019 | while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords) |
4022 | { | | 4020 | { |
4023 | AuthRecord *rr = m->CurrentRecord; | | 4021 | AuthRecord *rr = m->CurrentRecord; |
4024 | m->CurrentRecord = rr->next; | | 4022 | m->CurrentRecord = rr->next; |
4025 | if (ResourceRecordAnswersQuestion(&rr->resrec, q)) | | 4023 | if (ResourceRecordAnswersQuestion(&rr->resrec, q)) |
4026 | { | | 4024 | { |
4027 | AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue); | | 4025 | AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue); |
4028 | if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here | | 4026 | if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here |
4029 | } | | 4027 | } |
4030 | } | | 4028 | } |
4031 | } | | 4029 | } |
4032 | | | 4030 | |
4033 | m->CurrentQuestion = mDNSNULL; | | 4031 | m->CurrentQuestion = mDNSNULL; |
4034 | m->CurrentRecord = mDNSNULL; | | 4032 | m->CurrentRecord = mDNSNULL; |
4035 | } | | 4033 | } |
4036 | | | 4034 | |
4037 | mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const PreserveCG) | | 4035 | mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const PreserveCG) |
4038 | { | | 4036 | { |
4039 | CacheEntity *e = mDNSNULL; | | 4037 | CacheEntity *e = mDNSNULL; |
4040 | | | 4038 | |
4041 | if (m->lock_rrcache) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); } | | 4039 | if (m->lock_rrcache) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); } |
4042 | m->lock_rrcache = 1; | | 4040 | m->lock_rrcache = 1; |
4043 | | | 4041 | |
4044 | // If we have no free records, ask the client layer to give us some more memory | | 4042 | // If we have no free records, ask the client layer to give us some more memory |
4045 | if (!m->rrcache_free && m->MainCallback) | | 4043 | if (!m->rrcache_free && m->MainCallback) |
4046 | { | | 4044 | { |
4047 | if (m->rrcache_totalused != m->rrcache_size) | | 4045 | if (m->rrcache_totalused != m->rrcache_size) |
4048 | LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu", | | 4046 | LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu", |
4049 | m->rrcache_totalused, m->rrcache_size); | | 4047 | m->rrcache_totalused, m->rrcache_size); |
4050 | | | 4048 | |
4051 | // We don't want to be vulnerable to a malicious attacker flooding us with an infinite | | 4049 | // We don't want to be vulnerable to a malicious attacker flooding us with an infinite |
4052 | // number of bogus records so that we keep growing our cache until the machine runs out of memory. | | 4050 | // number of bogus records so that we keep growing our cache until the machine runs out of memory. |
4053 | // To guard against this, if our cache grows above 512kB (approx 3168 records at 164 bytes each), | | 4051 | // To guard against this, if our cache grows above 512kB (approx 3168 records at 164 bytes each), |
4054 | // and we're actively using less than 1/32 of that cache, then we purge all the unused records | | 4052 | // and we're actively using less than 1/32 of that cache, then we purge all the unused records |
4055 | // and recycle them, instead of allocating more memory. | | 4053 | // and recycle them, instead of allocating more memory. |
4056 | if (m->rrcache_size > 5000 && m->rrcache_size / 32 > m->rrcache_active) | | 4054 | if (m->rrcache_size > 5000 && m->rrcache_size / 32 > m->rrcache_active) |
4057 | LogInfo("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu", | | 4055 | LogInfo("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu", |
4058 | m->rrcache_size, m->rrcache_active); | | 4056 | m->rrcache_size, m->rrcache_active); |
4059 | else | | 4057 | else |
4060 | { | | 4058 | { |
4061 | mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback | | 4059 | mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback |
4062 | m->MainCallback(m, mStatus_GrowCache); | | 4060 | m->MainCallback(m, mStatus_GrowCache); |
4063 | mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again | | 4061 | mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again |
4064 | } | | 4062 | } |
4065 | } | | 4063 | } |
4066 | | | 4064 | |
4067 | // If we still have no free records, recycle all the records we can. | | 4065 | // If we still have no free records, recycle all the records we can. |
4068 | // Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass. | | 4066 | // Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass. |
4069 | if (!m->rrcache_free) | | 4067 | if (!m->rrcache_free) |
4070 | { | | 4068 | { |
4071 | mDNSu32 oldtotalused = m->rrcache_totalused; | | 4069 | mDNSu32 oldtotalused = m->rrcache_totalused; |
4072 | mDNSu32 slot; | | 4070 | mDNSu32 slot; |
4073 | for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) | | 4071 | for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) |
4074 | { | | 4072 | { |
4075 | CacheGroup **cp = &m->rrcache_hash[slot]; | | 4073 | CacheGroup **cp = &m->rrcache_hash[slot]; |
4076 | while (*cp) | | 4074 | while (*cp) |
4077 | { | | 4075 | { |
4078 | CacheRecord **rp = &(*cp)->members; | | 4076 | CacheRecord **rp = &(*cp)->members; |
4079 | while (*rp) | | 4077 | while (*rp) |
4080 | { | | 4078 | { |
4081 | // Records that answer still-active questions are not candidates for recycling | | 4079 | // Records that answer still-active questions are not candidates for recycling |
4082 | // Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash | | 4080 | // Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash |
4083 | if ((*rp)->CRActiveQuestion || (*rp)->NextInCFList) | | 4081 | if ((*rp)->CRActiveQuestion || (*rp)->NextInCFList) |
4084 | rp=&(*rp)->next; | | 4082 | rp=&(*rp)->next; |
4085 | else | | 4083 | else |
4086 | { | | 4084 | { |
4087 | CacheRecord *rr = *rp; | | 4085 | CacheRecord *rr = *rp; |
4088 | *rp = (*rp)->next; // Cut record from list | | 4086 | *rp = (*rp)->next; // Cut record from list |
4089 | ReleaseCacheRecord(m, rr); | | 4087 | ReleaseCacheRecord(m, rr); |
4090 | } | | 4088 | } |
4091 | } | | 4089 | } |
4092 | if ((*cp)->rrcache_tail != rp) | | 4090 | if ((*cp)->rrcache_tail != rp) |
4093 | verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp); | | 4091 | verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp); |
4094 | (*cp)->rrcache_tail = rp; | | 4092 | (*cp)->rrcache_tail = rp; |
4095 | if ((*cp)->members || (*cp)==PreserveCG) cp=&(*cp)->next; | | 4093 | if ((*cp)->members || (*cp)==PreserveCG) cp=&(*cp)->next; |
4096 | else ReleaseCacheGroup(m, cp); | | 4094 | else ReleaseCacheGroup(m, cp); |
4097 | } | | 4095 | } |
4098 | } | | 4096 | } |
4099 | LogInfo("GetCacheEntity recycled %d records to reduce cache from %d to %d", | | 4097 | LogInfo("GetCacheEntity recycled %d records to reduce cache from %d to %d", |
4100 | oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused); | | 4098 | oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused); |
4101 | } | | 4099 | } |
4102 | | | 4100 | |
4103 | if (m->rrcache_free) // If there are records in the free list, take one | | 4101 | if (m->rrcache_free) // If there are records in the free list, take one |
4104 | { | | 4102 | { |
4105 | e = m->rrcache_free; | | 4103 | e = m->rrcache_free; |
4106 | m->rrcache_free = e->next; | | 4104 | m->rrcache_free = e->next; |
4107 | if (++m->rrcache_totalused >= m->rrcache_report) | | 4105 | if (++m->rrcache_totalused >= m->rrcache_report) |
4108 | { | | 4106 | { |
4109 | LogInfo("RR Cache now using %ld objects", m->rrcache_totalused); | | 4107 | LogInfo("RR Cache now using %ld objects", m->rrcache_totalused); |
4110 | if (m->rrcache_report < 100) m->rrcache_report += 10; | | 4108 | if (m->rrcache_report < 100) m->rrcache_report += 10; |
4111 | else if (m->rrcache_report < 1000) m->rrcache_report += 100; | | 4109 | else if (m->rrcache_report < 1000) m->rrcache_report += 100; |
4112 | else m->rrcache_report += 1000; | | 4110 | else m->rrcache_report += 1000; |
4113 | } | | 4111 | } |
4114 | mDNSPlatformMemZero(e, sizeof(*e)); | | 4112 | mDNSPlatformMemZero(e, sizeof(*e)); |
4115 | } | | 4113 | } |
4116 | | | 4114 | |
4117 | m->lock_rrcache = 0; | | 4115 | m->lock_rrcache = 0; |
4118 | | | 4116 | |
4119 | return(e); | | 4117 | return(e); |
4120 | } | | 4118 | } |
4121 | | | 4119 | |
4122 | mDNSlocal CacheRecord *GetCacheRecord(mDNS *const m, CacheGroup *cg, mDNSu16 RDLength) | | 4120 | mDNSlocal CacheRecord *GetCacheRecord(mDNS *const m, CacheGroup *cg, mDNSu16 RDLength) |
4123 | { | | 4121 | { |
4124 | CacheRecord *r = (CacheRecord *)GetCacheEntity(m, cg); | | 4122 | CacheRecord *r = (CacheRecord *)GetCacheEntity(m, cg); |
4125 | if (r) | | 4123 | if (r) |
4126 | { | | 4124 | { |
4127 | r->resrec.rdata = (RData*)&r->smallrdatastorage; // By default, assume we're usually going to be using local storage | | 4125 | r->resrec.rdata = (RData*)&r->smallrdatastorage; // By default, assume we're usually going to be using local storage |
4128 | if (RDLength > InlineCacheRDSize) // If RDLength is too big, allocate extra storage | | 4126 | if (RDLength > InlineCacheRDSize) // If RDLength is too big, allocate extra storage |
4129 | { | | 4127 | { |
4130 | r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength); | | 4128 | r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength); |
4131 | if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength; | | 4129 | if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength; |
4132 | else { ReleaseCacheEntity(m, (CacheEntity*)r); r = mDNSNULL; } | | 4130 | else { ReleaseCacheEntity(m, (CacheEntity*)r); r = mDNSNULL; } |
4133 | } | | 4131 | } |
4134 | } | | 4132 | } |
4135 | return(r); | | 4133 | return(r); |
4136 | } | | 4134 | } |
4137 | | | 4135 | |
4138 | mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr) | | 4136 | mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr) |
4139 | { | | 4137 | { |
4140 | mDNSu16 namelen = DomainNameLength(rr->name); | | 4138 | mDNSu16 namelen = DomainNameLength(rr->name); |
4141 | CacheGroup *cg = (CacheGroup*)GetCacheEntity(m, mDNSNULL); | | 4139 | CacheGroup *cg = (CacheGroup*)GetCacheEntity(m, mDNSNULL); |
4142 | if (!cg) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); } | | 4140 | if (!cg) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); } |
4143 | cg->next = m->rrcache_hash[slot]; | | 4141 | cg->next = m->rrcache_hash[slot]; |
4144 | cg->namehash = rr->namehash; | | 4142 | cg->namehash = rr->namehash; |
4145 | cg->members = mDNSNULL; | | 4143 | cg->members = mDNSNULL; |
4146 | cg->rrcache_tail = &cg->members; | | 4144 | cg->rrcache_tail = &cg->members; |
4147 | cg->name = (domainname*)cg->namestorage; | | 4145 | cg->name = (domainname*)cg->namestorage; |
4148 | //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s", | | 4146 | //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s", |
4149 | // (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c); | | 4147 | // (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c); |
4150 | if (namelen > InlineCacheGroupNameSize) cg->name = mDNSPlatformMemAllocate(namelen); | | 4148 | if (namelen > InlineCacheGroupNameSize) cg->name = mDNSPlatformMemAllocate(namelen); |
4151 | if (!cg->name) | | 4149 | if (!cg->name) |
4152 | { | | 4150 | { |
4153 | LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr->name->c); | | 4151 | LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr->name->c); |
4154 | ReleaseCacheEntity(m, (CacheEntity*)cg); | | 4152 | ReleaseCacheEntity(m, (CacheEntity*)cg); |
4155 | return(mDNSNULL); | | 4153 | return(mDNSNULL); |
4156 | } | | 4154 | } |
4157 | AssignDomainName(cg->name, rr->name); | | 4155 | AssignDomainName(cg->name, rr->name); |
4158 | | | 4156 | |
4159 | if (CacheGroupForRecord(m, slot, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c); | | 4157 | if (CacheGroupForRecord(m, slot, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c); |
4160 | m->rrcache_hash[slot] = cg; | | 4158 | m->rrcache_hash[slot] = cg; |
4161 | if (CacheGroupForRecord(m, slot, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c); | | 4159 | if (CacheGroupForRecord(m, slot, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c); |
4162 | | | 4160 | |
4163 | return(cg); | | 4161 | return(cg); |
4164 | } | | 4162 | } |
4165 | | | 4163 | |
4166 | mDNSexport void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr) | | 4164 | mDNSexport void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr) |
4167 | { | | 4165 | { |
4168 | if (m->mDNS_busy != m->mDNS_reentrancy+1) | | 4166 | if (m->mDNS_busy != m->mDNS_reentrancy+1) |
4169 | LogMsg("mDNS_PurgeCacheResourceRecord: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); | | 4167 | LogMsg("mDNS_PurgeCacheResourceRecord: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); |
4170 | // Make sure we mark this record as thoroughly expired -- we don't ever want to give | | 4168 | // Make sure we mark this record as thoroughly expired -- we don't ever want to give |
4171 | // a positive answer using an expired record (e.g. from an interface that has gone away). | | 4169 | // a positive answer using an expired record (e.g. from an interface that has gone away). |
4172 | // We don't want to clear CRActiveQuestion here, because that would leave the record subject to | | 4170 | // We don't want to clear CRActiveQuestion here, because that would leave the record subject to |
4173 | // summary deletion without giving the proper callback to any questions that are monitoring it. | | 4171 | // summary deletion without giving the proper callback to any questions that are monitoring it. |
4174 | // By setting UnansweredQueries to MaxUnansweredQueries we ensure it won't trigger any further expiration queries. | | 4172 | // By setting UnansweredQueries to MaxUnansweredQueries we ensure it won't trigger any further expiration queries. |
4175 | rr->TimeRcvd = m->timenow - mDNSPlatformOneSecond * 60; | | 4173 | rr->TimeRcvd = m->timenow - mDNSPlatformOneSecond * 60; |
4176 | rr->UnansweredQueries = MaxUnansweredQueries; | | 4174 | rr->UnansweredQueries = MaxUnansweredQueries; |
4177 | rr->resrec.rroriginalttl = 0; | | 4175 | rr->resrec.rroriginalttl = 0; |
4178 | SetNextCacheCheckTimeForRecord(m, rr); | | 4176 | SetNextCacheCheckTimeForRecord(m, rr); |
4179 | } | | 4177 | } |
4180 | | | 4178 | |
4181 | mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m) | | 4179 | mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m) |
4182 | { | | 4180 | { |
4183 | mDNSs32 time; | | 4181 | mDNSs32 time; |
4184 | mDNSPlatformLock(m); | | 4182 | mDNSPlatformLock(m); |
4185 | if (m->mDNS_busy) | | 4183 | if (m->mDNS_busy) |
4186 | { | | 4184 | { |
4187 | LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow."); | | 4185 | LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow."); |
4188 | if (!m->timenow) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy); | | 4186 | if (!m->timenow) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy); |
4189 | } | | 4187 | } |
4190 | | | 4188 | |
4191 | if (m->timenow) time = m->timenow; | | 4189 | if (m->timenow) time = m->timenow; |
4192 | else time = mDNS_TimeNow_NoLock(m); | | 4190 | else time = mDNS_TimeNow_NoLock(m); |
4193 | mDNSPlatformUnlock(m); | | 4191 | mDNSPlatformUnlock(m); |
4194 | return(time); | | 4192 | return(time); |
4195 | } | | 4193 | } |
4196 | | | 4194 | |
4197 | // To avoid pointless CPU thrash, we use SetSPSProxyListChanged(X) to record the last interface that | | 4195 | // To avoid pointless CPU thrash, we use SetSPSProxyListChanged(X) to record the last interface that |
4198 | // had its Sleep Proxy client list change, and defer to actual BPF reconfiguration to mDNS_Execute(). | | 4196 | // had its Sleep Proxy client list change, and defer to actual BPF reconfiguration to mDNS_Execute(). |
4199 | // (GetNextScheduledEvent() returns "now" when m->SPSProxyListChanged is set) | | 4197 | // (GetNextScheduledEvent() returns "now" when m->SPSProxyListChanged is set) |
4200 | #define SetSPSProxyListChanged(X) do { \ | | 4198 | #define SetSPSProxyListChanged(X) do { \ |
4201 | if (m->SPSProxyListChanged && m->SPSProxyListChanged != (X)) mDNSPlatformUpdateProxyList(m, m->SPSProxyListChanged); \ | | 4199 | if (m->SPSProxyListChanged && m->SPSProxyListChanged != (X)) mDNSPlatformUpdateProxyList(m, m->SPSProxyListChanged); \ |
4202 | m->SPSProxyListChanged = (X); } while(0) | | 4200 | m->SPSProxyListChanged = (X); } while(0) |
4203 | | | 4201 | |
4204 | // Called from mDNS_Execute() to expire stale proxy records | | 4202 | // Called from mDNS_Execute() to expire stale proxy records |
4205 | mDNSlocal void CheckProxyRecords(mDNS *const m, AuthRecord *list) | | 4203 | mDNSlocal void CheckProxyRecords(mDNS *const m, AuthRecord *list) |
4206 | { | | 4204 | { |
4207 | m->CurrentRecord = list; | | 4205 | m->CurrentRecord = list; |
4208 | while (m->CurrentRecord) | | 4206 | while (m->CurrentRecord) |
4209 | { | | 4207 | { |
4210 | AuthRecord *rr = m->CurrentRecord; | | 4208 | AuthRecord *rr = m->CurrentRecord; |
4211 | if (rr->resrec.RecordType != kDNSRecordTypeDeregistering && rr->WakeUp.HMAC.l[0]) | | 4209 | if (rr->resrec.RecordType != kDNSRecordTypeDeregistering && rr->WakeUp.HMAC.l[0]) |
4212 | { | | 4210 | { |
4213 | // If m->SPSSocket is NULL that means we're not acting as a sleep proxy any more, | | 4211 | // If m->SPSSocket is NULL that means we're not acting as a sleep proxy any more, |
4214 | // so we need to cease proxying for *all* records we may have, expired or not. | | 4212 | // so we need to cease proxying for *all* records we may have, expired or not. |
4215 | if (m->SPSSocket && m->timenow - rr->TimeExpire < 0) // If proxy record not expired yet, update m->NextScheduledSPS | | 4213 | if (m->SPSSocket && m->timenow - rr->TimeExpire < 0) // If proxy record not expired yet, update m->NextScheduledSPS |
4216 | { | | 4214 | { |
4217 | if (m->NextScheduledSPS - rr->TimeExpire > 0) | | 4215 | if (m->NextScheduledSPS - rr->TimeExpire > 0) |
4218 | m->NextScheduledSPS = rr->TimeExpire; | | 4216 | m->NextScheduledSPS = rr->TimeExpire; |
4219 | } | | 4217 | } |
4220 | else // else proxy record expired, so remove it | | 4218 | else // else proxy record expired, so remove it |
4221 | { | | 4219 | { |
4222 | LogSPS("CheckProxyRecords: Removing %d H-MAC %.6a I-MAC %.6a %d %s", | | 4220 | LogSPS("CheckProxyRecords: Removing %d H-MAC %.6a I-MAC %.6a %d %s", |
4223 | m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, ARDisplayString(m, rr)); | | 4221 | m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, ARDisplayString(m, rr)); |
4224 | SetSPSProxyListChanged(rr->resrec.InterfaceID); | | 4222 | SetSPSProxyListChanged(rr->resrec.InterfaceID); |
4225 | mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); | | 4223 | mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); |
4226 | // Don't touch rr after this -- memory may have been free'd | | 4224 | // Don't touch rr after this -- memory may have been free'd |
4227 | } | | 4225 | } |
4228 | } | | 4226 | } |
4229 | // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because | | 4227 | // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because |
4230 | // new records could have been added to the end of the list as a result of that call. | | 4228 | // new records could have been added to the end of the list as a result of that call. |
4231 | if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now | | 4229 | if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now |
4232 | m->CurrentRecord = rr->next; | | 4230 | m->CurrentRecord = rr->next; |
4233 | } | | 4231 | } |
4234 | } | | 4232 | } |
4235 | | | 4233 | |
4236 | mDNSlocal void CheckRmvEventsForLocalRecords(mDNS *const m) | | 4234 | mDNSlocal void CheckRmvEventsForLocalRecords(mDNS *const m) |
4237 | { | | 4235 | { |
4238 | while (m->CurrentRecord) | | 4236 | while (m->CurrentRecord) |
4239 | { | | 4237 | { |
4240 | AuthRecord *rr = m->CurrentRecord; | | 4238 | AuthRecord *rr = m->CurrentRecord; |
4241 | if (rr->AnsweredLocalQ && rr->resrec.RecordType == kDNSRecordTypeDeregistering) | | 4239 | if (rr->AnsweredLocalQ && rr->resrec.RecordType == kDNSRecordTypeDeregistering) |
4242 | { | | 4240 | { |
4243 | debugf("CheckRmvEventsForLocalRecords: Generating local RMV events for %s", ARDisplayString(m, rr)); | | 4241 | debugf("CheckRmvEventsForLocalRecords: Generating local RMV events for %s", ARDisplayString(m, rr)); |
4244 | rr->resrec.RecordType = kDNSRecordTypeShared; | | 4242 | rr->resrec.RecordType = kDNSRecordTypeShared; |
4245 | AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); | | 4243 | AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); |
4246 | if (m->CurrentRecord == rr) // If rr still exists in list, restore its state now | | 4244 | if (m->CurrentRecord == rr) // If rr still exists in list, restore its state now |
4247 | { | | 4245 | { |
4248 | rr->resrec.RecordType = kDNSRecordTypeDeregistering; | | 4246 | rr->resrec.RecordType = kDNSRecordTypeDeregistering; |
4249 | rr->AnsweredLocalQ = mDNSfalse; | | 4247 | rr->AnsweredLocalQ = mDNSfalse; |
4250 | // SendResponses normally calls CompleteDeregistration after sending goodbyes. | | 4248 | // SendResponses normally calls CompleteDeregistration after sending goodbyes. |
4251 | // For LocalOnly records, we don't do that and hence we need to do that here. | | 4249 | // For LocalOnly records, we don't do that and hence we need to do that here. |
4252 | if (RRLocalOnly(rr)) CompleteDeregistration(m, rr); | | 4250 | if (RRLocalOnly(rr)) CompleteDeregistration(m, rr); |
4253 | } | | 4251 | } |
4254 | } | | 4252 | } |
4255 | if (m->CurrentRecord == rr) // If m->CurrentRecord was not auto-advanced, do it ourselves now | | 4253 | if (m->CurrentRecord == rr) // If m->CurrentRecord was not auto-advanced, do it ourselves now |
4256 | m->CurrentRecord = rr->next; | | 4254 | m->CurrentRecord = rr->next; |
4257 | } | | 4255 | } |
4258 | } | | 4256 | } |
4259 | | | 4257 | |
4260 | mDNSlocal void TimeoutQuestions(mDNS *const m) | | 4258 | mDNSlocal void TimeoutQuestions(mDNS *const m) |
4261 | { | | 4259 | { |
4262 | m->NextScheduledStopTime = m->timenow + 0x3FFFFFFF; | | 4260 | m->NextScheduledStopTime = m->timenow + 0x3FFFFFFF; |
4263 | if (m->CurrentQuestion) | | 4261 | if (m->CurrentQuestion) |
4264 | LogMsg("TimeoutQuestions ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, | | 4262 | LogMsg("TimeoutQuestions ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, |
4265 | DNSTypeName(m->CurrentQuestion->qtype)); | | 4263 | DNSTypeName(m->CurrentQuestion->qtype)); |
4266 | m->CurrentQuestion = m->Questions; | | 4264 | m->CurrentQuestion = m->Questions; |
4267 | while (m->CurrentQuestion) | | 4265 | while (m->CurrentQuestion) |
4268 | { | | 4266 | { |
4269 | DNSQuestion *const q = m->CurrentQuestion; | | 4267 | DNSQuestion *const q = m->CurrentQuestion; |
4270 | if (q->StopTime) | | 4268 | if (q->StopTime) |
4271 | { | | 4269 | { |
4272 | if (m->timenow - q->StopTime >= 0) | | 4270 | if (m->timenow - q->StopTime >= 0) |
4273 | { | | 4271 | { |
4274 | LogInfo("TimeoutQuestions: question %##s timed out, time %d", q->qname.c, m->timenow - q->StopTime); | | 4272 | LogInfo("TimeoutQuestions: question %##s timed out, time %d", q->qname.c, m->timenow - q->StopTime); |
4275 | GenerateNegativeResponse(m); | | 4273 | GenerateNegativeResponse(m); |
4276 | if (m->CurrentQuestion == q) q->StopTime = 0; | | 4274 | if (m->CurrentQuestion == q) q->StopTime = 0; |
4277 | } | | 4275 | } |
4278 | else | | 4276 | else |
4279 | { | | 4277 | { |
4280 | if (m->NextScheduledStopTime - q->StopTime > 0) | | 4278 | if (m->NextScheduledStopTime - q->StopTime > 0) |
4281 | m->NextScheduledStopTime = q->StopTime; | | 4279 | m->NextScheduledStopTime = q->StopTime; |
4282 | } | | 4280 | } |
4283 | } | | 4281 | } |
4284 | // If m->CurrentQuestion wasn't modified out from under us, advance it now | | 4282 | // If m->CurrentQuestion wasn't modified out from under us, advance it now |
4285 | // We can't do this at the start of the loop because GenerateNegativeResponse | | 4283 | // We can't do this at the start of the loop because GenerateNegativeResponse |
4286 | // depends on having m->CurrentQuestion point to the right question | | 4284 | // depends on having m->CurrentQuestion point to the right question |
4287 | if (m->CurrentQuestion == q) | | 4285 | if (m->CurrentQuestion == q) |
4288 | m->CurrentQuestion = q->next; | | 4286 | m->CurrentQuestion = q->next; |
4289 | } | | 4287 | } |
4290 | m->CurrentQuestion = mDNSNULL; | | 4288 | m->CurrentQuestion = mDNSNULL; |
4291 | } | | 4289 | } |
4292 | | | 4290 | |
4293 | mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) | | 4291 | mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) |
4294 | { | | 4292 | { |
4295 | mDNS_Lock(m); // Must grab lock before trying to read m->timenow | | 4293 | mDNS_Lock(m); // Must grab lock before trying to read m->timenow |
4296 | | | 4294 | |
4297 | if (m->timenow - m->NextScheduledEvent >= 0) | | 4295 | if (m->timenow - m->NextScheduledEvent >= 0) |
4298 | { | | 4296 | { |
4299 | int i; | | 4297 | int i; |
4300 | AuthRecord *head, *tail; | | 4298 | AuthRecord *head, *tail; |
4301 | mDNSu32 slot; | | 4299 | mDNSu32 slot; |
4302 | AuthGroup *ag; | | 4300 | AuthGroup *ag; |
4303 | | | 4301 | |
4304 | verbosedebugf("mDNS_Execute"); | | 4302 | verbosedebugf("mDNS_Execute"); |
4305 | | | 4303 | |
4306 | if (m->CurrentQuestion) | | 4304 | if (m->CurrentQuestion) |
4307 | LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", | | 4305 | LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", |
4308 | m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); | | 4306 | m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); |
4309 | | | 4307 | |
4310 | if (m->CurrentRecord) | | 4308 | if (m->CurrentRecord) |
4311 | LogMsg("mDNS_Execute: ERROR m->CurrentRecord already set: %s", ARDisplayString(m, m->CurrentRecord)); | | 4309 | LogMsg("mDNS_Execute: ERROR m->CurrentRecord already set: %s", ARDisplayString(m, m->CurrentRecord)); |
4312 | | | 4310 | |
4313 | // 1. If we're past the probe suppression time, we can clear it | | 4311 | // 1. If we're past the probe suppression time, we can clear it |
4314 | if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0; | | 4312 | if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0; |
4315 | | | 4313 | |
4316 | // 2. If it's been more than ten seconds since the last probe failure, we can clear the counter | | 4314 | // 2. If it's been more than ten seconds since the last probe failure, we can clear the counter |
4317 | if (m->NumFailedProbes && m->timenow - m->ProbeFailTime >= mDNSPlatformOneSecond * 10) m->NumFailedProbes = 0; | | 4315 | if (m->NumFailedProbes && m->timenow - m->ProbeFailTime >= mDNSPlatformOneSecond * 10) m->NumFailedProbes = 0; |
4318 | | | 4316 | |
4319 | // 3. Purge our cache of stale old records | | 4317 | // 3. Purge our cache of stale old records |
4320 | if (m->rrcache_size && m->timenow - m->NextCacheCheck >= 0) | | 4318 | if (m->rrcache_size && m->timenow - m->NextCacheCheck >= 0) |
4321 | { | | 4319 | { |
4322 | mDNSu32 numchecked = 0; | | 4320 | mDNSu32 numchecked = 0; |
4323 | m->NextCacheCheck = m->timenow + 0x3FFFFFFF; | | 4321 | m->NextCacheCheck = m->timenow + 0x3FFFFFFF; |
4324 | for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) | | 4322 | for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) |
4325 | { | | 4323 | { |
4326 | if (m->timenow - m->rrcache_nextcheck[slot] >= 0) | | 4324 | if (m->timenow - m->rrcache_nextcheck[slot] >= 0) |
4327 | { | | 4325 | { |
4328 | CacheGroup **cp = &m->rrcache_hash[slot]; | | 4326 | CacheGroup **cp = &m->rrcache_hash[slot]; |
4329 | m->rrcache_nextcheck[slot] = m->timenow + 0x3FFFFFFF; | | 4327 | m->rrcache_nextcheck[slot] = m->timenow + 0x3FFFFFFF; |
4330 | while (*cp) | | 4328 | while (*cp) |
4331 | { | | 4329 | { |
4332 | debugf("m->NextCacheCheck %4d Slot %3d %##s", numchecked, slot, *cp ? (*cp)->name : (domainname*)"\x04NULL"); | | 4330 | debugf("m->NextCacheCheck %4d Slot %3d %##s", numchecked, slot, *cp ? (*cp)->name : (domainname*)"\x04NULL"); |
4333 | numchecked++; | | 4331 | numchecked++; |
4334 | CheckCacheExpiration(m, slot, *cp); | | 4332 | CheckCacheExpiration(m, slot, *cp); |
4335 | if ((*cp)->members) cp=&(*cp)->next; | | 4333 | if ((*cp)->members) cp=&(*cp)->next; |
4336 | else ReleaseCacheGroup(m, cp); | | 4334 | else ReleaseCacheGroup(m, cp); |
4337 | } | | 4335 | } |
4338 | } | | 4336 | } |
4339 | // Even if we didn't need to actually check this slot yet, still need to | | 4337 | // Even if we didn't need to actually check this slot yet, still need to |
4340 | // factor its nextcheck time into our overall NextCacheCheck value | | 4338 | // factor its nextcheck time into our overall NextCacheCheck value |
4341 | if (m->NextCacheCheck - m->rrcache_nextcheck[slot] > 0) | | 4339 | if (m->NextCacheCheck - m->rrcache_nextcheck[slot] > 0) |
4342 | m->NextCacheCheck = m->rrcache_nextcheck[slot]; | | 4340 | m->NextCacheCheck = m->rrcache_nextcheck[slot]; |
4343 | } | | 4341 | } |
4344 | debugf("m->NextCacheCheck %4d checked, next in %d", numchecked, m->NextCacheCheck - m->timenow); | | 4342 | debugf("m->NextCacheCheck %4d checked, next in %d", numchecked, m->NextCacheCheck - m->timenow); |
4345 | } | | 4343 | } |
4346 | | | 4344 | |
4347 | if (m->timenow - m->NextScheduledSPS >= 0) | | 4345 | if (m->timenow - m->NextScheduledSPS >= 0) |
4348 | { | | 4346 | { |
4349 | m->NextScheduledSPS = m->timenow + 0x3FFFFFFF; | | 4347 | m->NextScheduledSPS = m->timenow + 0x3FFFFFFF; |
4350 | CheckProxyRecords(m, m->DuplicateRecords); // Clear m->DuplicateRecords first, then m->ResourceRecords | | 4348 | CheckProxyRecords(m, m->DuplicateRecords); // Clear m->DuplicateRecords first, then m->ResourceRecords |
4351 | CheckProxyRecords(m, m->ResourceRecords); | | 4349 | CheckProxyRecords(m, m->ResourceRecords); |
4352 | } | | 4350 | } |
4353 | | | 4351 | |
4354 | SetSPSProxyListChanged(mDNSNULL); // Perform any deferred BPF reconfiguration now | | 4352 | SetSPSProxyListChanged(mDNSNULL); // Perform any deferred BPF reconfiguration now |
4355 | | | 4353 | |
4356 | // Clear AnnounceOwner if necessary. (Do this *before* SendQueries() and SendResponses().) | | 4354 | // Clear AnnounceOwner if necessary. (Do this *before* SendQueries() and SendResponses().) |
4357 | if (m->AnnounceOwner && m->timenow - m->AnnounceOwner >= 0) m->AnnounceOwner = 0; | | 4355 | if (m->AnnounceOwner && m->timenow - m->AnnounceOwner >= 0) m->AnnounceOwner = 0; |
4358 | | | 4356 | |
4359 | if (m->DelaySleep && m->timenow - m->DelaySleep >= 0) | | 4357 | if (m->DelaySleep && m->timenow - m->DelaySleep >= 0) |
4360 | { | | 4358 | { |
4361 | m->DelaySleep = 0; | | 4359 | m->DelaySleep = 0; |
4362 | if (m->SleepState == SleepState_Transferring) | | 4360 | if (m->SleepState == SleepState_Transferring) |
4363 | { | | 4361 | { |
4364 | LogSPS("Re-sleep delay passed; now checking for Sleep Proxy Servers"); | | 4362 | LogSPS("Re-sleep delay passed; now checking for Sleep Proxy Servers"); |
4365 | BeginSleepProcessing(m); | | 4363 | BeginSleepProcessing(m); |
4366 | } | | 4364 | } |
4367 | } | | 4365 | } |
4368 | | | 4366 | |
4369 | // 4. See if we can answer any of our new local questions from the cache | | 4367 | // 4. See if we can answer any of our new local questions from the cache |
4370 | for (i=0; m->NewQuestions && i<1000; i++) | | 4368 | for (i=0; m->NewQuestions && i<1000; i++) |
4371 | { | | 4369 | { |
4372 | if (m->NewQuestions->DelayAnswering && m->timenow - m->NewQuestions->DelayAnswering < 0) break; | | 4370 | if (m->NewQuestions->DelayAnswering && m->timenow - m->NewQuestions->DelayAnswering < 0) break; |
4373 | AnswerNewQuestion(m); | | 4371 | AnswerNewQuestion(m); |
4374 | } | | 4372 | } |
4375 | if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit"); | | 4373 | if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit"); |
4376 | | | 4374 | |
4377 | // Make sure we deliver *all* local RMV events, and clear the corresponding rr->AnsweredLocalQ flags, *before* | | 4375 | // Make sure we deliver *all* local RMV events, and clear the corresponding rr->AnsweredLocalQ flags, *before* |
4378 | // we begin generating *any* new ADD events in the m->NewLocalOnlyQuestions and m->NewLocalRecords loops below. | | 4376 | // we begin generating *any* new ADD events in the m->NewLocalOnlyQuestions and m->NewLocalRecords loops below. |
4379 | for (i=0; i<1000 && m->LocalRemoveEvents; i++) | | 4377 | for (i=0; i<1000 && m->LocalRemoveEvents; i++) |
4380 | { | | 4378 | { |
4381 | m->LocalRemoveEvents = mDNSfalse; | | 4379 | m->LocalRemoveEvents = mDNSfalse; |
4382 | m->CurrentRecord = m->ResourceRecords; | | 4380 | m->CurrentRecord = m->ResourceRecords; |
4383 | CheckRmvEventsForLocalRecords(m); | | 4381 | CheckRmvEventsForLocalRecords(m); |
4384 | // Walk the LocalOnly records and deliver the RMV events | | 4382 | // Walk the LocalOnly records and deliver the RMV events |
4385 | for (slot = 0; slot < AUTH_HASH_SLOTS; slot++) | | 4383 | for (slot = 0; slot < AUTH_HASH_SLOTS; slot++) |
4386 | for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next) | | 4384 | for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next) |
4387 | { | | 4385 | { |
4388 | m->CurrentRecord = ag->members; | | 4386 | m->CurrentRecord = ag->members; |
4389 | if (m->CurrentRecord) CheckRmvEventsForLocalRecords(m); | | 4387 | if (m->CurrentRecord) CheckRmvEventsForLocalRecords(m); |
4390 | } | | 4388 | } |
4391 | } | | 4389 | } |
4392 | | | 4390 | |
4393 | if (i >= 1000) LogMsg("mDNS_Execute: m->LocalRemoveEvents exceeded loop limit"); | | 4391 | if (i >= 1000) LogMsg("mDNS_Execute: m->LocalRemoveEvents exceeded loop limit"); |
4394 | | | 4392 | |
4395 | for (i=0; m->NewLocalOnlyQuestions && i<1000; i++) AnswerNewLocalOnlyQuestion(m); | | 4393 | for (i=0; m->NewLocalOnlyQuestions && i<1000; i++) AnswerNewLocalOnlyQuestion(m); |
4396 | if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit"); | | 4394 | if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit"); |
4397 | | | 4395 | |
4398 | head = tail = mDNSNULL; | | 4396 | head = tail = mDNSNULL; |
4399 | for (i=0; i<1000 && m->NewLocalRecords && m->NewLocalRecords != head; i++) | | 4397 | for (i=0; i<1000 && m->NewLocalRecords && m->NewLocalRecords != head; i++) |
4400 | { | | 4398 | { |
4401 | AuthRecord *rr = m->NewLocalRecords; | | 4399 | AuthRecord *rr = m->NewLocalRecords; |
4402 | m->NewLocalRecords = m->NewLocalRecords->next; | | 4400 | m->NewLocalRecords = m->NewLocalRecords->next; |
4403 | if (LocalRecordReady(rr)) | | 4401 | if (LocalRecordReady(rr)) |
4404 | { | | 4402 | { |
4405 | debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr)); | | 4403 | debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr)); |
4406 | AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue); | | 4404 | AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue); |
4407 | } | | 4405 | } |
4408 | else if (!rr->next) | | 4406 | else if (!rr->next) |
4409 | { | | 4407 | { |
4410 | // If we have just one record that is not ready, we don't have to unlink and | | 4408 | // If we have just one record that is not ready, we don't have to unlink and |
4411 | // reinsert. As the NewLocalRecords will be NULL for this case, the loop will | | 4409 | // reinsert. As the NewLocalRecords will be NULL for this case, the loop will |
4412 | // terminate and set the NewLocalRecords to rr. | | 4410 | // terminate and set the NewLocalRecords to rr. |
4413 | debugf("mDNS_Execute: Just one LocalAuthRecord %s, breaking out of the loop early", ARDisplayString(m, rr)); | | 4411 | debugf("mDNS_Execute: Just one LocalAuthRecord %s, breaking out of the loop early", ARDisplayString(m, rr)); |
4414 | if (head != mDNSNULL || m->NewLocalRecords != mDNSNULL) | | 4412 | if (head != mDNSNULL || m->NewLocalRecords != mDNSNULL) |
4415 | LogMsg("mDNS_Execute: ERROR!!: head %p, NewLocalRecords %p", head, m->NewLocalRecords); | | 4413 | LogMsg("mDNS_Execute: ERROR!!: head %p, NewLocalRecords %p", head, m->NewLocalRecords); |
4416 | | | 4414 | |
4417 | head = rr; | | 4415 | head = rr; |
4418 | } | | 4416 | } |
4419 | else | | 4417 | else |
4420 | { | | 4418 | { |
4421 | AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records | | 4419 | AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records |
4422 | debugf("mDNS_Execute: Skipping LocalAuthRecord %s", ARDisplayString(m, rr)); | | 4420 | debugf("mDNS_Execute: Skipping LocalAuthRecord %s", ARDisplayString(m, rr)); |
4423 | // if this is the first record we are skipping, move to the end of the list. | | 4421 | // if this is the first record we are skipping, move to the end of the list. |
4424 | // if we have already skipped records before, append it at the end. | | 4422 | // if we have already skipped records before, append it at the end. |
4425 | while (*p && *p != rr) p=&(*p)->next; | | 4423 | while (*p && *p != rr) p=&(*p)->next; |
4426 | if (*p) *p = rr->next; // Cut this record from the list | | 4424 | if (*p) *p = rr->next; // Cut this record from the list |
4427 | else { LogMsg("mDNS_Execute: ERROR!! Cannot find record %s in ResourceRecords list", ARDisplayString(m, rr)); break; } | | 4425 | else { LogMsg("mDNS_Execute: ERROR!! Cannot find record %s in ResourceRecords list", ARDisplayString(m, rr)); break; } |
4428 | if (!head) | | 4426 | if (!head) |
4429 | { | | 4427 | { |
4430 | while (*p) p=&(*p)->next; | | 4428 | while (*p) p=&(*p)->next; |
4431 | *p = rr; | | 4429 | *p = rr; |
4432 | head = tail = rr; | | 4430 | head = tail = rr; |
4433 | } | | 4431 | } |
4434 | else | | 4432 | else |
4435 | { | | 4433 | { |
4436 | tail->next = rr; | | 4434 | tail->next = rr; |
4437 | tail = rr; | | 4435 | tail = rr; |
4438 | } | | 4436 | } |
4439 | rr->next = mDNSNULL; | | 4437 | rr->next = mDNSNULL; |
4440 | } | | 4438 | } |
4441 | } | | 4439 | } |
4442 | m->NewLocalRecords = head; | | 4440 | m->NewLocalRecords = head; |
4443 | debugf("mDNS_Execute: Setting NewLocalRecords to %s", (head ? ARDisplayString(m, head) : "NULL")); | | 4441 | debugf("mDNS_Execute: Setting NewLocalRecords to %s", (head ? ARDisplayString(m, head) : "NULL")); |
4444 | | | 4442 | |
4445 | if (i >= 1000) LogMsg("mDNS_Execute: m->NewLocalRecords exceeded loop limit"); | | 4443 | if (i >= 1000) LogMsg("mDNS_Execute: m->NewLocalRecords exceeded loop limit"); |
4446 | | | 4444 | |
4447 | // Check to see if we have any new LocalOnly/P2P records to examine for delivering | | 4445 | // Check to see if we have any new LocalOnly/P2P records to examine for delivering |
4448 | // to our local questions | | 4446 | // to our local questions |
4449 | if (m->NewLocalOnlyRecords) | | 4447 | if (m->NewLocalOnlyRecords) |
4450 | { | | 4448 | { |
4451 | m->NewLocalOnlyRecords = mDNSfalse; | | 4449 | m->NewLocalOnlyRecords = mDNSfalse; |
4452 | for (slot = 0; slot < AUTH_HASH_SLOTS; slot++) | | 4450 | for (slot = 0; slot < AUTH_HASH_SLOTS; slot++) |
4453 | for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next) | | 4451 | for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next) |
4454 | { | | 4452 | { |
4455 | for (i=0; i<100 && ag->NewLocalOnlyRecords; i++) | | 4453 | for (i=0; i<100 && ag->NewLocalOnlyRecords; i++) |
4456 | { | | 4454 | { |
4457 | AuthRecord *rr = ag->NewLocalOnlyRecords; | | 4455 | AuthRecord *rr = ag->NewLocalOnlyRecords; |
4458 | ag->NewLocalOnlyRecords = ag->NewLocalOnlyRecords->next; | | 4456 | ag->NewLocalOnlyRecords = ag->NewLocalOnlyRecords->next; |
4459 | // LocalOnly records should always be ready as they never probe | | 4457 | // LocalOnly records should always be ready as they never probe |
4460 | if (LocalRecordReady(rr)) | | 4458 | if (LocalRecordReady(rr)) |
4461 | { | | 4459 | { |
4462 | debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr)); | | 4460 | debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr)); |
4463 | AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue); | | 4461 | AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue); |
4464 | } | | 4462 | } |
4465 | else LogMsg("mDNS_Execute: LocalOnlyRecord %s not ready", ARDisplayString(m, rr)); | | 4463 | else LogMsg("mDNS_Execute: LocalOnlyRecord %s not ready", ARDisplayString(m, rr)); |
4466 | } | | 4464 | } |
4467 | // We limit about 100 per AuthGroup that can be serviced at a time | | 4465 | // We limit about 100 per AuthGroup that can be serviced at a time |
4468 | if (i >= 100) LogMsg("mDNS_Execute: ag->NewLocalOnlyRecords exceeded loop limit"); | | 4466 | if (i >= 100) LogMsg("mDNS_Execute: ag->NewLocalOnlyRecords exceeded loop limit"); |
4469 | } | | 4467 | } |
4470 | } | | 4468 | } |
4471 | | | 4469 | |
4472 | // 5. Some questions may have picked a new DNS server and the cache may answer these questions now. | | 4470 | // 5. Some questions may have picked a new DNS server and the cache may answer these questions now. |
4473 | AnswerQuestionsForDNSServerChanges(m); | | 4471 | AnswerQuestionsForDNSServerChanges(m); |
4474 | | | 4472 | |
4475 | // 6. See what packets we need to send | | 4473 | // 6. See what packets we need to send |
4476 | if (m->mDNSPlatformStatus != mStatus_NoError || (m->SleepState == SleepState_Sleeping)) | | 4474 | if (m->mDNSPlatformStatus != mStatus_NoError || (m->SleepState == SleepState_Sleeping)) |
4477 | DiscardDeregistrations(m); | | 4475 | DiscardDeregistrations(m); |
4478 | if (m->mDNSPlatformStatus == mStatus_NoError && (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0)) | | 4476 | if (m->mDNSPlatformStatus == mStatus_NoError && (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0)) |
4479 | { | | 4477 | { |
4480 | // If the platform code is ready, and we're not suppressing packet generation right now | | 4478 | // If the platform code is ready, and we're not suppressing packet generation right now |
4481 | // then send our responses, probes, and questions. | | 4479 | // then send our responses, probes, and questions. |
4482 | // We check the cache first, because there might be records close to expiring that trigger questions to refresh them. | | 4480 | // We check the cache first, because there might be records close to expiring that trigger questions to refresh them. |
4483 | // We send queries next, because there might be final-stage probes that complete their probing here, causing | | 4481 | // We send queries next, because there might be final-stage probes that complete their probing here, causing |
4484 | // them to advance to announcing state, and we want those to be included in any announcements we send out. | | 4482 | // them to advance to announcing state, and we want those to be included in any announcements we send out. |
4485 | // Finally, we send responses, including the previously mentioned records that just completed probing. | | 4483 | // Finally, we send responses, including the previously mentioned records that just completed probing. |
4486 | m->SuppressSending = 0; | | 4484 | m->SuppressSending = 0; |
4487 | | | 4485 | |
4488 | // 7. Send Query packets. This may cause some probing records to advance to announcing state | | 4486 | // 7. Send Query packets. This may cause some probing records to advance to announcing state |
4489 | if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m); | | 4487 | if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m); |
4490 | if (m->timenow - m->NextScheduledQuery >= 0) | | 4488 | if (m->timenow - m->NextScheduledQuery >= 0) |
4491 | { | | 4489 | { |
4492 | DNSQuestion *q; | | 4490 | DNSQuestion *q; |
4493 | LogMsg("mDNS_Execute: SendQueries didn't send all its queries (%d - %d = %d) will try again in one second", | | 4491 | LogMsg("mDNS_Execute: SendQueries didn't send all its queries (%d - %d = %d) will try again in one second", |
4494 | m->timenow, m->NextScheduledQuery, m->timenow - m->NextScheduledQuery); | | 4492 | m->timenow, m->NextScheduledQuery, m->timenow - m->NextScheduledQuery); |
4495 | m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond; | | 4493 | m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond; |
4496 | for (q = m->Questions; q && q != m->NewQuestions; q=q->next) | | 4494 | for (q = m->Questions; q && q != m->NewQuestions; q=q->next) |
4497 | if (ActiveQuestion(q) && m->timenow - NextQSendTime(q) >= 0) | | 4495 | if (ActiveQuestion(q) && m->timenow - NextQSendTime(q) >= 0) |
4498 | LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); | | 4496 | LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); |
4499 | } | | 4497 | } |
4500 | if (m->timenow - m->NextScheduledProbe >= 0) | | 4498 | if (m->timenow - m->NextScheduledProbe >= 0) |
4501 | { | | 4499 | { |
4502 | LogMsg("mDNS_Execute: SendQueries didn't send all its probes (%d - %d = %d) will try again in one second", | | 4500 | debugf("mDNS_Execute: SendQueries didn't send all its probes (%d - %d = %d) will try again in one second", |
4503 | m->timenow, m->NextScheduledProbe, m->timenow - m->NextScheduledProbe); | | 4501 | m->timenow, m->NextScheduledProbe, m->timenow - m->NextScheduledProbe); |
4504 | m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond; | | 4502 | m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond; |
4505 | } | | 4503 | } |
4506 | | | 4504 | |
4507 | // 8. Send Response packets, including probing records just advanced to announcing state | | 4505 | // 8. Send Response packets, including probing records just advanced to announcing state |
4508 | if (m->timenow - m->NextScheduledResponse >= 0) SendResponses(m); | | 4506 | if (m->timenow - m->NextScheduledResponse >= 0) SendResponses(m); |
4509 | if (m->timenow - m->NextScheduledResponse >= 0) | | 4507 | if (m->timenow - m->NextScheduledResponse >= 0) |
4510 | { | | 4508 | { |
4511 | LogMsg("mDNS_Execute: SendResponses didn't send all its responses; will try again in one second"); | | 4509 | debugf("mDNS_Execute: SendResponses didn't send all its responses; will try again in one second"); |
4512 | m->NextScheduledResponse = m->timenow + mDNSPlatformOneSecond; | | 4510 | m->NextScheduledResponse = m->timenow + mDNSPlatformOneSecond; |
4513 | } | | 4511 | } |
4514 | } | | 4512 | } |
4515 | | | 4513 | |
4516 | // Clear RandomDelay values, ready to pick a new different value next time | | 4514 | // Clear RandomDelay values, ready to pick a new different value next time |
4517 | m->RandomQueryDelay = 0; | | 4515 | m->RandomQueryDelay = 0; |
4518 | m->RandomReconfirmDelay = 0; | | 4516 | m->RandomReconfirmDelay = 0; |
4519 | | | 4517 | |
4520 | if (m->NextScheduledStopTime && m->timenow - m->NextScheduledStopTime >= 0) TimeoutQuestions(m); | | 4518 | if (m->NextScheduledStopTime && m->timenow - m->NextScheduledStopTime >= 0) TimeoutQuestions(m); |
4521 | #ifndef UNICAST_DISABLED | | 4519 | #ifndef UNICAST_DISABLED |
4522 | if (m->NextSRVUpdate && m->timenow - m->NextSRVUpdate >= 0) UpdateAllSRVRecords(m); | | 4520 | if (m->NextSRVUpdate && m->timenow - m->NextSRVUpdate >= 0) UpdateAllSRVRecords(m); |
4523 | if (m->timenow - m->NextScheduledNATOp >= 0) CheckNATMappings(m); | | 4521 | if (m->timenow - m->NextScheduledNATOp >= 0) CheckNATMappings(m); |
4524 | if (m->timenow - m->NextuDNSEvent >= 0) uDNS_Tasks(m); | | 4522 | if (m->timenow - m->NextuDNSEvent >= 0) uDNS_Tasks(m); |
4525 | #endif | | 4523 | #endif |
4526 | } | | 4524 | } |
4527 | | | 4525 | |
4528 | // Note about multi-threaded systems: | | 4526 | // Note about multi-threaded systems: |
4529 | // On a multi-threaded system, some other thread could run right after the mDNS_Unlock(), | | 4527 | // On a multi-threaded system, some other thread could run right after the mDNS_Unlock(), |
4530 | // performing mDNS API operations that change our next scheduled event time. | | 4528 | // performing mDNS API operations that change our next scheduled event time. |
4531 | // | | 4529 | // |
4532 | // On multi-threaded systems (like the current Windows implementation) that have a single main thread | | 4530 | // On multi-threaded systems (like the current Windows implementation) that have a single main thread |
4533 | // calling mDNS_Execute() (and other threads allowed to call mDNS API routines) it is the responsibility | | 4531 | // calling mDNS_Execute() (and other threads allowed to call mDNS API routines) it is the responsibility |
4534 | // of the mDNSPlatformUnlock() routine to signal some kind of stateful condition variable that will | | 4532 | // of the mDNSPlatformUnlock() routine to signal some kind of stateful condition variable that will |
4535 | // signal whatever blocking primitive the main thread is using, so that it will wake up and execute one | | 4533 | // signal whatever blocking primitive the main thread is using, so that it will wake up and execute one |
4536 | // more iteration of its loop, and immediately call mDNS_Execute() again. The signal has to be stateful | | 4534 | // more iteration of its loop, and immediately call mDNS_Execute() again. The signal has to be stateful |
4537 | // in the sense that if the main thread has not yet entered its blocking primitive, then as soon as it | | 4535 | // in the sense that if the main thread has not yet entered its blocking primitive, then as soon as it |
4538 | // does, the state of the signal will be noticed, causing the blocking primitive to return immediately | | 4536 | // does, the state of the signal will be noticed, causing the blocking primitive to return immediately |
4539 | // without blocking. This avoids the race condition between the signal from the other thread arriving | | 4537 | // without blocking. This avoids the race condition between the signal from the other thread arriving |
4540 | // just *before* or just *after* the main thread enters the blocking primitive. | | 4538 | // just *before* or just *after* the main thread enters the blocking primitive. |
4541 | // | | 4539 | // |
4542 | // On multi-threaded systems (like the current Mac OS 9 implementation) that are entirely timer-driven, | | 4540 | // On multi-threaded systems (like the current Mac OS 9 implementation) that are entirely timer-driven, |
4543 | // with no main mDNS_Execute() thread, it is the responsibility of the mDNSPlatformUnlock() routine to | | 4541 | // with no main mDNS_Execute() thread, it is the responsibility of the mDNSPlatformUnlock() routine to |
4544 | // set the timer according to the m->NextScheduledEvent value, and then when the timer fires, the timer | | 4542 | // set the timer according to the m->NextScheduledEvent value, and then when the timer fires, the timer |
4545 | // callback function should call mDNS_Execute() (and ignore the return value, which may already be stale | | 4543 | // callback function should call mDNS_Execute() (and ignore the return value, which may already be stale |
4546 | // by the time it gets to the timer callback function). | | 4544 | // by the time it gets to the timer callback function). |
4547 | | | 4545 | |
4548 | mDNS_Unlock(m); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value | | 4546 | mDNS_Unlock(m); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value |
4549 | return(m->NextScheduledEvent); | | 4547 | return(m->NextScheduledEvent); |
4550 | } | | 4548 | } |
4551 | | | 4549 | |
4552 | mDNSlocal void SuspendLLQs(mDNS *m) | | 4550 | mDNSlocal void SuspendLLQs(mDNS *m) |
4553 | { | | 4551 | { |
4554 | DNSQuestion *q; | | 4552 | DNSQuestion *q; |
4555 | for (q = m->Questions; q; q = q->next) | | 4553 | for (q = m->Questions; q; q = q->next) |
4556 | if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->state == LLQ_Established) | | 4554 | if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->state == LLQ_Established) |
4557 | { q->ReqLease = 0; sendLLQRefresh(m, q); } | | 4555 | { q->ReqLease = 0; sendLLQRefresh(m, q); } |
4558 | } | | 4556 | } |
4559 | | | 4557 | |
4560 | mDNSlocal mDNSBool QuestionHasLocalAnswers(mDNS *const m, DNSQuestion *q) | | 4558 | mDNSlocal mDNSBool QuestionHasLocalAnswers(mDNS *const m, DNSQuestion *q) |
4561 | { | | 4559 | { |
4562 | AuthRecord *rr; | | 4560 | AuthRecord *rr; |
4563 | mDNSu32 slot; | | 4561 | mDNSu32 slot; |
4564 | AuthGroup *ag; | | 4562 | AuthGroup *ag; |
4565 | | | 4563 | |
4566 | slot = AuthHashSlot(&q->qname); | | 4564 | slot = AuthHashSlot(&q->qname); |
4567 | ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname); | | 4565 | ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname); |
4568 | if (ag) | | 4566 | if (ag) |
4569 | { | | 4567 | { |
4570 | for (rr = ag->members; rr; rr=rr->next) | | 4568 | for (rr = ag->members; rr; rr=rr->next) |
4571 | // Filter the /etc/hosts records - LocalOnly, Unique, A/AAAA/CNAME | | 4569 | // Filter the /etc/hosts records - LocalOnly, Unique, A/AAAA/CNAME |
4572 | if (LORecordAnswersAddressType(rr) && LocalOnlyRecordAnswersQuestion(rr, q)) | | 4570 | if (LORecordAnswersAddressType(rr) && LocalOnlyRecordAnswersQuestion(rr, q)) |
4573 | { | | 4571 | { |
4574 | LogInfo("QuestionHasLocalAnswers: Question %p %##s (%s) has local answer %s", q, q->qname.c, DNSTypeName(q->qtype), ARDisplayString(m, rr)); | | 4572 | LogInfo("QuestionHasLocalAnswers: Question %p %##s (%s) has local answer %s", q, q->qname.c, DNSTypeName(q->qtype), ARDisplayString(m, rr)); |
4575 | return mDNStrue; | | 4573 | return mDNStrue; |
4576 | } | | 4574 | } |
4577 | } | | 4575 | } |
4578 | return mDNSfalse; | | 4576 | return mDNSfalse; |
4579 | } | | 4577 | } |
4580 | | | 4578 | |
4581 | // ActivateUnicastQuery() is called from three places: | | 4579 | // ActivateUnicastQuery() is called from three places: |
4582 | // 1. When a new question is created | | 4580 | // 1. When a new question is created |
4583 | // 2. On wake from sleep | | 4581 | // 2. On wake from sleep |
4584 | // 3. When the DNS configuration changes | | 4582 | // 3. When the DNS configuration changes |
4585 | // In case 1 we don't want to mess with our established ThisQInterval and LastQTime (ScheduleImmediately is false) | | 4583 | // In case 1 we don't want to mess with our established ThisQInterval and LastQTime (ScheduleImmediately is false) |
4586 | // In cases 2 and 3 we do want to cause the question to be resent immediately (ScheduleImmediately is true) | | 4584 | // In cases 2 and 3 we do want to cause the question to be resent immediately (ScheduleImmediately is true) |
4587 | mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question, mDNSBool ScheduleImmediately) | | 4585 | mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question, mDNSBool ScheduleImmediately) |
4588 | { | | 4586 | { |
4589 | // For now this AutoTunnel stuff is specific to Mac OS X. | | 4587 | // For now this AutoTunnel stuff is specific to Mac OS X. |
4590 | // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer | | 4588 | // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer |
4591 | #if APPLE_OSX_mDNSResponder | | 4589 | #if APPLE_OSX_mDNSResponder |
4592 | // Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally. | | 4590 | // Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally. |
4593 | // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the | | 4591 | // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the |
4594 | // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel. | | 4592 | // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel. |
4595 | // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then | | 4593 | // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then |
4596 | // returns results for both at the same time. If we are looking for the _autotunnel6 record, then skip this logic | | 4594 | // returns results for both at the same time. If we are looking for the _autotunnel6 record, then skip this logic |
4597 | // as this would trigger looking up _autotunnel6._autotunnel6 and end up failing the original query. | | 4595 | // as this would trigger looking up _autotunnel6._autotunnel6 and end up failing the original query. |
4598 | | | 4596 | |
4599 | if (RRTypeIsAddressType(question->qtype) && PrivateQuery(question) && | | 4597 | if (RRTypeIsAddressType(question->qtype) && PrivateQuery(question) && |
4600 | !SameDomainLabel(question->qname.c, (const mDNSu8 *)"\x0c_autotunnel6")&& question->QuestionCallback != AutoTunnelCallback) | | 4598 | !SameDomainLabel(question->qname.c, (const mDNSu8 *)"\x0c_autotunnel6")&& question->QuestionCallback != AutoTunnelCallback) |
4601 | { | | 4599 | { |
4602 | question->NoAnswer = NoAnswer_Suspended; | | 4600 | question->NoAnswer = NoAnswer_Suspended; |
4603 | AddNewClientTunnel(m, question); | | 4601 | AddNewClientTunnel(m, question); |
4604 | return; | | 4602 | return; |
4605 | } | | 4603 | } |
4606 | #endif // APPLE_OSX_mDNSResponder | | 4604 | #endif // APPLE_OSX_mDNSResponder |
4607 | | | 4605 | |
4608 | if (!question->DuplicateOf) | | 4606 | if (!question->DuplicateOf) |
4609 | { | | 4607 | { |
4610 | debugf("ActivateUnicastQuery: %##s %s%s%s", | | 4608 | debugf("ActivateUnicastQuery: %##s %s%s%s", |
4611 | question->qname.c, DNSTypeName(question->qtype), PrivateQuery(question) ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : ""); | | 4609 | question->qname.c, DNSTypeName(question->qtype), PrivateQuery(question) ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : ""); |
4612 | question->CNAMEReferrals = 0; | | 4610 | question->CNAMEReferrals = 0; |
4613 | if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; } | | 4611 | if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; } |
4614 | if (question->LongLived) | | 4612 | if (question->LongLived) |
4615 | { | | 4613 | { |
4616 | question->state = LLQ_InitialRequest; | | 4614 | question->state = LLQ_InitialRequest; |
4617 | question->id = zeroOpaque64; | | 4615 | question->id = zeroOpaque64; |
4618 | question->servPort = zeroIPPort; | | 4616 | question->servPort = zeroIPPort; |
4619 | if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; } | | 4617 | if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; } |
4620 | } | | 4618 | } |
4621 | // If the question has local answers, then we don't want answers from outside | | 4619 | // If the question has local answers, then we don't want answers from outside |
4622 | if (ScheduleImmediately && !QuestionHasLocalAnswers(m, question)) | | 4620 | if (ScheduleImmediately && !QuestionHasLocalAnswers(m, question)) |
4623 | { | | 4621 | { |
4624 | question->ThisQInterval = InitialQuestionInterval; | | 4622 | question->ThisQInterval = InitialQuestionInterval; |
4625 | question->LastQTime = m->timenow - question->ThisQInterval; | | 4623 | question->LastQTime = m->timenow - question->ThisQInterval; |
4626 | SetNextQueryTime(m, question); | | 4624 | SetNextQueryTime(m, question); |
4627 | } | | 4625 | } |
4628 | } | | 4626 | } |
4629 | } | | 4627 | } |
4630 | | | 4628 | |
4631 | // Caller should hold the lock | | 4629 | // Caller should hold the lock |
4632 | mDNSexport void mDNSCoreRestartAddressQueries(mDNS *const m, mDNSBool SearchDomainsChanged, FlushCache flushCacheRecords, | | 4630 | mDNSexport void mDNSCoreRestartAddressQueries(mDNS *const m, mDNSBool SearchDomainsChanged, FlushCache flushCacheRecords, |
4633 | CallbackBeforeStartQuery BeforeStartCallback, void *context) | | 4631 | CallbackBeforeStartQuery BeforeStartCallback, void *context) |
4634 | { | | 4632 | { |
4635 | DNSQuestion *q; | | 4633 | DNSQuestion *q; |
4636 | DNSQuestion *restart = mDNSNULL; | | 4634 | DNSQuestion *restart = mDNSNULL; |
4637 | | | 4635 | |
4638 | if (!m->mDNS_busy) LogMsg("mDNSCoreRestartAddressQueries: ERROR!! Lock not held"); | | 4636 | if (!m->mDNS_busy) LogMsg("mDNSCoreRestartAddressQueries: ERROR!! Lock not held"); |
4639 | | | 4637 | |
4640 | // 1. Flush the cache records | | 4638 | // 1. Flush the cache records |
4641 | if (flushCacheRecords) flushCacheRecords(m); | | 4639 | if (flushCacheRecords) flushCacheRecords(m); |
4642 | | | 4640 | |
4643 | // 2. Even though we may have purged the cache records above, before it can generate RMV event | | 4641 | // 2. Even though we may have purged the cache records above, before it can generate RMV event |
4644 | // we are going to stop the question. Hence we need to deliver the RMV event before we | | 4642 | // we are going to stop the question. Hence we need to deliver the RMV event before we |
4645 | // stop the question. | | 4643 | // stop the question. |
4646 | // | | 4644 | // |
4647 | // CurrentQuestion is used by RmvEventsForQuestion below. While delivering RMV events, the | | 4645 | // CurrentQuestion is used by RmvEventsForQuestion below. While delivering RMV events, the |
4648 | // application callback can potentially stop the current question (detected by CurrentQuestion) or | | 4646 | // application callback can potentially stop the current question (detected by CurrentQuestion) or |
4649 | // *any* other question which could be the next one that we may process here. RestartQuestion | | 4647 | // *any* other question which could be the next one that we may process here. RestartQuestion |
4650 | // points to the "next" question which will be automatically advanced in mDNS_StopQuery_internal | | 4648 | // points to the "next" question which will be automatically advanced in mDNS_StopQuery_internal |
4651 | // if the "next" question is stopped while the CurrentQuestion is stopped | | 4649 | // if the "next" question is stopped while the CurrentQuestion is stopped |
4652 | | | 4650 | |
4653 | if (m->RestartQuestion) | | 4651 | if (m->RestartQuestion) |
4654 | LogMsg("mDNSCoreRestartAddressQueries: ERROR!! m->RestartQuestion already set: %##s (%s)", | | 4652 | LogMsg("mDNSCoreRestartAddressQueries: ERROR!! m->RestartQuestion already set: %##s (%s)", |
4655 | m->RestartQuestion->qname.c, DNSTypeName(m->RestartQuestion->qtype)); | | 4653 | m->RestartQuestion->qname.c, DNSTypeName(m->RestartQuestion->qtype)); |
4656 | | | 4654 | |
4657 | m->RestartQuestion = m->Questions; | | 4655 | m->RestartQuestion = m->Questions; |
4658 | while (m->RestartQuestion) | | 4656 | while (m->RestartQuestion) |
4659 | { | | 4657 | { |
4660 | q = m->RestartQuestion; | | 4658 | q = m->RestartQuestion; |
4661 | m->RestartQuestion = q->next; | | 4659 | m->RestartQuestion = q->next; |
4662 | // GetZoneData questions are referenced by other questions (original query that started the GetZoneData | | 4660 | // GetZoneData questions are referenced by other questions (original query that started the GetZoneData |
4663 | // question) through their "nta" pointer. Normally when the original query stops, it stops the | | 4661 | // question) through their "nta" pointer. Normally when the original query stops, it stops the |
4664 | // GetZoneData question and also frees the memory (See CancelGetZoneData). If we stop the GetZoneData | | 4662 | // GetZoneData question and also frees the memory (See CancelGetZoneData). If we stop the GetZoneData |
4665 | // question followed by the original query that refers to this GetZoneData question, we will end up | | 4663 | // question followed by the original query that refers to this GetZoneData question, we will end up |
4666 | // freeing the GetZoneData question and then start the "freed" question at the end. | | 4664 | // freeing the GetZoneData question and then start the "freed" question at the end. |
4667 | | | 4665 | |
4668 | if (IsGetZoneDataQuestion(q)) | | 4666 | if (IsGetZoneDataQuestion(q)) |
4669 | { | | 4667 | { |
4670 | DNSQuestion *refq = q->next; | | 4668 | DNSQuestion *refq = q->next; |
4671 | LogInfo("mDNSCoreRestartAddressQueries: Skipping GetZoneDataQuestion %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype)); | | 4669 | LogInfo("mDNSCoreRestartAddressQueries: Skipping GetZoneDataQuestion %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype)); |
4672 | // debug stuff, we just try to find the referencing question and don't do much with it | | 4670 | // debug stuff, we just try to find the referencing question and don't do much with it |
4673 | while (refq) | | 4671 | while (refq) |
4674 | { | | 4672 | { |
4675 | if (q == &refq->nta->question) | | 4673 | if (q == &refq->nta->question) |
4676 | { | | 4674 | { |
4677 | LogInfo("mDNSCoreRestartAddressQueries: Question %p %##s (%s) referring to GetZoneDataQuestion %p, not stopping", refq, refq->qname.c, DNSTypeName(refq->qtype), q); | | 4675 | LogInfo("mDNSCoreRestartAddressQueries: Question %p %##s (%s) referring to GetZoneDataQuestion %p, not stopping", refq, refq->qname.c, DNSTypeName(refq->qtype), q); |
4678 | } | | 4676 | } |
4679 | refq = refq->next; | | 4677 | refq = refq->next; |
4680 | } | | 4678 | } |
4681 | continue; | | 4679 | continue; |
4682 | } | | 4680 | } |
4683 | | | 4681 | |
4684 | // This function is called when /etc/hosts changes and that could affect A, AAAA and CNAME queries | | 4682 | // This function is called when /etc/hosts changes and that could affect A, AAAA and CNAME queries |
4685 | if (q->qtype != kDNSType_A && q->qtype != kDNSType_AAAA && q->qtype != kDNSType_CNAME) continue; | | 4683 | if (q->qtype != kDNSType_A && q->qtype != kDNSType_AAAA && q->qtype != kDNSType_CNAME) continue; |
4686 | | | 4684 | |
4687 | // If the search domains did not change, then we restart all the queries. Otherwise, only | | 4685 | // If the search domains did not change, then we restart all the queries. Otherwise, only |
4688 | // for queries for which we "might" have appended search domains ("might" because we may | | 4686 | // for queries for which we "might" have appended search domains ("might" because we may |
4689 | // find results before we apply search domains even though AppendSearchDomains is set to 1) | | 4687 | // find results before we apply search domains even though AppendSearchDomains is set to 1) |
4690 | if (!SearchDomainsChanged || q->AppendSearchDomains) | | 4688 | if (!SearchDomainsChanged || q->AppendSearchDomains) |
4691 | { | | 4689 | { |
4692 | // NOTE: CacheRecordRmvEventsForQuestion will not generate RMV events for queries that have non-zero | | 4690 | // NOTE: CacheRecordRmvEventsForQuestion will not generate RMV events for queries that have non-zero |
4693 | // LOAddressAnswers. Hence it is important that we call CacheRecordRmvEventsForQuestion before | | 4691 | // LOAddressAnswers. Hence it is important that we call CacheRecordRmvEventsForQuestion before |
4694 | // LocalRecordRmvEventsForQuestion (which decrements LOAddressAnswers). Let us say that | | 4692 | // LocalRecordRmvEventsForQuestion (which decrements LOAddressAnswers). Let us say that |
4695 | // /etc/hosts has an A Record for web.apple.com. Any queries for web.apple.com will be answered locally. | | 4693 | // /etc/hosts has an A Record for web.apple.com. Any queries for web.apple.com will be answered locally. |
4696 | // But this can't prevent a CNAME/AAAA query to not to be sent on the wire. When it is sent on the wire, | | 4694 | // But this can't prevent a CNAME/AAAA query to not to be sent on the wire. When it is sent on the wire, |
4697 | // it could create cache entries. When we are restarting queries, we can't deliver the cache RMV events | | 4695 | // it could create cache entries. When we are restarting queries, we can't deliver the cache RMV events |
4698 | // for the original query using these cache entries as ADDs were never delivered using these cache | | 4696 | // for the original query using these cache entries as ADDs were never delivered using these cache |
4699 | // entries and hence this order is needed. | | 4697 | // entries and hence this order is needed. |
4700 | | | 4698 | |
4701 | // If the query is suppressed, the RMV events won't be delivered | | 4699 | // If the query is suppressed, the RMV events won't be delivered |
4702 | if (!CacheRecordRmvEventsForQuestion(m, q)) { LogInfo("mDNSCoreRestartAddressQueries: Question deleted while delivering Cache Record RMV events"); continue; } | | 4700 | if (!CacheRecordRmvEventsForQuestion(m, q)) { LogInfo("mDNSCoreRestartAddressQueries: Question deleted while delivering Cache Record RMV events"); continue; } |
4703 | | | 4701 | |
4704 | // SuppressQuery status does not affect questions that are answered using local records | | 4702 | // SuppressQuery status does not affect questions that are answered using local records |
4705 | if (!LocalRecordRmvEventsForQuestion(m, q)) { LogInfo("mDNSCoreRestartAddressQueries: Question deleted while delivering Local Record RMV events"); continue; } | | 4703 | if (!LocalRecordRmvEventsForQuestion(m, q)) { LogInfo("mDNSCoreRestartAddressQueries: Question deleted while delivering Local Record RMV events"); continue; } |
4706 | | | 4704 | |
4707 | LogInfo("mDNSCoreRestartAddressQueries: Stop question %p %##s (%s), AppendSearchDomains %d, qnameOrig %p", q, | | 4705 | LogInfo("mDNSCoreRestartAddressQueries: Stop question %p %##s (%s), AppendSearchDomains %d, qnameOrig %p", q, |
4708 | q->qname.c, DNSTypeName(q->qtype), q->AppendSearchDomains, q->qnameOrig); | | 4706 | q->qname.c, DNSTypeName(q->qtype), q->AppendSearchDomains, q->qnameOrig); |
4709 | mDNS_StopQuery_internal(m, q); | | 4707 | mDNS_StopQuery_internal(m, q); |
4710 | // Reset state so that it looks like it was in the beginning i.e it should look at /etc/hosts, cache | | 4708 | // Reset state so that it looks like it was in the beginning i.e it should look at /etc/hosts, cache |
4711 | // and then search domains should be appended. At the beginning, qnameOrig was NULL. | | 4709 | // and then search domains should be appended. At the beginning, qnameOrig was NULL. |
4712 | if (q->qnameOrig) | | 4710 | if (q->qnameOrig) |
4713 | { | | 4711 | { |
4714 | LogInfo("mDNSCoreRestartAddressQueries: qnameOrig %##s", q->qnameOrig); | | 4712 | LogInfo("mDNSCoreRestartAddressQueries: qnameOrig %##s", q->qnameOrig); |
4715 | AssignDomainName(&q->qname, q->qnameOrig); | | 4713 | AssignDomainName(&q->qname, q->qnameOrig); |
4716 | mDNSPlatformMemFree(q->qnameOrig); | | 4714 | mDNSPlatformMemFree(q->qnameOrig); |
4717 | q->qnameOrig = mDNSNULL; | | 4715 | q->qnameOrig = mDNSNULL; |
4718 | q->RetryWithSearchDomains = ApplySearchDomainsFirst(q) ? 1 : 0; | | 4716 | q->RetryWithSearchDomains = ApplySearchDomainsFirst(q) ? 1 : 0; |
4719 | } | | 4717 | } |
4720 | q->SearchListIndex = 0; | | 4718 | q->SearchListIndex = 0; |
4721 | q->next = restart; | | 4719 | q->next = restart; |
4722 | restart = q; | | 4720 | restart = q; |
4723 | } | | 4721 | } |
4724 | } | | 4722 | } |
4725 | | | 4723 | |
4726 | // 3. Callback before we start the query | | 4724 | // 3. Callback before we start the query |
4727 | if (BeforeStartCallback) BeforeStartCallback(m, context); | | 4725 | if (BeforeStartCallback) BeforeStartCallback(m, context); |
4728 | | | 4726 | |
4729 | // 4. Restart all the stopped queries | | 4727 | // 4. Restart all the stopped queries |
4730 | while (restart) | | 4728 | while (restart) |
4731 | { | | 4729 | { |
4732 | q = restart; | | 4730 | q = restart; |
4733 | restart = restart->next; | | 4731 | restart = restart->next; |
4734 | q->next = mDNSNULL; | | 4732 | q->next = mDNSNULL; |
4735 | LogInfo("mDNSCoreRestartAddressQueries: Start question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype)); | | 4733 | LogInfo("mDNSCoreRestartAddressQueries: Start question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype)); |
4736 | mDNS_StartQuery_internal(m, q); | | 4734 | mDNS_StartQuery_internal(m, q); |
4737 | } | | 4735 | } |
4738 | } | | 4736 | } |
4739 | | | 4737 | |
4740 | mDNSexport void mDNSCoreRestartQueries(mDNS *const m) | | 4738 | mDNSexport void mDNSCoreRestartQueries(mDNS *const m) |
4741 | { | | 4739 | { |
4742 | DNSQuestion *q; | | 4740 | DNSQuestion *q; |
4743 | | | 4741 | |
4744 | #ifndef UNICAST_DISABLED | | 4742 | #ifndef UNICAST_DISABLED |
4745 | // Retrigger all our uDNS questions | | 4743 | // Retrigger all our uDNS questions |
4746 | if (m->CurrentQuestion) | | 4744 | if (m->CurrentQuestion) |
4747 | LogMsg("mDNSCoreRestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", | | 4745 | LogMsg("mDNSCoreRestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", |
4748 | m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); | | 4746 | m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); |
4749 | m->CurrentQuestion = m->Questions; | | 4747 | m->CurrentQuestion = m->Questions; |
4750 | while (m->CurrentQuestion) | | 4748 | while (m->CurrentQuestion) |
4751 | { | | 4749 | { |
4752 | q = m->CurrentQuestion; | | 4750 | q = m->CurrentQuestion; |
4753 | m->CurrentQuestion = m->CurrentQuestion->next; | | 4751 | m->CurrentQuestion = m->CurrentQuestion->next; |
4754 | if (!mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q)) ActivateUnicastQuery(m, q, mDNStrue); | | 4752 | if (!mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q)) ActivateUnicastQuery(m, q, mDNStrue); |
4755 | } | | 4753 | } |
4756 | #endif | | 4754 | #endif |
4757 | | | 4755 | |
4758 | // Retrigger all our mDNS questions | | 4756 | // Retrigger all our mDNS questions |
4759 | for (q = m->Questions; q; q=q->next) // Scan our list of questions | | 4757 | for (q = m->Questions; q; q=q->next) // Scan our list of questions |
4760 | if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q)) | | 4758 | if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q)) |
4761 | { | | 4759 | { |
4762 | q->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question | | 4760 | q->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question |
4763 | q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it | | 4761 | q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it |
4764 | q->LastQTime = m->timenow - q->ThisQInterval; | | 4762 | q->LastQTime = m->timenow - q->ThisQInterval; |
4765 | q->RecentAnswerPkts = 0; | | 4763 | q->RecentAnswerPkts = 0; |
4766 | ExpireDupSuppressInfo(q->DupSuppress, m->timenow); | | 4764 | ExpireDupSuppressInfo(q->DupSuppress, m->timenow); |
4767 | m->NextScheduledQuery = m->timenow; | | 4765 | m->NextScheduledQuery = m->timenow; |
4768 | } | | 4766 | } |
4769 | } | | 4767 | } |
4770 | | | 4768 | |
4771 | // *************************************************************************** | | 4769 | // *************************************************************************** |
4772 | #if COMPILER_LIKES_PRAGMA_MARK | | 4770 | #if COMPILER_LIKES_PRAGMA_MARK |
4773 | #pragma mark - | | 4771 | #pragma mark - |
4774 | #pragma mark - Power Management (Sleep/Wake) | | 4772 | #pragma mark - Power Management (Sleep/Wake) |
4775 | #endif | | 4773 | #endif |
4776 | | | 4774 | |
4777 | mDNSexport void mDNS_UpdateAllowSleep(mDNS *const m) | | 4775 | mDNSexport void mDNS_UpdateAllowSleep(mDNS *const m) |
4778 | { | | 4776 | { |
4779 | #ifndef IDLESLEEPCONTROL_DISABLED | | 4777 | #ifndef IDLESLEEPCONTROL_DISABLED |
4780 | mDNSBool allowSleep = mDNStrue; | | 4778 | mDNSBool allowSleep = mDNStrue; |
4781 | char reason[128]; | | 4779 | char reason[128]; |
4782 | | | 4780 | |
4783 | reason[0] = 0; | | 4781 | reason[0] = 0; |
4784 | | | 4782 | |
4785 | if (m->SystemSleepOnlyIfWakeOnLAN) | | 4783 | if (m->SystemSleepOnlyIfWakeOnLAN) |
4786 | { | | 4784 | { |
4787 | // Don't sleep if we are a proxy for any services | | 4785 | // Don't sleep if we are a proxy for any services |
4788 | if (m->ProxyRecords) | | 4786 | if (m->ProxyRecords) |
4789 | { | | 4787 | { |
4790 | allowSleep = mDNSfalse; | | 4788 | allowSleep = mDNSfalse; |
4791 | mDNS_snprintf(reason, sizeof(reason), "sleep proxy for %d records", m->ProxyRecords); | | 4789 | mDNS_snprintf(reason, sizeof(reason), "sleep proxy for %d records", m->ProxyRecords); |
4792 | LogInfo("Sleep disabled because we are proxying %d records", m->ProxyRecords); | | 4790 | LogInfo("Sleep disabled because we are proxying %d records", m->ProxyRecords); |
4793 | } | | 4791 | } |
4794 | | | 4792 | |
4795 | if (allowSleep && mDNSCoreHaveAdvertisedMulticastServices(m)) | | 4793 | if (allowSleep && mDNSCoreHaveAdvertisedMulticastServices(m)) |
4796 | { | | 4794 | { |
4797 | // Scan the list of active interfaces | | 4795 | // Scan the list of active interfaces |
4798 | NetworkInterfaceInfo *intf; | | 4796 | NetworkInterfaceInfo *intf; |
4799 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) | | 4797 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) |
4800 | { | | 4798 | { |
4801 | if (intf->McastTxRx && !intf->Loopback) | | 4799 | if (intf->McastTxRx && !intf->Loopback) |
4802 | { | | 4800 | { |
4803 | // Disallow sleep if this interface doesn't support NetWake | | 4801 | // Disallow sleep if this interface doesn't support NetWake |
4804 | if (!intf->NetWake) | | 4802 | if (!intf->NetWake) |
4805 | { | | 4803 | { |
4806 | allowSleep = mDNSfalse; | | 4804 | allowSleep = mDNSfalse; |
4807 | mDNS_snprintf(reason, sizeof(reason), "%s does not support NetWake", intf->ifname); | | 4805 | mDNS_snprintf(reason, sizeof(reason), "%s does not support NetWake", intf->ifname); |
4808 | LogInfo("Sleep disabled because %s does not support NetWake", intf->ifname); | | 4806 | LogInfo("Sleep disabled because %s does not support NetWake", intf->ifname); |
4809 | break; | | 4807 | break; |
4810 | } | | 4808 | } |
4811 | | | 4809 | |
4812 | // Disallow sleep if there is no sleep proxy server | | 4810 | // Disallow sleep if there is no sleep proxy server |
4813 | if (FindSPSInCache1(m, &intf->NetWakeBrowse, mDNSNULL, mDNSNULL) == mDNSNULL) | | 4811 | if (FindSPSInCache1(m, &intf->NetWakeBrowse, mDNSNULL, mDNSNULL) == mDNSNULL) |
4814 | { | | 4812 | { |
4815 | allowSleep = mDNSfalse; | | 4813 | allowSleep = mDNSfalse; |
4816 | mDNS_snprintf(reason, sizeof(reason), "%s does not support NetWake", intf->ifname); | | 4814 | mDNS_snprintf(reason, sizeof(reason), "%s does not support NetWake", intf->ifname); |
4817 | LogInfo("Sleep disabled because %s has no sleep proxy", intf->ifname); | | 4815 | LogInfo("Sleep disabled because %s has no sleep proxy", intf->ifname); |
4818 | break; | | 4816 | break; |
4819 | } | | 4817 | } |
4820 | } | | 4818 | } |
4821 | } | | 4819 | } |
4822 | } | | 4820 | } |
4823 | } | | 4821 | } |
4824 | | | 4822 | |
4825 | // Call the platform code to enable/disable sleep | | 4823 | // Call the platform code to enable/disable sleep |
4826 | mDNSPlatformSetAllowSleep(m, allowSleep, reason); | | 4824 | mDNSPlatformSetAllowSleep(m, allowSleep, reason); |
4827 | #endif /* !defined(IDLESLEEPCONTROL_DISABLED) */ | | 4825 | #endif /* !defined(IDLESLEEPCONTROL_DISABLED) */ |
4828 | } | | 4826 | } |
4829 | | | 4827 | |
4830 | mDNSlocal void SendSPSRegistrationForOwner(mDNS *const m, NetworkInterfaceInfo *const intf, const mDNSOpaque16 id, const OwnerOptData *const owner) | | 4828 | mDNSlocal void SendSPSRegistrationForOwner(mDNS *const m, NetworkInterfaceInfo *const intf, const mDNSOpaque16 id, const OwnerOptData *const owner) |
4831 | { | | 4829 | { |
4832 | const int optspace = DNSOpt_Header_Space + DNSOpt_LeaseData_Space + DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC); | | 4830 | const int optspace = DNSOpt_Header_Space + DNSOpt_LeaseData_Space + DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC); |
4833 | const int sps = intf->NextSPSAttempt / 3; | | 4831 | const int sps = intf->NextSPSAttempt / 3; |
4834 | AuthRecord *rr; | | 4832 | AuthRecord *rr; |
4835 | | | 4833 | |
4836 | if (!intf->SPSAddr[sps].type) | | 4834 | if (!intf->SPSAddr[sps].type) |
4837 | { | | 4835 | { |
4838 | intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond; | | 4836 | intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond; |
4839 | if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0) | | 4837 | if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0) |
4840 | m->NextScheduledSPRetry = intf->NextSPSAttemptTime; | | 4838 | m->NextScheduledSPRetry = intf->NextSPSAttemptTime; |
4841 | LogSPS("SendSPSRegistration: %s SPS %d (%d) %##s not yet resolved", intf->ifname, intf->NextSPSAttempt, sps, intf->NetWakeResolve[sps].qname.c); | | 4839 | LogSPS("SendSPSRegistration: %s SPS %d (%d) %##s not yet resolved", intf->ifname, intf->NextSPSAttempt, sps, intf->NetWakeResolve[sps].qname.c); |
4842 | goto exit; | | 4840 | goto exit; |
4843 | } | | 4841 | } |
4844 | | | 4842 | |
4845 | // Mark our mDNS records (not unicast records) for transfer to SPS | | 4843 | // Mark our mDNS records (not unicast records) for transfer to SPS |
4846 | if (mDNSOpaque16IsZero(id)) | | 4844 | if (mDNSOpaque16IsZero(id)) |
4847 | for (rr = m->ResourceRecords; rr; rr=rr->next) | | 4845 | for (rr = m->ResourceRecords; rr; rr=rr->next) |
4848 | if (rr->resrec.RecordType > kDNSRecordTypeDeregistering) | | 4846 | if (rr->resrec.RecordType > kDNSRecordTypeDeregistering) |
4849 | if (rr->resrec.InterfaceID == intf->InterfaceID || (!rr->resrec.InterfaceID && (rr->ForceMCast || IsLocalDomain(rr->resrec.name)))) | | 4847 | if (rr->resrec.InterfaceID == intf->InterfaceID || (!rr->resrec.InterfaceID && (rr->ForceMCast || IsLocalDomain(rr->resrec.name)))) |
4850 | if (mDNSPlatformMemSame(owner, &rr->WakeUp, sizeof(*owner))) | | 4848 | if (mDNSPlatformMemSame(owner, &rr->WakeUp, sizeof(*owner))) |
4851 | rr->SendRNow = mDNSInterfaceMark; // mark it now | | 4849 | rr->SendRNow = mDNSInterfaceMark; // mark it now |
4852 | | | 4850 | |
4853 | while (1) | | 4851 | while (1) |
4854 | { | | 4852 | { |
4855 | mDNSu8 *p = m->omsg.data; | | 4853 | mDNSu8 *p = m->omsg.data; |
4856 | // To comply with RFC 2782, PutResourceRecord suppresses name compression for SRV records in unicast updates. | | 4854 | // To comply with RFC 2782, PutResourceRecord suppresses name compression for SRV records in unicast updates. |
4857 | // For now we follow that same logic for SPS registrations too. | | 4855 | // For now we follow that same logic for SPS registrations too. |
4858 | // If we decide to compress SRV records in SPS registrations in the future, we can achieve that by creating our | | 4856 | // If we decide to compress SRV records in SPS registrations in the future, we can achieve that by creating our |
4859 | // initial DNSMessage with h.flags set to zero, and then update it to UpdateReqFlags right before sending the packet. | | 4857 | // initial DNSMessage with h.flags set to zero, and then update it to UpdateReqFlags right before sending the packet. |
4860 | InitializeDNSMessage(&m->omsg.h, mDNSOpaque16IsZero(id) ? mDNS_NewMessageID(m) : id, UpdateReqFlags); | | 4858 | InitializeDNSMessage(&m->omsg.h, mDNSOpaque16IsZero(id) ? mDNS_NewMessageID(m) : id, UpdateReqFlags); |
4861 | | | 4859 | |
4862 | for (rr = m->ResourceRecords; rr; rr=rr->next) | | 4860 | for (rr = m->ResourceRecords; rr; rr=rr->next) |
4863 | if (rr->SendRNow || (!mDNSOpaque16IsZero(id) && !AuthRecord_uDNS(rr) && mDNSSameOpaque16(rr->updateid, id) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0)) | | 4861 | if (rr->SendRNow || (!mDNSOpaque16IsZero(id) && !AuthRecord_uDNS(rr) && mDNSSameOpaque16(rr->updateid, id) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0)) |
4864 | if (mDNSPlatformMemSame(owner, &rr->WakeUp, sizeof(*owner))) | | 4862 | if (mDNSPlatformMemSame(owner, &rr->WakeUp, sizeof(*owner))) |
4865 | { | | 4863 | { |
4866 | mDNSu8 *newptr; | | 4864 | mDNSu8 *newptr; |
4867 | const mDNSu8 *const limit = m->omsg.data + (m->omsg.h.mDNS_numUpdates ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData) - optspace; | | 4865 | const mDNSu8 *const limit = m->omsg.data + (m->omsg.h.mDNS_numUpdates ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData) - optspace; |
4868 | if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) | | 4866 | if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) |
4869 | rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it | | 4867 | rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it |
4870 | newptr = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit); | | 4868 | newptr = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit); |
4871 | rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state | | 4869 | rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state |
4872 | if (!newptr) | | 4870 | if (!newptr) |
4873 | LogSPS("SendSPSRegistration put %s FAILED %d/%d %s", intf->ifname, p - m->omsg.data, limit - m->omsg.data, ARDisplayString(m, rr)); | | 4871 | LogSPS("SendSPSRegistration put %s FAILED %d/%d %s", intf->ifname, p - m->omsg.data, limit - m->omsg.data, ARDisplayString(m, rr)); |
4874 | else | | 4872 | else |
4875 | { | | 4873 | { |
4876 | LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, rr)); | | 4874 | LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, rr)); |
4877 | rr->SendRNow = mDNSNULL; | | 4875 | rr->SendRNow = mDNSNULL; |
4878 | rr->ThisAPInterval = mDNSPlatformOneSecond; | | 4876 | rr->ThisAPInterval = mDNSPlatformOneSecond; |
4879 | rr->LastAPTime = m->timenow; | | 4877 | rr->LastAPTime = m->timenow; |
4880 | rr->updateid = m->omsg.h.id; | | 4878 | rr->updateid = m->omsg.h.id; |
4881 | if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0) | | 4879 | if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0) |
4882 | m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval); | | 4880 | m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval); |
4883 | p = newptr; | | 4881 | p = newptr; |
4884 | } | | 4882 | } |
4885 | } | | 4883 | } |
4886 | | | 4884 | |
4887 | if (!m->omsg.h.mDNS_numUpdates) break; | | 4885 | if (!m->omsg.h.mDNS_numUpdates) break; |
4888 | else | | 4886 | else |
4889 | { | | 4887 | { |
4890 | AuthRecord opt; | | 4888 | AuthRecord opt; |
4891 | mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); | | 4889 | mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); |
4892 | opt.resrec.rrclass = NormalMaxDNSMessageData; | | 4890 | opt.resrec.rrclass = NormalMaxDNSMessageData; |
4893 | opt.resrec.rdlength = sizeof(rdataOPT) * 2; // Two options in this OPT record | | 4891 | opt.resrec.rdlength = sizeof(rdataOPT) * 2; // Two options in this OPT record |
4894 | opt.resrec.rdestimate = sizeof(rdataOPT) * 2; | | 4892 | opt.resrec.rdestimate = sizeof(rdataOPT) * 2; |
4895 | opt.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease; | | 4893 | opt.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease; |
4896 | opt.resrec.rdata->u.opt[0].optlen = DNSOpt_LeaseData_Space - 4; | | 4894 | opt.resrec.rdata->u.opt[0].optlen = DNSOpt_LeaseData_Space - 4; |
4897 | opt.resrec.rdata->u.opt[0].u.updatelease = DEFAULT_UPDATE_LEASE; | | 4895 | opt.resrec.rdata->u.opt[0].u.updatelease = DEFAULT_UPDATE_LEASE; |
4898 | if (!owner->HMAC.l[0]) // If no owner data, | | 4896 | if (!owner->HMAC.l[0]) // If no owner data, |
4899 | SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[1]); // use our own interface information | | 4897 | SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[1]); // use our own interface information |
4900 | else // otherwise, use the owner data we were given | | 4898 | else // otherwise, use the owner data we were given |
4901 | { | | 4899 | { |
4902 | opt.resrec.rdata->u.opt[1].u.owner = *owner; | | 4900 | opt.resrec.rdata->u.opt[1].u.owner = *owner; |
4903 | opt.resrec.rdata->u.opt[1].opt = kDNSOpt_Owner; | | 4901 | opt.resrec.rdata->u.opt[1].opt = kDNSOpt_Owner; |
4904 | opt.resrec.rdata->u.opt[1].optlen = DNSOpt_Owner_Space(&owner->HMAC, &owner->IMAC) - 4; | | 4902 | opt.resrec.rdata->u.opt[1].optlen = DNSOpt_Owner_Space(&owner->HMAC, &owner->IMAC) - 4; |
4905 | } | | 4903 | } |
4906 | LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, &opt)); | | 4904 | LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, &opt)); |
4907 | p = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData); | | 4905 | p = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData); |
4908 | if (!p) | | 4906 | if (!p) |
4909 | LogMsg("SendSPSRegistration: Failed to put OPT record (%d updates) %s", m->omsg.h.mDNS_numUpdates, ARDisplayString(m, &opt)); | | 4907 | LogMsg("SendSPSRegistration: Failed to put OPT record (%d updates) %s", m->omsg.h.mDNS_numUpdates, ARDisplayString(m, &opt)); |
4910 | else | | 4908 | else |
4911 | { | | 4909 | { |
4912 | mStatus err; | | 4910 | mStatus err; |
4913 | | | 4911 | |
4914 | LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf->ifname, intf->NextSPSAttempt, sps, | | 4912 | LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf->ifname, intf->NextSPSAttempt, sps, |
4915 | mDNSVal16(m->omsg.h.id), m->omsg.h.mDNS_numUpdates, p - m->omsg.data, &intf->SPSAddr[sps], mDNSVal16(intf->SPSPort[sps])); | | 4913 | mDNSVal16(m->omsg.h.id), m->omsg.h.mDNS_numUpdates, p - m->omsg.data, &intf->SPSAddr[sps], mDNSVal16(intf->SPSPort[sps])); |
4916 | // if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID; // For simulating packet loss | | 4914 | // if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID; // For simulating packet loss |
4917 | err = mDNSSendDNSMessage(m, &m->omsg, p, intf->InterfaceID, mDNSNULL, &intf->SPSAddr[sps], intf->SPSPort[sps], mDNSNULL, mDNSNULL); | | 4915 | err = mDNSSendDNSMessage(m, &m->omsg, p, intf->InterfaceID, mDNSNULL, &intf->SPSAddr[sps], intf->SPSPort[sps], mDNSNULL, mDNSNULL); |
4918 | if (err) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err); | | 4916 | if (err) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err); |
4919 | if (err && intf->SPSAddr[sps].type == mDNSAddrType_IPv6 && intf->NetWakeResolve[sps].ThisQInterval == -1) | | 4917 | if (err && intf->SPSAddr[sps].type == mDNSAddrType_IPv6 && intf->NetWakeResolve[sps].ThisQInterval == -1) |
4920 | { | | 4918 | { |
4921 | LogSPS("SendSPSRegistration %d %##s failed to send to IPv6 address; will try IPv4 instead", sps, intf->NetWakeResolve[sps].qname.c); | | 4919 | LogSPS("SendSPSRegistration %d %##s failed to send to IPv6 address; will try IPv4 instead", sps, intf->NetWakeResolve[sps].qname.c); |
4922 | intf->NetWakeResolve[sps].qtype = kDNSType_A; | | 4920 | intf->NetWakeResolve[sps].qtype = kDNSType_A; |
4923 | mDNS_StartQuery_internal(m, &intf->NetWakeResolve[sps]); | | 4921 | mDNS_StartQuery_internal(m, &intf->NetWakeResolve[sps]); |
4924 | return; | | 4922 | return; |
4925 | } | | 4923 | } |
4926 | } | | 4924 | } |
4927 | } | | 4925 | } |
4928 | } | | 4926 | } |
4929 | | | 4927 | |
4930 | intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond * 10; // If successful, update NextSPSAttemptTime | | 4928 | intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond * 10; // If successful, update NextSPSAttemptTime |
4931 | | | 4929 | |
4932 | exit: | | 4930 | exit: |
4933 | if (mDNSOpaque16IsZero(id) && intf->NextSPSAttempt < 8) intf->NextSPSAttempt++; | | 4931 | if (mDNSOpaque16IsZero(id) && intf->NextSPSAttempt < 8) intf->NextSPSAttempt++; |
4934 | } | | 4932 | } |
4935 | | | 4933 | |
4936 | mDNSlocal mDNSBool RecordIsFirstOccurrenceOfOwner(mDNS *const m, const AuthRecord *const rr) | | 4934 | mDNSlocal mDNSBool RecordIsFirstOccurrenceOfOwner(mDNS *const m, const AuthRecord *const rr) |
4937 | { | | 4935 | { |
4938 | AuthRecord *ar; | | 4936 | AuthRecord *ar; |
4939 | for (ar = m->ResourceRecords; ar && ar != rr; ar=ar->next) | | 4937 | for (ar = m->ResourceRecords; ar && ar != rr; ar=ar->next) |
4940 | if (mDNSPlatformMemSame(&rr->WakeUp, &ar->WakeUp, sizeof(rr->WakeUp))) return mDNSfalse; | | 4938 | if (mDNSPlatformMemSame(&rr->WakeUp, &ar->WakeUp, sizeof(rr->WakeUp))) return mDNSfalse; |
4941 | return mDNStrue; | | 4939 | return mDNStrue; |
4942 | } | | 4940 | } |
4943 | | | 4941 | |
4944 | mDNSlocal void SendSPSRegistration(mDNS *const m, NetworkInterfaceInfo *const intf, const mDNSOpaque16 id) | | 4942 | mDNSlocal void SendSPSRegistration(mDNS *const m, NetworkInterfaceInfo *const intf, const mDNSOpaque16 id) |
4945 | { | | 4943 | { |
4946 | AuthRecord *ar; | | 4944 | AuthRecord *ar; |
4947 | OwnerOptData owner = zeroOwner; | | 4945 | OwnerOptData owner = zeroOwner; |
4948 | | | 4946 | |
4949 | SendSPSRegistrationForOwner(m, intf, id, &owner); | | 4947 | SendSPSRegistrationForOwner(m, intf, id, &owner); |
4950 | | | 4948 | |
4951 | for (ar = m->ResourceRecords; ar; ar=ar->next) | | 4949 | for (ar = m->ResourceRecords; ar; ar=ar->next) |
4952 | { | | 4950 | { |
4953 | if (!mDNSPlatformMemSame(&owner, &ar->WakeUp, sizeof(owner)) && RecordIsFirstOccurrenceOfOwner(m, ar)) | | 4951 | if (!mDNSPlatformMemSame(&owner, &ar->WakeUp, sizeof(owner)) && RecordIsFirstOccurrenceOfOwner(m, ar)) |
4954 | { | | 4952 | { |
4955 | owner = ar->WakeUp; | | 4953 | owner = ar->WakeUp; |
4956 | SendSPSRegistrationForOwner(m, intf, id, &owner); | | 4954 | SendSPSRegistrationForOwner(m, intf, id, &owner); |
4957 | } | | 4955 | } |
4958 | } | | 4956 | } |
4959 | } | | 4957 | } |
4960 | | | 4958 | |
4961 | // RetrySPSRegistrations is called from SendResponses, with the lock held | | 4959 | // RetrySPSRegistrations is called from SendResponses, with the lock held |
4962 | mDNSlocal void RetrySPSRegistrations(mDNS *const m) | | 4960 | mDNSlocal void RetrySPSRegistrations(mDNS *const m) |
4963 | { | | 4961 | { |
4964 | AuthRecord *rr; | | 4962 | AuthRecord *rr; |
4965 | NetworkInterfaceInfo *intf; | | 4963 | NetworkInterfaceInfo *intf; |
4966 | | | 4964 | |
4967 | // First make sure none of our interfaces' NextSPSAttemptTimes are inadvertently set to m->timenow + mDNSPlatformOneSecond * 10 | | 4965 | // First make sure none of our interfaces' NextSPSAttemptTimes are inadvertently set to m->timenow + mDNSPlatformOneSecond * 10 |
4968 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) | | 4966 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) |
4969 | if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10) | | 4967 | if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10) |
4970 | intf->NextSPSAttemptTime++; | | 4968 | intf->NextSPSAttemptTime++; |
4971 | | | 4969 | |
4972 | // Retry any record registrations that are due | | 4970 | // Retry any record registrations that are due |
4973 | for (rr = m->ResourceRecords; rr; rr=rr->next) | | 4971 | for (rr = m->ResourceRecords; rr; rr=rr->next) |
4974 | if (!AuthRecord_uDNS(rr) && !mDNSOpaque16IsZero(rr->updateid) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0) | | 4972 | if (!AuthRecord_uDNS(rr) && !mDNSOpaque16IsZero(rr->updateid) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0) |
4975 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) | | 4973 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) |
4976 | if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == intf->InterfaceID) | | 4974 | if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == intf->InterfaceID) |
4977 | { | | 4975 | { |
4978 | LogSPS("RetrySPSRegistrations: %s", ARDisplayString(m, rr)); | | 4976 | LogSPS("RetrySPSRegistrations: %s", ARDisplayString(m, rr)); |
4979 | SendSPSRegistration(m, intf, rr->updateid); | | 4977 | SendSPSRegistration(m, intf, rr->updateid); |
4980 | } | | 4978 | } |
4981 | | | 4979 | |
4982 | // For interfaces where we did an SPS registration attempt, increment intf->NextSPSAttempt | | 4980 | // For interfaces where we did an SPS registration attempt, increment intf->NextSPSAttempt |
4983 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) | | 4981 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) |
4984 | if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10 && intf->NextSPSAttempt < 8) | | 4982 | if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10 && intf->NextSPSAttempt < 8) |
4985 | intf->NextSPSAttempt++; | | 4983 | intf->NextSPSAttempt++; |
4986 | } | | 4984 | } |
4987 | | | 4985 | |
4988 | mDNSlocal void NetWakeResolve(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) | | 4986 | mDNSlocal void NetWakeResolve(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) |
4989 | { | | 4987 | { |
4990 | NetworkInterfaceInfo *intf = (NetworkInterfaceInfo *)question->QuestionContext; | | 4988 | NetworkInterfaceInfo *intf = (NetworkInterfaceInfo *)question->QuestionContext; |
4991 | int sps = (int)(question - intf->NetWakeResolve); | | 4989 | int sps = (int)(question - intf->NetWakeResolve); |
4992 | (void)m; // Unused | | 4990 | (void)m; // Unused |
4993 | LogSPS("NetWakeResolve: SPS: %d Add: %d %s", sps, AddRecord, RRDisplayString(m, answer)); | | 4991 | LogSPS("NetWakeResolve: SPS: %d Add: %d %s", sps, AddRecord, RRDisplayString(m, answer)); |
4994 | | | 4992 | |
4995 | if (!AddRecord) return; // Don't care about REMOVE events | | 4993 | if (!AddRecord) return; // Don't care about REMOVE events |
4996 | if (answer->rrtype != question->qtype) return; // Don't care about CNAMEs | | 4994 | if (answer->rrtype != question->qtype) return; // Don't care about CNAMEs |
4997 | | | 4995 | |
4998 | // if (answer->rrtype == kDNSType_AAAA && sps == 0) return; // To test failing to resolve sleep proxy's address | | 4996 | // if (answer->rrtype == kDNSType_AAAA && sps == 0) return; // To test failing to resolve sleep proxy's address |
4999 | | | 4997 | |
5000 | if (answer->rrtype == kDNSType_SRV) | | 4998 | if (answer->rrtype == kDNSType_SRV) |
5001 | { | | 4999 | { |
5002 | // 1. Got the SRV record; now look up the target host's IPv6 link-local address | | 5000 | // 1. Got the SRV record; now look up the target host's IPv6 link-local address |
5003 | mDNS_StopQuery(m, question); | | 5001 | mDNS_StopQuery(m, question); |
5004 | intf->SPSPort[sps] = answer->rdata->u.srv.port; | | 5002 | intf->SPSPort[sps] = answer->rdata->u.srv.port; |
5005 | AssignDomainName(&question->qname, &answer->rdata->u.srv.target); | | 5003 | AssignDomainName(&question->qname, &answer->rdata->u.srv.target); |
5006 | question->qtype = kDNSType_AAAA; | | 5004 | question->qtype = kDNSType_AAAA; |
5007 | mDNS_StartQuery(m, question); | | 5005 | mDNS_StartQuery(m, question); |
5008 | } | | 5006 | } |
5009 | else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == sizeof(mDNSv6Addr) && mDNSv6AddressIsLinkLocal(&answer->rdata->u.ipv6)) | | 5007 | else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == sizeof(mDNSv6Addr) && mDNSv6AddressIsLinkLocal(&answer->rdata->u.ipv6)) |
5010 | { | | 5008 | { |
5011 | // 2. Got the target host's IPv6 link-local address; record address and initiate an SPS registration if appropriate | | 5009 | // 2. Got the target host's IPv6 link-local address; record address and initiate an SPS registration if appropriate |
5012 | mDNS_StopQuery(m, question); | | 5010 | mDNS_StopQuery(m, question); |
5013 | question->ThisQInterval = -1; | | 5011 | question->ThisQInterval = -1; |
5014 | intf->SPSAddr[sps].type = mDNSAddrType_IPv6; | | 5012 | intf->SPSAddr[sps].type = mDNSAddrType_IPv6; |
5015 | intf->SPSAddr[sps].ip.v6 = answer->rdata->u.ipv6; | | 5013 | intf->SPSAddr[sps].ip.v6 = answer->rdata->u.ipv6; |
5016 | mDNS_Lock(m); | | 5014 | mDNS_Lock(m); |
5017 | if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID); // If we're ready for this result, use it now | | 5015 | if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID); // If we're ready for this result, use it now |
5018 | mDNS_Unlock(m); | | 5016 | mDNS_Unlock(m); |
5019 | } | | 5017 | } |
5020 | else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == 0) | | 5018 | else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == 0) |
5021 | { | | 5019 | { |
5022 | // 3. Got negative response -- target host apparently has IPv6 disabled -- so try looking up the target host's IPv4 address(es) instead | | 5020 | // 3. Got negative response -- target host apparently has IPv6 disabled -- so try looking up the target host's IPv4 address(es) instead |
5023 | mDNS_StopQuery(m, question); | | 5021 | mDNS_StopQuery(m, question); |
5024 | LogSPS("NetWakeResolve: SPS %d %##s has no IPv6 address, will try IPv4 instead", sps, question->qname.c); | | 5022 | LogSPS("NetWakeResolve: SPS %d %##s has no IPv6 address, will try IPv4 instead", sps, question->qname.c); |
5025 | question->qtype = kDNSType_A; | | 5023 | question->qtype = kDNSType_A; |
5026 | mDNS_StartQuery(m, question); | | 5024 | mDNS_StartQuery(m, question); |
5027 | } | | 5025 | } |
5028 | else if (answer->rrtype == kDNSType_A && answer->rdlength == sizeof(mDNSv4Addr)) | | 5026 | else if (answer->rrtype == kDNSType_A && answer->rdlength == sizeof(mDNSv4Addr)) |
5029 | { | | 5027 | { |
5030 | // 4. Got an IPv4 address for the target host; record address and initiate an SPS registration if appropriate | | 5028 | // 4. Got an IPv4 address for the target host; record address and initiate an SPS registration if appropriate |
5031 | mDNS_StopQuery(m, question); | | 5029 | mDNS_StopQuery(m, question); |
5032 | question->ThisQInterval = -1; | | 5030 | question->ThisQInterval = -1; |
5033 | intf->SPSAddr[sps].type = mDNSAddrType_IPv4; | | 5031 | intf->SPSAddr[sps].type = mDNSAddrType_IPv4; |
5034 | intf->SPSAddr[sps].ip.v4 = answer->rdata->u.ipv4; | | 5032 | intf->SPSAddr[sps].ip.v4 = answer->rdata->u.ipv4; |
5035 | mDNS_Lock(m); | | 5033 | mDNS_Lock(m); |
5036 | if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID); // If we're ready for this result, use it now | | 5034 | if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID); // If we're ready for this result, use it now |
5037 | mDNS_Unlock(m); | | 5035 | mDNS_Unlock(m); |
5038 | } | | 5036 | } |
5039 | } | | 5037 | } |
5040 | | | 5038 | |
5041 | mDNSexport mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m) | | 5039 | mDNSexport mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m) |
5042 | { | | 5040 | { |
5043 | AuthRecord *rr; | | 5041 | AuthRecord *rr; |
5044 | for (rr = m->ResourceRecords; rr; rr=rr->next) | | 5042 | for (rr = m->ResourceRecords; rr; rr=rr->next) |
5045 | if (rr->resrec.rrtype == kDNSType_SRV && !AuthRecord_uDNS(rr) && !mDNSSameIPPort(rr->resrec.rdata->u.srv.port, DiscardPort)) | | 5043 | if (rr->resrec.rrtype == kDNSType_SRV && !AuthRecord_uDNS(rr) && !mDNSSameIPPort(rr->resrec.rdata->u.srv.port, DiscardPort)) |
5046 | return mDNStrue; | | 5044 | return mDNStrue; |
5047 | return mDNSfalse; | | 5045 | return mDNSfalse; |
5048 | } | | 5046 | } |
5049 | | | 5047 | |
5050 | mDNSlocal void SendSleepGoodbyes(mDNS *const m) | | 5048 | mDNSlocal void SendSleepGoodbyes(mDNS *const m) |
5051 | { | | 5049 | { |
5052 | AuthRecord *rr; | | 5050 | AuthRecord *rr; |
5053 | m->SleepState = SleepState_Sleeping; | | 5051 | m->SleepState = SleepState_Sleeping; |
5054 | | | 5052 | |
5055 | #ifndef UNICAST_DISABLED | | 5053 | #ifndef UNICAST_DISABLED |
5056 | SleepRecordRegistrations(m); // If we have no SPS, need to deregister our uDNS records | | 5054 | SleepRecordRegistrations(m); // If we have no SPS, need to deregister our uDNS records |
5057 | #endif /* UNICAST_DISABLED */ | | 5055 | #endif /* UNICAST_DISABLED */ |
5058 | | | 5056 | |
5059 | // Mark all the records we need to deregister and send them | | 5057 | // Mark all the records we need to deregister and send them |
5060 | for (rr = m->ResourceRecords; rr; rr=rr->next) | | 5058 | for (rr = m->ResourceRecords; rr; rr=rr->next) |
5061 | if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye) | | 5059 | if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye) |
5062 | rr->ImmedAnswer = mDNSInterfaceMark; | | 5060 | rr->ImmedAnswer = mDNSInterfaceMark; |
5063 | SendResponses(m); | | 5061 | SendResponses(m); |
5064 | } | | 5062 | } |
5065 | | | 5063 | |
5066 | // BeginSleepProcessing is called, with the lock held, from either mDNS_Execute or mDNSCoreMachineSleep | | 5064 | // BeginSleepProcessing is called, with the lock held, from either mDNS_Execute or mDNSCoreMachineSleep |
5067 | mDNSlocal void BeginSleepProcessing(mDNS *const m) | | 5065 | mDNSlocal void BeginSleepProcessing(mDNS *const m) |
5068 | { | | 5066 | { |
5069 | mDNSBool SendGoodbyes = mDNStrue; | | 5067 | mDNSBool SendGoodbyes = mDNStrue; |
5070 | const CacheRecord *sps[3] = { mDNSNULL }; | | 5068 | const CacheRecord *sps[3] = { mDNSNULL }; |
5071 | | | 5069 | |
5072 | m->NextScheduledSPRetry = m->timenow; | | 5070 | m->NextScheduledSPRetry = m->timenow; |
5073 | | | 5071 | |
5074 | if (!m->SystemWakeOnLANEnabled) LogSPS("BeginSleepProcessing: m->SystemWakeOnLANEnabled is false"); | | 5072 | if (!m->SystemWakeOnLANEnabled) LogSPS("BeginSleepProcessing: m->SystemWakeOnLANEnabled is false"); |
5075 | else if (!mDNSCoreHaveAdvertisedMulticastServices(m)) LogSPS("BeginSleepProcessing: No advertised services"); | | 5073 | else if (!mDNSCoreHaveAdvertisedMulticastServices(m)) LogSPS("BeginSleepProcessing: No advertised services"); |
5076 | else // If we have at least one advertised service | | 5074 | else // If we have at least one advertised service |
5077 | { | | 5075 | { |
5078 | NetworkInterfaceInfo *intf; | | 5076 | NetworkInterfaceInfo *intf; |
5079 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) | | 5077 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) |
5080 | { | | 5078 | { |
5081 | if (!intf->NetWake) LogSPS("BeginSleepProcessing: %-6s not capable of magic packet wakeup", intf->ifname); | | 5079 | if (!intf->NetWake) LogSPS("BeginSleepProcessing: %-6s not capable of magic packet wakeup", intf->ifname); |
5082 | #if APPLE_OSX_mDNSResponder | | 5080 | #if APPLE_OSX_mDNSResponder |
5083 | else if (ActivateLocalProxy(m, intf->ifname) == mStatus_NoError) | | 5081 | else if (ActivateLocalProxy(m, intf->ifname) == mStatus_NoError) |
5084 | { | | 5082 | { |
5085 | SendGoodbyes = mDNSfalse; | | 5083 | SendGoodbyes = mDNSfalse; |
5086 | LogSPS("BeginSleepProcessing: %-6s using local proxy", intf->ifname); | | 5084 | LogSPS("BeginSleepProcessing: %-6s using local proxy", intf->ifname); |
5087 | // This will leave m->SleepState set to SleepState_Transferring, | | 5085 | // This will leave m->SleepState set to SleepState_Transferring, |
5088 | // which is okay because with no outstanding resolves, or updates in flight, | | 5086 | // which is okay because with no outstanding resolves, or updates in flight, |
5089 | // mDNSCoreReadyForSleep() will conclude correctly that all the updates have already completed | | 5087 | // mDNSCoreReadyForSleep() will conclude correctly that all the updates have already completed |
5090 | } | | 5088 | } |
5091 | #endif // APPLE_OSX_mDNSResponder | | 5089 | #endif // APPLE_OSX_mDNSResponder |
5092 | else | | 5090 | else |
5093 | { | | 5091 | { |
5094 | FindSPSInCache(m, &intf->NetWakeBrowse, sps); | | 5092 | FindSPSInCache(m, &intf->NetWakeBrowse, sps); |
5095 | if (!sps[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found (Next Browse Q in %d, interval %d)", | | 5093 | if (!sps[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found (Next Browse Q in %d, interval %d)", |
5096 | intf->ifname, &intf->ip, NextQSendTime(&intf->NetWakeBrowse) - m->timenow, intf->NetWakeBrowse.ThisQInterval); | | 5094 | intf->ifname, &intf->ip, NextQSendTime(&intf->NetWakeBrowse) - m->timenow, intf->NetWakeBrowse.ThisQInterval); |
5097 | else | | 5095 | else |
5098 | { | | 5096 | { |
5099 | int i; | | 5097 | int i; |
5100 | SendGoodbyes = mDNSfalse; | | 5098 | SendGoodbyes = mDNSfalse; |
5101 | intf->NextSPSAttempt = 0; | | 5099 | intf->NextSPSAttempt = 0; |
5102 | intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond; | | 5100 | intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond; |
5103 | // Don't need to set m->NextScheduledSPRetry here because we already set "m->NextScheduledSPRetry = m->timenow" above | | 5101 | // Don't need to set m->NextScheduledSPRetry here because we already set "m->NextScheduledSPRetry = m->timenow" above |
5104 | for (i=0; i<3; i++) | | 5102 | for (i=0; i<3; i++) |
5105 | { | | 5103 | { |
5106 | #if ForceAlerts | | 5104 | #if ForceAlerts |
5107 | if (intf->SPSAddr[i].type) | | 5105 | if (intf->SPSAddr[i].type) |
5108 | { LogMsg("BeginSleepProcessing: %s %d intf->SPSAddr[i].type %d", intf->ifname, i, intf->SPSAddr[i].type); *(long*)0 = 0; } | | 5106 | { LogMsg("BeginSleepProcessing: %s %d intf->SPSAddr[i].type %d", intf->ifname, i, intf->SPSAddr[i].type); *(long*)0 = 0; } |
5109 | if (intf->NetWakeResolve[i].ThisQInterval >= 0) | | 5107 | if (intf->NetWakeResolve[i].ThisQInterval >= 0) |
5110 | { LogMsg("BeginSleepProcessing: %s %d intf->NetWakeResolve[i].ThisQInterval %d", intf->ifname, i, intf->NetWakeResolve[i].ThisQInterval); *(long*)0 = 0; } | | 5108 | { LogMsg("BeginSleepProcessing: %s %d intf->NetWakeResolve[i].ThisQInterval %d", intf->ifname, i, intf->NetWakeResolve[i].ThisQInterval); *(long*)0 = 0; } |
5111 | #endif | | 5109 | #endif |
5112 | intf->SPSAddr[i].type = mDNSAddrType_None; | | 5110 | intf->SPSAddr[i].type = mDNSAddrType_None; |
5113 | if (intf->NetWakeResolve[i].ThisQInterval >= 0) mDNS_StopQuery(m, &intf->NetWakeResolve[i]); | | 5111 | if (intf->NetWakeResolve[i].ThisQInterval >= 0) mDNS_StopQuery(m, &intf->NetWakeResolve[i]); |
5114 | intf->NetWakeResolve[i].ThisQInterval = -1; | | 5112 | intf->NetWakeResolve[i].ThisQInterval = -1; |
5115 | if (sps[i]) | | 5113 | if (sps[i]) |
5116 | { | | 5114 | { |
5117 | LogSPS("BeginSleepProcessing: %-6s Found Sleep Proxy Server %d TTL %d %s", intf->ifname, i, sps[i]->resrec.rroriginalttl, CRDisplayString(m, sps[i])); | | 5115 | LogSPS("BeginSleepProcessing: %-6s Found Sleep Proxy Server %d TTL %d %s", intf->ifname, i, sps[i]->resrec.rroriginalttl, CRDisplayString(m, sps[i])); |
5118 | mDNS_SetupQuestion(&intf->NetWakeResolve[i], intf->InterfaceID, &sps[i]->resrec.rdata->u.name, kDNSType_SRV, NetWakeResolve, intf); | | 5116 | mDNS_SetupQuestion(&intf->NetWakeResolve[i], intf->InterfaceID, &sps[i]->resrec.rdata->u.name, kDNSType_SRV, NetWakeResolve, intf); |
5119 | intf->NetWakeResolve[i].ReturnIntermed = mDNStrue; | | 5117 | intf->NetWakeResolve[i].ReturnIntermed = mDNStrue; |
5120 | mDNS_StartQuery_internal(m, &intf->NetWakeResolve[i]); | | 5118 | mDNS_StartQuery_internal(m, &intf->NetWakeResolve[i]); |
5121 | } | | 5119 | } |
5122 | } | | 5120 | } |
5123 | } | | 5121 | } |
5124 | } | | 5122 | } |
5125 | } | | 5123 | } |
5126 | } | | 5124 | } |
5127 | | | 5125 | |
5128 | if (SendGoodbyes) // If we didn't find even one Sleep Proxy | | 5126 | if (SendGoodbyes) // If we didn't find even one Sleep Proxy |
5129 | { | | 5127 | { |
5130 | LogSPS("BeginSleepProcessing: Not registering with Sleep Proxy Server"); | | 5128 | LogSPS("BeginSleepProcessing: Not registering with Sleep Proxy Server"); |
5131 | SendSleepGoodbyes(m); | | 5129 | SendSleepGoodbyes(m); |
5132 | } | | 5130 | } |
5133 | } | | 5131 | } |
5134 | | | 5132 | |
5135 | // Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep. | | 5133 | // Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep. |
5136 | // Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up. | | 5134 | // Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up. |
5137 | // Normally, the platform support layer below mDNSCore should call this, not the client layer above. | | 5135 | // Normally, the platform support layer below mDNSCore should call this, not the client layer above. |
5138 | mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep) | | 5136 | mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep) |
5139 | { | | 5137 | { |
5140 | AuthRecord *rr; | | 5138 | AuthRecord *rr; |
5141 | | | 5139 | |
5142 | LogSPS("%s (old state %d) at %ld", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow); | | 5140 | LogSPS("%s (old state %d) at %ld", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow); |
5143 | | | 5141 | |
5144 | if (sleep && !m->SleepState) // Going to sleep | | 5142 | if (sleep && !m->SleepState) // Going to sleep |
5145 | { | | 5143 | { |
5146 | mDNS_Lock(m); | | 5144 | mDNS_Lock(m); |
5147 | // If we're going to sleep, need to stop advertising that we're a Sleep Proxy Server | | 5145 | // If we're going to sleep, need to stop advertising that we're a Sleep Proxy Server |
5148 | if (m->SPSSocket) | | 5146 | if (m->SPSSocket) |
5149 | { | | 5147 | { |
5150 | mDNSu8 oldstate = m->SPSState; | | 5148 | mDNSu8 oldstate = m->SPSState; |
5151 | mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here | | 5149 | mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here |
5152 | m->SPSState = 2; | | 5150 | m->SPSState = 2; |
5153 | if (oldstate == 1) mDNS_DeregisterService(m, &m->SPSRecords); | | 5151 | if (oldstate == 1) mDNS_DeregisterService(m, &m->SPSRecords); |
5154 | mDNS_ReclaimLockAfterCallback(); | | 5152 | mDNS_ReclaimLockAfterCallback(); |
5155 | } | | 5153 | } |
5156 | | | 5154 | |
5157 | m->SleepState = SleepState_Transferring; | | 5155 | m->SleepState = SleepState_Transferring; |
5158 | if (m->SystemWakeOnLANEnabled && m->DelaySleep) | | 5156 | if (m->SystemWakeOnLANEnabled && m->DelaySleep) |
5159 | { | | 5157 | { |
5160 | // If we just woke up moments ago, allow ten seconds for networking to stabilize before going back to sleep | | 5158 | // If we just woke up moments ago, allow ten seconds for networking to stabilize before going back to sleep |
5161 | LogSPS("mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m->DelaySleep - m->timenow); | | 5159 | LogSPS("mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m->DelaySleep - m->timenow); |
5162 | m->SleepLimit = NonZeroTime(m->DelaySleep + mDNSPlatformOneSecond * 10); | | 5160 | m->SleepLimit = NonZeroTime(m->DelaySleep + mDNSPlatformOneSecond * 10); |
5163 | } | | 5161 | } |
5164 | else | | 5162 | else |
5165 | { | | 5163 | { |
5166 | m->DelaySleep = 0; | | 5164 | m->DelaySleep = 0; |
5167 | m->SleepLimit = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 10); | | 5165 | m->SleepLimit = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 10); |
5168 | BeginSleepProcessing(m); | | 5166 | BeginSleepProcessing(m); |
5169 | } | | 5167 | } |
5170 | | | 5168 | |
5171 | #ifndef UNICAST_DISABLED | | 5169 | #ifndef UNICAST_DISABLED |
5172 | SuspendLLQs(m); | | 5170 | SuspendLLQs(m); |
5173 | #endif | | 5171 | #endif |
5174 | mDNS_Unlock(m); | | 5172 | mDNS_Unlock(m); |
5175 | // RemoveAutoTunnel6Record needs to be called outside the lock, as it grabs the lock also. | | 5173 | // RemoveAutoTunnel6Record needs to be called outside the lock, as it grabs the lock also. |
5176 | #if APPLE_OSX_mDNSResponder | | 5174 | #if APPLE_OSX_mDNSResponder |
5177 | RemoveAutoTunnel6Record(m); | | 5175 | RemoveAutoTunnel6Record(m); |
5178 | #endif | | 5176 | #endif |
5179 | LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m->SleepState, | | 5177 | LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m->SleepState, |
5180 | m->SleepState == SleepState_Transferring ? "Transferring" : | | 5178 | m->SleepState == SleepState_Transferring ? "Transferring" : |
5181 | m->SleepState == SleepState_Sleeping ? "Sleeping" : "?", m->SleepSeqNum); | | 5179 | m->SleepState == SleepState_Sleeping ? "Sleeping" : "?", m->SleepSeqNum); |
5182 | } | | 5180 | } |
5183 | else if (!sleep) // Waking up | | 5181 | else if (!sleep) // Waking up |
5184 | { | | 5182 | { |
5185 | mDNSu32 slot; | | 5183 | mDNSu32 slot; |
5186 | CacheGroup *cg; | | 5184 | CacheGroup *cg; |
5187 | CacheRecord *cr; | | 5185 | CacheRecord *cr; |
5188 | NetworkInterfaceInfo *intf; | | 5186 | NetworkInterfaceInfo *intf; |
5189 | | | 5187 | |
5190 | mDNS_Lock(m); | | 5188 | mDNS_Lock(m); |
5191 | // Reset SleepLimit back to 0 now that we're awake again. | | 5189 | // Reset SleepLimit back to 0 now that we're awake again. |
5192 | m->SleepLimit = 0; | | 5190 | m->SleepLimit = 0; |
5193 | | | 5191 | |
5194 | // If we were previously sleeping, but now we're not, increment m->SleepSeqNum to indicate that we're entering a new period of wakefulness | | 5192 | // If we were previously sleeping, but now we're not, increment m->SleepSeqNum to indicate that we're entering a new period of wakefulness |
5195 | if (m->SleepState != SleepState_Awake) | | 5193 | if (m->SleepState != SleepState_Awake) |
5196 | { | | 5194 | { |
5197 | m->SleepState = SleepState_Awake; | | 5195 | m->SleepState = SleepState_Awake; |
5198 | m->SleepSeqNum++; | | 5196 | m->SleepSeqNum++; |
5199 | // If the machine wakes and then immediately tries to sleep again (e.g. a maintenance wake) | | 5197 | // If the machine wakes and then immediately tries to sleep again (e.g. a maintenance wake) |
5200 | // then we enforce a minimum delay of 16 seconds before we begin sleep processing. | | 5198 | // then we enforce a minimum delay of 16 seconds before we begin sleep processing. |
5201 | // This is to allow time for the Ethernet link to come up, DHCP to get an address, mDNS to issue queries, etc., | | 5199 | // This is to allow time for the Ethernet link to come up, DHCP to get an address, mDNS to issue queries, etc., |
5202 | // before we make our determination of whether there's a Sleep Proxy out there we should register with. | | 5200 | // before we make our determination of whether there's a Sleep Proxy out there we should register with. |
5203 | m->DelaySleep = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 16); | | 5201 | m->DelaySleep = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 16); |
5204 | } | | 5202 | } |
5205 | | | 5203 | |
5206 | if (m->SPSState == 3) | | 5204 | if (m->SPSState == 3) |
5207 | { | | 5205 | { |
5208 | m->SPSState = 0; | | 5206 | m->SPSState = 0; |
5209 | mDNSCoreBeSleepProxyServer_internal(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower); | | 5207 | mDNSCoreBeSleepProxyServer_internal(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower); |
5210 | } | | 5208 | } |
5211 | | | 5209 | |
5212 | // In case we gave up waiting and went to sleep before we got an ack from the Sleep Proxy, | | 5210 | // In case we gave up waiting and went to sleep before we got an ack from the Sleep Proxy, |
5213 | // on wake we go through our record list and clear updateid back to zero | | 5211 | // on wake we go through our record list and clear updateid back to zero |
5214 | for (rr = m->ResourceRecords; rr; rr=rr->next) rr->updateid = zeroID; | | 5212 | for (rr = m->ResourceRecords; rr; rr=rr->next) rr->updateid = zeroID; |
5215 | | | 5213 | |
5216 | // ... and the same for NextSPSAttempt | | 5214 | // ... and the same for NextSPSAttempt |
5217 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) intf->NextSPSAttempt = -1; | | 5215 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) intf->NextSPSAttempt = -1; |
5218 | | | 5216 | |
5219 | // Restart unicast and multicast queries | | 5217 | // Restart unicast and multicast queries |
5220 | mDNSCoreRestartQueries(m); | | 5218 | mDNSCoreRestartQueries(m); |
5221 | | | 5219 | |
5222 | // and reactivtate service registrations | | 5220 | // and reactivtate service registrations |
5223 | m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond); | | 5221 | m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond); |
5224 | LogInfo("mDNSCoreMachineSleep waking: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow); | | 5222 | LogInfo("mDNSCoreMachineSleep waking: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow); |
5225 | | | 5223 | |
5226 | // 2. Re-validate our cache records | | 5224 | // 2. Re-validate our cache records |
5227 | FORALL_CACHERECORDS(slot, cg, cr) | | 5225 | FORALL_CACHERECORDS(slot, cg, cr) |
5228 | mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake); | | 5226 | mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake); |
5229 | | | 5227 | |
5230 | // 3. Retrigger probing and announcing for all our authoritative records | | 5228 | // 3. Retrigger probing and announcing for all our authoritative records |
5231 | for (rr = m->ResourceRecords; rr; rr=rr->next) | | 5229 | for (rr = m->ResourceRecords; rr; rr=rr->next) |
5232 | if (AuthRecord_uDNS(rr)) | | 5230 | if (AuthRecord_uDNS(rr)) |
5233 | { | | 5231 | { |
5234 | ActivateUnicastRegistration(m, rr); | | 5232 | ActivateUnicastRegistration(m, rr); |
5235 | } | | 5233 | } |
5236 | else | | 5234 | else |
5237 | { | | 5235 | { |
5238 | if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique; | | 5236 | if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique; |
5239 | rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); | | 5237 | rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); |
5240 | rr->AnnounceCount = InitialAnnounceCount; | | 5238 | rr->AnnounceCount = InitialAnnounceCount; |
5241 | rr->SendNSECNow = mDNSNULL; | | 5239 | rr->SendNSECNow = mDNSNULL; |
5242 | InitializeLastAPTime(m, rr); | | 5240 | InitializeLastAPTime(m, rr); |
5243 | } | | 5241 | } |
5244 | | | 5242 | |
5245 | // 4. Refresh NAT mappings | | 5243 | // 4. Refresh NAT mappings |
5246 | // We don't want to have to assume that all hardware can necessarily keep accurate | | 5244 | // We don't want to have to assume that all hardware can necessarily keep accurate |
5247 | // track of passage of time while asleep, so on wake we refresh our NAT mappings | | 5245 | // track of passage of time while asleep, so on wake we refresh our NAT mappings |
5248 | // We typically wake up with no interfaces active, so there's no need to rush to try to find our external address. | | 5246 | // We typically wake up with no interfaces active, so there's no need to rush to try to find our external address. |
5249 | // When we get a network configuration change, mDNSMacOSXNetworkChanged calls uDNS_SetupDNSConfig, which calls | | 5247 | // When we get a network configuration change, mDNSMacOSXNetworkChanged calls uDNS_SetupDNSConfig, which calls |
5250 | // mDNS_SetPrimaryInterfaceInfo, which then sets m->retryGetAddr to immediately request our external address from the NAT gateway. | | 5248 | // mDNS_SetPrimaryInterfaceInfo, which then sets m->retryGetAddr to immediately request our external address from the NAT gateway. |
5251 | m->retryIntervalGetAddr = NATMAP_INIT_RETRY; | | 5249 | m->retryIntervalGetAddr = NATMAP_INIT_RETRY; |
5252 | m->retryGetAddr = m->timenow + mDNSPlatformOneSecond * 5; | | 5250 | m->retryGetAddr = m->timenow + mDNSPlatformOneSecond * 5; |
5253 | LogInfo("mDNSCoreMachineSleep: retryGetAddr in %d %d", m->retryGetAddr - m->timenow, m->timenow); | | 5251 | LogInfo("mDNSCoreMachineSleep: retryGetAddr in %d %d", m->retryGetAddr - m->timenow, m->timenow); |
5254 | RecreateNATMappings(m); | | 5252 | RecreateNATMappings(m); |
5255 | mDNS_Unlock(m); | | 5253 | mDNS_Unlock(m); |
5256 | } | | 5254 | } |
5257 | } | | 5255 | } |
5258 | | | 5256 | |
5259 | mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now) | | 5257 | mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now) |
5260 | { | | 5258 | { |
5261 | DNSQuestion *q; | | 5259 | DNSQuestion *q; |
5262 | AuthRecord *rr; | | 5260 | AuthRecord *rr; |
5263 | NetworkInterfaceInfo *intf; | | 5261 | NetworkInterfaceInfo *intf; |
5264 | | | 5262 | |
5265 | mDNS_Lock(m); | | 5263 | mDNS_Lock(m); |
5266 | | | 5264 | |
5267 | if (m->DelaySleep) goto notready; | | 5265 | if (m->DelaySleep) goto notready; |
5268 | | | 5266 | |
5269 | // If we've not hit the sleep limit time, and it's not time for our next retry, we can skip these checks | | 5267 | // If we've not hit the sleep limit time, and it's not time for our next retry, we can skip these checks |
5270 | if (m->SleepLimit - now > 0 && m->NextScheduledSPRetry - now > 0) goto notready; | | 5268 | if (m->SleepLimit - now > 0 && m->NextScheduledSPRetry - now > 0) goto notready; |
5271 | | | 5269 | |
5272 | m->NextScheduledSPRetry = now + 0x40000000UL; | | 5270 | m->NextScheduledSPRetry = now + 0x40000000UL; |
5273 | | | 5271 | |
5274 | // See if we might need to retransmit any lost Sleep Proxy Registrations | | 5272 | // See if we might need to retransmit any lost Sleep Proxy Registrations |
5275 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) | | 5273 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) |
5276 | if (intf->NextSPSAttempt >= 0) | | 5274 | if (intf->NextSPSAttempt >= 0) |
5277 | { | | 5275 | { |
5278 | if (now - intf->NextSPSAttemptTime >= 0) | | 5276 | if (now - intf->NextSPSAttemptTime >= 0) |
5279 | { | | 5277 | { |
5280 | LogSPS("mDNSCoreReadyForSleep: retrying for %s SPS %d try %d", | | 5278 | LogSPS("mDNSCoreReadyForSleep: retrying for %s SPS %d try %d", |
5281 | intf->ifname, intf->NextSPSAttempt/3, intf->NextSPSAttempt); | | 5279 | intf->ifname, intf->NextSPSAttempt/3, intf->NextSPSAttempt); |
5282 | SendSPSRegistration(m, intf, zeroID); | | 5280 | SendSPSRegistration(m, intf, zeroID); |
5283 | // Don't need to "goto notready" here, because if we do still have record registrations | | 5281 | // Don't need to "goto notready" here, because if we do still have record registrations |
5284 | // that have not been acknowledged yet, we'll catch that in the record list scan below. | | 5282 | // that have not been acknowledged yet, we'll catch that in the record list scan below. |
5285 | } | | 5283 | } |
5286 | else | | 5284 | else |
5287 | if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0) | | 5285 | if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0) |
5288 | m->NextScheduledSPRetry = intf->NextSPSAttemptTime; | | 5286 | m->NextScheduledSPRetry = intf->NextSPSAttemptTime; |
5289 | } | | 5287 | } |
5290 | | | 5288 | |
5291 | // Scan list of interfaces, and see if we're still waiting for any sleep proxy resolves to complete | | 5289 | // Scan list of interfaces, and see if we're still waiting for any sleep proxy resolves to complete |
5292 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) | | 5290 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) |
5293 | { | | 5291 | { |
5294 | int sps = (intf->NextSPSAttempt == 0) ? 0 : (intf->NextSPSAttempt-1)/3; | | 5292 | int sps = (intf->NextSPSAttempt == 0) ? 0 : (intf->NextSPSAttempt-1)/3; |
5295 | if (intf->NetWakeResolve[sps].ThisQInterval >= 0) | | 5293 | if (intf->NetWakeResolve[sps].ThisQInterval >= 0) |
5296 | { | | 5294 | { |
5297 | LogSPS("mDNSCoreReadyForSleep: waiting for SPS Resolve %s %##s (%s)", | | 5295 | LogSPS("mDNSCoreReadyForSleep: waiting for SPS Resolve %s %##s (%s)", |
5298 | intf->ifname, intf->NetWakeResolve[sps].qname.c, DNSTypeName(intf->NetWakeResolve[sps].qtype)); | | 5296 | intf->ifname, intf->NetWakeResolve[sps].qname.c, DNSTypeName(intf->NetWakeResolve[sps].qtype)); |
5299 | goto spsnotready; | | 5297 | goto spsnotready; |
5300 | } | | 5298 | } |
5301 | } | | 5299 | } |
5302 | | | 5300 | |
5303 | // Scan list of registered records | | 5301 | // Scan list of registered records |
5304 | for (rr = m->ResourceRecords; rr; rr = rr->next) | | 5302 | for (rr = m->ResourceRecords; rr; rr = rr->next) |
5305 | if (!AuthRecord_uDNS(rr)) | | 5303 | if (!AuthRecord_uDNS(rr)) |
5306 | if (!mDNSOpaque16IsZero(rr->updateid)) | | 5304 | if (!mDNSOpaque16IsZero(rr->updateid)) |
5307 | { LogSPS("mDNSCoreReadyForSleep: waiting for SPS Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto spsnotready; } | | 5305 | { LogSPS("mDNSCoreReadyForSleep: waiting for SPS Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto spsnotready; } |
5308 | | | 5306 | |
5309 | // Scan list of private LLQs, and make sure they've all completed their handshake with the server | | 5307 | // Scan list of private LLQs, and make sure they've all completed their handshake with the server |
5310 | for (q = m->Questions; q; q = q->next) | | 5308 | for (q = m->Questions; q; q = q->next) |
5311 | if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->ReqLease == 0 && q->tcp) | | 5309 | if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->ReqLease == 0 && q->tcp) |
5312 | { | | 5310 | { |
5313 | LogSPS("mDNSCoreReadyForSleep: waiting for LLQ %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); | | 5311 | LogSPS("mDNSCoreReadyForSleep: waiting for LLQ %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); |
5314 | goto notready; | | 5312 | goto notready; |
5315 | } | | 5313 | } |
5316 | | | 5314 | |
5317 | // Scan list of registered records | | 5315 | // Scan list of registered records |
5318 | for (rr = m->ResourceRecords; rr; rr = rr->next) | | 5316 | for (rr = m->ResourceRecords; rr; rr = rr->next) |
5319 | if (AuthRecord_uDNS(rr)) | | 5317 | if (AuthRecord_uDNS(rr)) |
5320 | { | | 5318 | { |
5321 | if (rr->state == regState_Refresh && rr->tcp) | | 5319 | if (rr->state == regState_Refresh && rr->tcp) |
5322 | { LogSPS("mDNSCoreReadyForSleep: waiting for Record Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; } | | 5320 | { LogSPS("mDNSCoreReadyForSleep: waiting for Record Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; } |
5323 | #if APPLE_OSX_mDNSResponder | | 5321 | #if APPLE_OSX_mDNSResponder |
5324 | if (!RecordReadyForSleep(m, rr)) { LogSPS("mDNSCoreReadyForSleep: waiting for %s", ARDisplayString(m, rr)); goto notready; } | | 5322 | if (!RecordReadyForSleep(m, rr)) { LogSPS("mDNSCoreReadyForSleep: waiting for %s", ARDisplayString(m, rr)); goto notready; } |
5325 | #endif | | 5323 | #endif |
5326 | } | | 5324 | } |
5327 | | | 5325 | |
5328 | mDNS_Unlock(m); | | 5326 | mDNS_Unlock(m); |
5329 | return mDNStrue; | | 5327 | return mDNStrue; |
5330 | | | 5328 | |
5331 | spsnotready: | | 5329 | spsnotready: |
5332 | | | 5330 | |
5333 | // If we failed to complete sleep proxy registration within ten seconds, we give up on that | | 5331 | // If we failed to complete sleep proxy registration within ten seconds, we give up on that |
5334 | // and allow up to ten seconds more to complete wide-area deregistration instead | | 5332 | // and allow up to ten seconds more to complete wide-area deregistration instead |
5335 | if (now - m->SleepLimit >= 0) | | 5333 | if (now - m->SleepLimit >= 0) |
5336 | { | | 5334 | { |
5337 | LogMsg("Failed to register with SPS, now sending goodbyes"); | | 5335 | LogMsg("Failed to register with SPS, now sending goodbyes"); |
5338 | | | 5336 | |
5339 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) | | 5337 | for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) |
5340 | if (intf->NetWakeBrowse.ThisQInterval >= 0) | | 5338 | if (intf->NetWakeBrowse.ThisQInterval >= 0) |
5341 | { | | 5339 | { |
5342 | LogSPS("ReadyForSleep mDNS_DeactivateNetWake %s %##s (%s)", | | 5340 | LogSPS("ReadyForSleep mDNS_DeactivateNetWake %s %##s (%s)", |
5343 | intf->ifname, intf->NetWakeResolve[0].qname.c, DNSTypeName(intf->NetWakeResolve[0].qtype)); | | 5341 | intf->ifname, intf->NetWakeResolve[0].qname.c, DNSTypeName(intf->NetWakeResolve[0].qtype)); |
5344 | mDNS_DeactivateNetWake_internal(m, intf); | | 5342 | mDNS_DeactivateNetWake_internal(m, intf); |
5345 | } | | 5343 | } |
5346 | | | 5344 | |
5347 | for (rr = m->ResourceRecords; rr; rr = rr->next) | | 5345 | for (rr = m->ResourceRecords; rr; rr = rr->next) |
5348 | if (!AuthRecord_uDNS(rr)) | | 5346 | if (!AuthRecord_uDNS(rr)) |
5349 | if (!mDNSOpaque16IsZero(rr->updateid)) | | 5347 | if (!mDNSOpaque16IsZero(rr->updateid)) |
5350 | { | | 5348 | { |
5351 | LogSPS("ReadyForSleep clearing updateid for %s", ARDisplayString(m, rr)); | | 5349 | LogSPS("ReadyForSleep clearing updateid for %s", ARDisplayString(m, rr)); |
5352 | rr->updateid = zeroID; | | 5350 | rr->updateid = zeroID; |
5353 | } | | 5351 | } |
5354 | | | 5352 | |
5355 | // We'd really like to allow up to ten seconds more here, | | 5353 | // We'd really like to allow up to ten seconds more here, |
5356 | // but if we don't respond to the sleep notification within 30 seconds | | 5354 | // but if we don't respond to the sleep notification within 30 seconds |
5357 | // we'll be put back to sleep forcibly without the chance to schedule the next maintenance wake. | | 5355 | // we'll be put back to sleep forcibly without the chance to schedule the next maintenance wake. |
5358 | // Right now we wait 16 sec after wake for all the interfaces to come up, then we wait up to 10 seconds | | 5356 | // Right now we wait 16 sec after wake for all the interfaces to come up, then we wait up to 10 seconds |
5359 | // more for SPS resolves and record registrations to complete, which puts us at 26 seconds. | | 5357 | // more for SPS resolves and record registrations to complete, which puts us at 26 seconds. |
5360 | // If we allow just one more second to send our goodbyes, that puts us at 27 seconds. | | 5358 | // If we allow just one more second to send our goodbyes, that puts us at 27 seconds. |
5361 | m->SleepLimit = now + mDNSPlatformOneSecond * 1; | | 5359 | m->SleepLimit = now + mDNSPlatformOneSecond * 1; |
5362 | | | 5360 | |
5363 | SendSleepGoodbyes(m); | | 5361 | SendSleepGoodbyes(m); |
5364 | } | | 5362 | } |
5365 | | | 5363 | |
5366 | notready: | | 5364 | notready: |
5367 | mDNS_Unlock(m); | | 5365 | mDNS_Unlock(m); |
5368 | return mDNSfalse; | | 5366 | return mDNSfalse; |
5369 | } | | 5367 | } |
5370 | | | 5368 | |
5371 | mDNSexport mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now) | | 5369 | mDNSexport mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now) |
5372 | { | | 5370 | { |
5373 | AuthRecord *ar; | | 5371 | AuthRecord *ar; |
5374 | | | 5372 | |
5375 | // Even when we have no wake-on-LAN-capable interfaces, or we failed to find a sleep proxy, or we have other | | 5373 | // Even when we have no wake-on-LAN-capable interfaces, or we failed to find a sleep proxy, or we have other |
5376 | // failure scenarios, we still want to wake up in at most 120 minutes, to see if the network environment has changed. | | 5374 | // failure scenarios, we still want to wake up in at most 120 minutes, to see if the network environment has changed. |
5377 | // E.g. we might wake up and find no wireless network because the base station got rebooted just at that moment, | | 5375 | // E.g. we might wake up and find no wireless network because the base station got rebooted just at that moment, |
5378 | // and if that happens we don't want to just give up and go back to sleep and never try again. | | 5376 | // and if that happens we don't want to just give up and go back to sleep and never try again. |
5379 | mDNSs32 e = now + (120 * 60 * mDNSPlatformOneSecond); // Sleep for at most 120 minutes | | 5377 | mDNSs32 e = now + (120 * 60 * mDNSPlatformOneSecond); // Sleep for at most 120 minutes |
5380 | | | 5378 | |
5381 | NATTraversalInfo *nat; | | 5379 | NATTraversalInfo *nat; |
5382 | for (nat = m->NATTraversals; nat; nat=nat->next) | | 5380 | for (nat = m->NATTraversals; nat; nat=nat->next) |
5383 | if (nat->Protocol && nat->ExpiryTime && nat->ExpiryTime - now > mDNSPlatformOneSecond*4) | | 5381 | if (nat->Protocol && nat->ExpiryTime && nat->ExpiryTime - now > mDNSPlatformOneSecond*4) |
5384 | { | | 5382 | { |
5385 | mDNSs32 t = nat->ExpiryTime - (nat->ExpiryTime - now) / 10; // Wake up when 90% of the way to the expiry time | | 5383 | mDNSs32 t = nat->ExpiryTime - (nat->ExpiryTime - now) / 10; // Wake up when 90% of the way to the expiry time |
5386 | if (e - t > 0) e = t; | | 5384 | if (e - t > 0) e = t; |
5387 | LogSPS("ComputeWakeTime: %p %s Int %5d Ext %5d Err %d Retry %5d Interval %5d Expire %5d Wake %5d", | | 5385 | LogSPS("ComputeWakeTime: %p %s Int %5d Ext %5d Err %d Retry %5d Interval %5d Expire %5d Wake %5d", |
5388 | nat, nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP", | | 5386 | nat, nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP", |
5389 | mDNSVal16(nat->IntPort), mDNSVal16(nat->ExternalPort), nat->Result, | | 5387 | mDNSVal16(nat->IntPort), mDNSVal16(nat->ExternalPort), nat->Result, |
5390 | nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0, | | 5388 | nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0, |
5391 | nat->retryInterval / mDNSPlatformOneSecond, | | 5389 | nat->retryInterval / mDNSPlatformOneSecond, |
5392 | nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0, | | 5390 | nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0, |
5393 | (t - now) / mDNSPlatformOneSecond); | | 5391 | (t - now) / mDNSPlatformOneSecond); |
5394 | } | | 5392 | } |
5395 | | | 5393 | |
5396 | // This loop checks both the time we need to renew wide-area registrations, | | 5394 | // This loop checks both the time we need to renew wide-area registrations, |
5397 | // and the time we need to renew Sleep Proxy registrations | | 5395 | // and the time we need to renew Sleep Proxy registrations |
5398 | for (ar = m->ResourceRecords; ar; ar = ar->next) | | 5396 | for (ar = m->ResourceRecords; ar; ar = ar->next) |
5399 | if (ar->expire && ar->expire - now > mDNSPlatformOneSecond*4) | | 5397 | if (ar->expire && ar->expire - now > mDNSPlatformOneSecond*4) |
5400 | { | | 5398 | { |
5401 | mDNSs32 t = ar->expire - (ar->expire - now) / 10; // Wake up when 90% of the way to the expiry time | | 5399 | mDNSs32 t = ar->expire - (ar->expire - now) / 10; // Wake up when 90% of the way to the expiry time |
5402 | if (e - t > 0) e = t; | | 5400 | if (e - t > 0) e = t; |
5403 | LogSPS("ComputeWakeTime: %p Int %7d Next %7d Expire %7d Wake %7d %s", | | 5401 | LogSPS("ComputeWakeTime: %p Int %7d Next %7d Expire %7d Wake %7d %s", |
5404 | ar, ar->ThisAPInterval / mDNSPlatformOneSecond, | | 5402 | ar, ar->ThisAPInterval / mDNSPlatformOneSecond, |
5405 | (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond, | | 5403 | (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond, |
5406 | ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0, | | 5404 | ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0, |
5407 | (t - now) / mDNSPlatformOneSecond, ARDisplayString(m, ar)); | | 5405 | (t - now) / mDNSPlatformOneSecond, ARDisplayString(m, ar)); |
5408 | } | | 5406 | } |
5409 | | | 5407 | |
5410 | return(e - now); | | 5408 | return(e - now); |
5411 | } | | 5409 | } |
5412 | | | 5410 | |
5413 | // *************************************************************************** | | 5411 | // *************************************************************************** |
5414 | #if COMPILER_LIKES_PRAGMA_MARK | | 5412 | #if COMPILER_LIKES_PRAGMA_MARK |
5415 | #pragma mark - | | 5413 | #pragma mark - |
5416 | #pragma mark - Packet Reception Functions | | 5414 | #pragma mark - Packet Reception Functions |
5417 | #endif | | 5415 | #endif |
5418 | | | 5416 | |
5419 | #define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo) | | 5417 | #define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo) |
5420 | | | 5418 | |
5421 | mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const mDNSu8 *const end, | | 5419 | mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const mDNSu8 *const end, |
5422 | const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, DNSMessage *const response, AuthRecord *ResponseRecords) | | 5420 | const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, DNSMessage *const response, AuthRecord *ResponseRecords) |
5423 | { | | 5421 | { |
5424 | mDNSu8 *responseptr = response->data; | | 5422 | mDNSu8 *responseptr = response->data; |
5425 | const mDNSu8 *const limit = response->data + sizeof(response->data); | | 5423 | const mDNSu8 *const limit = response->data + sizeof(response->data); |
5426 | const mDNSu8 *ptr = query->data; | | 5424 | const mDNSu8 *ptr = query->data; |
5427 | AuthRecord *rr; | | 5425 | AuthRecord *rr; |
5428 | mDNSu32 maxttl = 0x70000000; | | 5426 | mDNSu32 maxttl = 0x70000000; |
5429 | int i; | | 5427 | int i; |
5430 | | | 5428 | |
5431 | // Initialize the response fields so we can answer the questions | | 5429 | // Initialize the response fields so we can answer the questions |
5432 | InitializeDNSMessage(&response->h, query->h.id, ResponseFlags); | | 5430 | InitializeDNSMessage(&response->h, query->h.id, ResponseFlags); |
5433 | | | 5431 | |
5434 | // *** | | 5432 | // *** |
5435 | // *** 1. Write out the list of questions we are actually going to answer with this packet | | 5433 | // *** 1. Write out the list of questions we are actually going to answer with this packet |
5436 | // *** | | 5434 | // *** |
5437 | if (LegacyQuery) | | 5435 | if (LegacyQuery) |
5438 | { | | 5436 | { |
5439 | maxttl = kStaticCacheTTL; | | 5437 | maxttl = kStaticCacheTTL; |
5440 | for (i=0; i<query->h.numQuestions; i++) // For each question... | | 5438 | for (i=0; i<query->h.numQuestions; i++) // For each question... |
5441 | { | | 5439 | { |
5442 | DNSQuestion q; | | 5440 | DNSQuestion q; |
5443 | ptr = getQuestion(query, ptr, end, InterfaceID, &q); // get the question... | | 5441 | ptr = getQuestion(query, ptr, end, InterfaceID, &q); // get the question... |
5444 | if (!ptr) return(mDNSNULL); | | 5442 | if (!ptr) return(mDNSNULL); |
5445 | | | 5443 | |
5446 | for (rr=ResponseRecords; rr; rr=rr->NextResponse) // and search our list of proposed answers | | 5444 | for (rr=ResponseRecords; rr; rr=rr->NextResponse) // and search our list of proposed answers |
5447 | { | | 5445 | { |
5448 | if (rr->NR_AnswerTo == ptr) // If we're going to generate a record answering this question | | 5446 | if (rr->NR_AnswerTo == ptr) // If we're going to generate a record answering this question |
5449 | { // then put the question in the question section | | 5447 | { // then put the question in the question section |
5450 | responseptr = putQuestion(response, responseptr, limit, &q.qname, q.qtype, q.qclass); | | 5448 | responseptr = putQuestion(response, responseptr, limit, &q.qname, q.qtype, q.qclass); |
5451 | if (!responseptr) { debugf("GenerateUnicastResponse: Ran out of space for questions!"); return(mDNSNULL); } | | 5449 | if (!responseptr) { debugf("GenerateUnicastResponse: Ran out of space for questions!"); return(mDNSNULL); } |
5452 | break; // break out of the ResponseRecords loop, and go on to the next question | | 5450 | break; // break out of the ResponseRecords loop, and go on to the next question |
5453 | } | | 5451 | } |
5454 | } | | 5452 | } |
5455 | } | | 5453 | } |
5456 | | | 5454 | |
5457 | if (response->h.numQuestions == 0) { LogMsg("GenerateUnicastResponse: ERROR! Why no questions?"); return(mDNSNULL); } | | 5455 | if (response->h.numQuestions == 0) { LogMsg("GenerateUnicastResponse: ERROR! Why no questions?"); return(mDNSNULL); } |
5458 | } | | 5456 | } |
5459 | | | 5457 | |
5460 | // *** | | 5458 | // *** |
5461 | // *** 2. Write Answers | | 5459 | // *** 2. Write Answers |
5462 | // *** | | 5460 | // *** |
5463 | for (rr=ResponseRecords; rr; rr=rr->NextResponse) | | 5461 | for (rr=ResponseRecords; rr; rr=rr->NextResponse) |
5464 | if (rr->NR_AnswerTo) | | 5462 | if (rr->NR_AnswerTo) |
5465 | { | | 5463 | { |
5466 | mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAnswers, &rr->resrec, | | 5464 | mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAnswers, &rr->resrec, |
5467 | maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl); | | 5465 | maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl); |
5468 | if (p) responseptr = p; | | 5466 | if (p) responseptr = p; |
5469 | else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response->h.flags.b[0] |= kDNSFlag0_TC; } | | 5467 | else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response->h.flags.b[0] |= kDNSFlag0_TC; } |
5470 | } | | 5468 | } |
5471 | | | 5469 | |
5472 | // *** | | 5470 | // *** |
5473 | // *** 3. Write Additionals | | 5471 | // *** 3. Write Additionals |
5474 | // *** | | 5472 | // *** |
5475 | for (rr=ResponseRecords; rr; rr=rr->NextResponse) | | 5473 | for (rr=ResponseRecords; rr; rr=rr->NextResponse) |
5476 | if (rr->NR_AdditionalTo && !rr->NR_AnswerTo) | | 5474 | if (rr->NR_AdditionalTo && !rr->NR_AnswerTo) |
5477 | { | | 5475 | { |
5478 | mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAdditionals, &rr->resrec, | | 5476 | mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAdditionals, &rr->resrec, |
5479 | maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl); | | 5477 | maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl); |
5480 | if (p) responseptr = p; | | 5478 | if (p) responseptr = p; |
5481 | else debugf("GenerateUnicastResponse: No more space for additionals"); | | 5479 | else debugf("GenerateUnicastResponse: No more space for additionals"); |
5482 | } | | 5480 | } |
5483 | | | 5481 | |
5484 | return(responseptr); | | 5482 | return(responseptr); |
5485 | } | | 5483 | } |
5486 | | | 5484 | |
5487 | // AuthRecord *our is our Resource Record | | 5485 | // AuthRecord *our is our Resource Record |
5488 | // CacheRecord *pkt is the Resource Record from the response packet we've witnessed on the network | | 5486 | // CacheRecord *pkt is the Resource Record from the response packet we've witnessed on the network |
5489 | // Returns 0 if there is no conflict | | 5487 | // Returns 0 if there is no conflict |
5490 | // Returns +1 if there was a conflict and we won | | 5488 | // Returns +1 if there was a conflict and we won |
5491 | // Returns -1 if there was a conflict and we lost and have to rename | | 5489 | // Returns -1 if there was a conflict and we lost and have to rename |
5492 | mDNSlocal int CompareRData(const AuthRecord *const our, const CacheRecord *const pkt) | | 5490 | mDNSlocal int CompareRData(const AuthRecord *const our, const CacheRecord *const pkt) |
5493 | { | | 5491 | { |
5494 | mDNSu8 ourdata[256], *ourptr = ourdata, *ourend; | | 5492 | mDNSu8 ourdata[256], *ourptr = ourdata, *ourend; |
5495 | mDNSu8 pktdata[256], *pktptr = pktdata, *pktend; | | 5493 | mDNSu8 pktdata[256], *pktptr = pktdata, *pktend; |
5496 | if (!our) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); } | | 5494 | if (!our) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); } |
5497 | if (!pkt) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); } | | 5495 | if (!pkt) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); } |
5498 | | | 5496 | |
5499 | ourend = putRData(mDNSNULL, ourdata, ourdata + sizeof(ourdata), &our->resrec); | | 5497 | ourend = putRData(mDNSNULL, ourdata, ourdata + sizeof(ourdata), &our->resrec); |
5500 | pktend = putRData(mDNSNULL, pktdata, pktdata + sizeof(pktdata), &pkt->resrec); | | 5498 | pktend = putRData(mDNSNULL, pktdata, pktdata + sizeof(pktdata), &pkt->resrec); |
5501 | while (ourptr < ourend && pktptr < pktend && *ourptr == *pktptr) { ourptr++; pktptr++; } | | 5499 | while (ourptr < ourend && pktptr < pktend && *ourptr == *pktptr) { ourptr++; pktptr++; } |
5502 | if (ourptr >= ourend && pktptr >= pktend) return(0); // If data identical, not a conflict | | 5500 | if (ourptr >= ourend && pktptr >= pktend) return(0); // If data identical, not a conflict |
5503 | | | 5501 | |
5504 | if (ourptr >= ourend) return(-1); // Our data ran out first; We lost | | 5502 | if (ourptr >= ourend) return(-1); // Our data ran out first; We lost |
5505 | if (pktptr >= pktend) return(+1); // Packet data ran out first; We won | | 5503 | if (pktptr >= pktend) return(+1); // Packet data ran out first; We won |
5506 | if (*pktptr > *ourptr) return(-1); // Our data is numerically lower; We lost | | 5504 | if (*pktptr > *ourptr) return(-1); // Our data is numerically lower; We lost |
5507 | if (*pktptr < *ourptr) return(+1); // Packet data is numerically lower; We won | | 5505 | if (*pktptr < *ourptr) return(+1); // Packet data is numerically lower; We won |
5508 | | | 5506 | |
5509 | LogMsg("CompareRData ERROR: Invalid state"); | | 5507 | LogMsg("CompareRData ERROR: Invalid state"); |
5510 | return(-1); | | 5508 | return(-1); |