1*4b22b933Srs200217 /* -*- Mode: C; tab-width: 4 -*-
2*4b22b933Srs200217 *
3*4b22b933Srs200217 * Copyright (c) 2003-2006 Apple Computer, Inc. All rights reserved.
4*4b22b933Srs200217 *
5*4b22b933Srs200217 * Licensed under the Apache License, Version 2.0 (the "License");
6*4b22b933Srs200217 * you may not use this file except in compliance with the License.
7*4b22b933Srs200217 * You may obtain a copy of the License at
8*4b22b933Srs200217 *
9*4b22b933Srs200217 * http://www.apache.org/licenses/LICENSE-2.0
10*4b22b933Srs200217 *
11*4b22b933Srs200217 * Unless required by applicable law or agreed to in writing, software
12*4b22b933Srs200217 * distributed under the License is distributed on an "AS IS" BASIS,
13*4b22b933Srs200217 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*4b22b933Srs200217 * See the License for the specific language governing permissions and
15*4b22b933Srs200217 * limitations under the License.
16*4b22b933Srs200217
17*4b22b933Srs200217 Change History (most recent first):
18*4b22b933Srs200217
19*4b22b933Srs200217 $Log: uds_daemon.c,v $
20*4b22b933Srs200217 Revision 1.201.2.1 2006/08/29 06:24:36 cheshire
21*4b22b933Srs200217 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
22*4b22b933Srs200217
23*4b22b933Srs200217 Revision 1.201 2006/06/29 03:02:47 cheshire
24*4b22b933Srs200217 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
25*4b22b933Srs200217
26*4b22b933Srs200217 Revision 1.200 2006/06/28 08:56:26 cheshire
27*4b22b933Srs200217 Added "_op" to the end of the operation code enum values,
28*4b22b933Srs200217 to differentiate them from the routines with the same names
29*4b22b933Srs200217
30*4b22b933Srs200217 Revision 1.199 2006/06/28 08:53:39 cheshire
31*4b22b933Srs200217 Added (commented out) debugging messages
32*4b22b933Srs200217
33*4b22b933Srs200217 Revision 1.198 2006/06/27 20:16:07 cheshire
34*4b22b933Srs200217 Fix code layout
35*4b22b933Srs200217
36*4b22b933Srs200217 Revision 1.197 2006/05/18 01:32:35 cheshire
37*4b22b933Srs200217 <rdar://problem/4472706> iChat: Lost connection with Bonjour
38*4b22b933Srs200217 (mDNSResponder insufficiently defensive against malformed browsing PTR responses)
39*4b22b933Srs200217
40*4b22b933Srs200217 Revision 1.196 2006/05/05 07:07:13 cheshire
41*4b22b933Srs200217 <rdar://problem/4538206> mDNSResponder fails when UDS reads deliver partial data
42*4b22b933Srs200217
43*4b22b933Srs200217 Revision 1.195 2006/04/25 20:56:28 mkrochma
44*4b22b933Srs200217 Added comment about previous checkin
45*4b22b933Srs200217
46*4b22b933Srs200217 Revision 1.194 2006/04/25 18:29:36 mkrochma
47*4b22b933Srs200217 Workaround for warning: unused variable 'status' when building mDNSPosix
48*4b22b933Srs200217
49*4b22b933Srs200217 Revision 1.193 2006/03/19 17:14:38 cheshire
50*4b22b933Srs200217 <rdar://problem/4483117> Need faster purging of stale records
51*4b22b933Srs200217 read_rr_from_ipc_msg was not setting namehash and rdatahash
52*4b22b933Srs200217
53*4b22b933Srs200217 Revision 1.192 2006/03/18 20:58:32 cheshire
54*4b22b933Srs200217 Misplaced curly brace
55*4b22b933Srs200217
56*4b22b933Srs200217 Revision 1.191 2006/03/10 22:19:43 cheshire
57*4b22b933Srs200217 Update debugging message in resolve_result_callback() to indicate whether event is ADD or RMV
58*4b22b933Srs200217
59*4b22b933Srs200217 Revision 1.190 2006/03/10 21:56:12 cheshire
60*4b22b933Srs200217 <rdar://problem/4111464> After record update, old record sometimes remains in cache
61*4b22b933Srs200217 When service TXT and SRV record both change, clients with active resolve calls get *two* callbacks, one
62*4b22b933Srs200217 when the TXT data changes, and then immediately afterwards a second callback with the new port number
63*4b22b933Srs200217 This change suppresses the first unneccessary (and confusing) callback
64*4b22b933Srs200217
65*4b22b933Srs200217 Revision 1.189 2006/01/06 00:56:31 cheshire
66*4b22b933Srs200217 <rdar://problem/4400573> Should remove PID file on exit
67*4b22b933Srs200217
68*4b22b933Srs200217 Revision 1.188 2005/10/11 22:15:03 cheshire
69*4b22b933Srs200217 <rdar://problem/4296042> Add memory corruption safeguards to uds_daemon.c
70*4b22b933Srs200217 Only compile uds_validatelists() when building for Mac OS X
71*4b22b933Srs200217
72*4b22b933Srs200217 Revision 1.187 2005/10/11 20:30:27 cheshire
73*4b22b933Srs200217 <rdar://problem/4296042> Add memory corruption safeguards to uds_daemon.c
74*4b22b933Srs200217
75*4b22b933Srs200217 Revision 1.186 2005/09/12 07:11:53 herscher
76*4b22b933Srs200217 <rdar://problem/4248878> Lazily call RegisterSearchDomains to workaround crashes of several routers. This code is conditionally compiled, and currently is only enabled on Windows platforms.
77*4b22b933Srs200217
78*4b22b933Srs200217 Revision 1.185 2005/07/29 00:55:10 ksekar
79*4b22b933Srs200217 Removed validation check in uds_validatelists which generated false alarms
80*4b22b933Srs200217
81*4b22b933Srs200217 Revision 1.184 2005/07/04 22:40:26 cheshire
82*4b22b933Srs200217 Additional debugging code to help catch memory corruption
83*4b22b933Srs200217
84*4b22b933Srs200217 Revision 1.183 2005/06/13 22:39:11 cheshire
85*4b22b933Srs200217 <rdar://problem/4144870> Missing return statement in handle_enum_request() error handling
86*4b22b933Srs200217
87*4b22b933Srs200217 Revision 1.182 2005/03/21 00:39:31 shersche
88*4b22b933Srs200217 <rdar://problem/4021486> Fix build warnings on Win32 platform
89*4b22b933Srs200217
90*4b22b933Srs200217 Revision 1.181 2005/03/20 20:21:32 shersche
91*4b22b933Srs200217 <rdar://problem/4056827> mDNSResponder crashes when incorrect interface index is passed to DNSServiceRegister()
92*4b22b933Srs200217 Text record length and data parameters must be initialized to 0 and NULL to ensure that the service request
93*4b22b933Srs200217 object is cleaned up correctly when encountering an interface index error.
94*4b22b933Srs200217
95*4b22b933Srs200217 Revision 1.180 2005/03/10 00:13:12 cheshire
96*4b22b933Srs200217 <rdar://problem/4043098> DNSServiceBrowse no longer returning error codes for invalid types
97*4b22b933Srs200217 In handle_browse_request(), mStatus err was being set correctly if an error occurred,
98*4b22b933Srs200217 but the end of the function returned mStatus_NoError intead of err.
99*4b22b933Srs200217
100*4b22b933Srs200217 Revision 1.179 2005/03/04 02:47:26 ksekar
101*4b22b933Srs200217 <rdar://problem/4026393> SCPreference domains disappear from enumeration when moving out from firewall
102*4b22b933Srs200217
103*4b22b933Srs200217 Revision 1.178 2005/02/25 19:35:38 ksekar
104*4b22b933Srs200217 <rdar://problem/4023750> Non-local empty string registration failures should not return errors to caller
105*4b22b933Srs200217
106*4b22b933Srs200217 Revision 1.177 2005/02/25 03:05:41 cheshire
107*4b22b933Srs200217 Change "broken pipe" message to debugf()
108*4b22b933Srs200217
109*4b22b933Srs200217 Revision 1.176 2005/02/24 18:44:45 ksekar
110*4b22b933Srs200217 <rdar://problem/4018516> Printer Sharing does not get re-registered with wide-area
111*4b22b933Srs200217
112*4b22b933Srs200217 Revision 1.175 2005/02/21 21:31:25 ksekar
113*4b22b933Srs200217 <rdar://problem/4015162> changed LogMsg to debugf
114*4b22b933Srs200217
115*4b22b933Srs200217 Revision 1.174 2005/02/20 01:41:17 cheshire
116*4b22b933Srs200217 Fix compiler signed/unsigned warning
117*4b22b933Srs200217
118*4b22b933Srs200217 Revision 1.173 2005/02/18 01:26:42 cheshire
119*4b22b933Srs200217 <rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
120*4b22b933Srs200217 Log additional information about failed client
121*4b22b933Srs200217
122*4b22b933Srs200217 Revision 1.172 2005/02/18 00:58:35 cheshire
123*4b22b933Srs200217 <rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
124*4b22b933Srs200217
125*4b22b933Srs200217 Revision 1.171 2005/02/18 00:43:12 cheshire
126*4b22b933Srs200217 <rdar://problem/4010245> mDNSResponder should auto-truncate service names that are too long
127*4b22b933Srs200217
128*4b22b933Srs200217 Revision 1.170 2005/02/16 01:15:02 cheshire
129*4b22b933Srs200217 Improve LogOperation() debugging messages for DNSServiceBrowse and DNSServiceRegister
130*4b22b933Srs200217
131*4b22b933Srs200217 Revision 1.169 2005/02/08 01:57:14 cheshire
132*4b22b933Srs200217 More detailed error reporting in udsserver_init()
133*4b22b933Srs200217
134*4b22b933Srs200217 Revision 1.168 2005/02/03 00:44:37 cheshire
135*4b22b933Srs200217 <rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
136*4b22b933Srs200217
137*4b22b933Srs200217 Revision 1.167 2005/02/02 02:19:32 cheshire
138*4b22b933Srs200217 Add comment explaining why unlink(MDNS_UDS_SERVERPATH); fails
139*4b22b933Srs200217
140*4b22b933Srs200217 Revision 1.166 2005/02/01 19:58:52 ksekar
141*4b22b933Srs200217 Shortened cryptic "broken pipe" syslog message
142*4b22b933Srs200217
143*4b22b933Srs200217 Revision 1.165 2005/02/01 19:56:47 ksekar
144*4b22b933Srs200217 Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording
145*4b22b933Srs200217
146*4b22b933Srs200217 Revision 1.164 2005/01/28 06:07:55 cheshire
147*4b22b933Srs200217 Don't use deliver_error() from within handle_regrecord_request()
148*4b22b933Srs200217
149*4b22b933Srs200217 Revision 1.163 2005/01/28 01:39:16 cheshire
150*4b22b933Srs200217 Include file descriptor number in "broken pipe" message
151*4b22b933Srs200217
152*4b22b933Srs200217 Revision 1.162 2005/01/27 23:59:20 cheshire
153*4b22b933Srs200217 Remove extraneous LogMsg
154*4b22b933Srs200217
155*4b22b933Srs200217 Revision 1.161 2005/01/27 22:57:56 cheshire
156*4b22b933Srs200217 Fix compile errors on gcc4
157*4b22b933Srs200217
158*4b22b933Srs200217 Revision 1.160 2005/01/27 20:52:11 cheshire
159*4b22b933Srs200217 <rdar://problem/3972566> mDNSResponder leaks sockets for add/update/remove record calls
160*4b22b933Srs200217
161*4b22b933Srs200217 Revision 1.159 2005/01/27 01:45:25 cheshire
162*4b22b933Srs200217 <rdar://problem/3976147> mDNSResponder should never call exit(1);
163*4b22b933Srs200217
164*4b22b933Srs200217 Revision 1.158 2005/01/25 17:28:07 ksekar
165*4b22b933Srs200217 <rdar://problem/3971467> Should not return "local" twice for domain enumeration
166*4b22b933Srs200217
167*4b22b933Srs200217 Revision 1.157 2005/01/21 02:20:39 cheshire
168*4b22b933Srs200217 Fix mistake in LogOperation() format string
169*4b22b933Srs200217
170*4b22b933Srs200217 Revision 1.156 2005/01/19 19:15:36 ksekar
171*4b22b933Srs200217 Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
172*4b22b933Srs200217
173*4b22b933Srs200217 Revision 1.155 2005/01/19 03:00:47 cheshire
174*4b22b933Srs200217 Show Add/Rmv in DNSServiceBrowse LogOperation() message
175*4b22b933Srs200217
176*4b22b933Srs200217 Revision 1.154 2005/01/15 00:56:42 ksekar
177*4b22b933Srs200217 <rdar://problem/3954575> Unicast services don't disappear when logging
178*4b22b933Srs200217 out of VPN
179*4b22b933Srs200217
180*4b22b933Srs200217 Revision 1.153 2005/01/14 18:44:28 ksekar
181*4b22b933Srs200217 <rdar://problem/3954609> mDNSResponder is crashing when changing domains
182*4b22b933Srs200217
183*4b22b933Srs200217 Revision 1.152 2005/01/13 17:16:38 ksekar
184*4b22b933Srs200217 Back out checkin 1.150 - correct fix is on clientstub side
185*4b22b933Srs200217
186*4b22b933Srs200217 Revision 1.151 2005/01/11 21:06:29 ksekar
187*4b22b933Srs200217 Changed now-benign LogMsg to debugf
188*4b22b933Srs200217
189*4b22b933Srs200217 Revision 1.150 2005/01/07 23:59:15 ksekar
190*4b22b933Srs200217 <rdar://problem/3942900> dnd-sd shows the wrong port numbers
191*4b22b933Srs200217
192*4b22b933Srs200217 Revision 1.149 2004/12/20 23:20:35 cheshire
193*4b22b933Srs200217 <rdar://problem/3928361> mDNSResponder crashes repeatedly when printer sharing is enabled
194*4b22b933Srs200217 Make sure to call mDNS_SetupResourceRecord() for all newly created AuthRecords
195*4b22b933Srs200217
196*4b22b933Srs200217 Revision 1.148 2004/12/20 20:37:35 cheshire
197*4b22b933Srs200217 AllowRemoteQuery not set for the extras in a ServiceRecordSet
198*4b22b933Srs200217
199*4b22b933Srs200217 Revision 1.147 2004/12/20 00:15:41 cheshire
200*4b22b933Srs200217 Include client file descriptor numbers in udsserver_info() output
201*4b22b933Srs200217
202*4b22b933Srs200217 Revision 1.146 2004/12/17 05:25:47 cheshire
203*4b22b933Srs200217 <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
204*4b22b933Srs200217
205*4b22b933Srs200217 Revision 1.145 2004/12/16 21:39:46 cheshire
206*4b22b933Srs200217 Include CacheGroup objects in CacheUsed count
207*4b22b933Srs200217
208*4b22b933Srs200217 Revision 1.144 2004/12/16 21:27:38 ksekar
209*4b22b933Srs200217 Fixed build failures when compiled with verbose debugging messages
210*4b22b933Srs200217
211*4b22b933Srs200217 Revision 1.143 2004/12/16 20:13:02 cheshire
212*4b22b933Srs200217 <rdar://problem/3324626> Cache memory management improvements
213*4b22b933Srs200217
214*4b22b933Srs200217 Revision 1.142 2004/12/16 08:07:33 shersche
215*4b22b933Srs200217 Fix compiler error (mixed declarations and code) on Windows
216*4b22b933Srs200217
217*4b22b933Srs200217 Revision 1.141 2004/12/16 01:56:21 cheshire
218*4b22b933Srs200217 Improve DNSServiceEnumerateDomains syslog message
219*4b22b933Srs200217
220*4b22b933Srs200217 Revision 1.140 2004/12/14 03:02:10 ksekar
221*4b22b933Srs200217 <rdar://problem/3919016> Rare race condition can cause crash
222*4b22b933Srs200217
223*4b22b933Srs200217 Revision 1.139 2004/12/13 21:18:45 ksekar
224*4b22b933Srs200217 Include uDNS registrations in CountPeerRegistrations
225*4b22b933Srs200217
226*4b22b933Srs200217 Revision 1.138 2004/12/13 18:23:18 ksekar
227*4b22b933Srs200217 <rdar://problem/3915805> mDNSResponder error when quitting iChat -
228*4b22b933Srs200217 don't close sockets delivering errors to blocked clients
229*4b22b933Srs200217
230*4b22b933Srs200217 Revision 1.137 2004/12/13 00:09:22 ksekar
231*4b22b933Srs200217 <rdar://problem/3915805> mDNSResponder error when quitting iChat
232*4b22b933Srs200217
233*4b22b933Srs200217 Revision 1.136 2004/12/11 01:52:10 cheshire
234*4b22b933Srs200217 <rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
235*4b22b933Srs200217
236*4b22b933Srs200217 Revision 1.135 2004/12/10 20:46:37 cheshire
237*4b22b933Srs200217 Change LogOperation message to debugf
238*4b22b933Srs200217
239*4b22b933Srs200217 Revision 1.134 2004/12/10 13:19:37 cheshire
240*4b22b933Srs200217 Add verbosedebugf() logging message in CountPeerRegistrations()
241*4b22b933Srs200217
242*4b22b933Srs200217 Revision 1.133 2004/12/10 05:27:26 cheshire
243*4b22b933Srs200217 <rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
244*4b22b933Srs200217
245*4b22b933Srs200217 Revision 1.132 2004/12/10 04:28:28 cheshire
246*4b22b933Srs200217 <rdar://problem/3914406> User not notified of name changes for services using new UDS API
247*4b22b933Srs200217
248*4b22b933Srs200217 Revision 1.131 2004/12/10 02:09:25 cheshire
249*4b22b933Srs200217 <rdar://problem/3898376> Modify default TTLs
250*4b22b933Srs200217
251*4b22b933Srs200217 Revision 1.130 2004/12/10 00:55:24 cheshire
252*4b22b933Srs200217 Add full name and type to LogOperation messages for DNSServiceAddRecord/UpdateRecord/RemoveRecord
253*4b22b933Srs200217
254*4b22b933Srs200217 Revision 1.129 2004/12/09 03:17:23 ksekar
255*4b22b933Srs200217 <rdar://problem/3910435> DomainEnumeration interface index should be zero
256*4b22b933Srs200217
257*4b22b933Srs200217 Revision 1.128 2004/12/07 21:26:05 ksekar
258*4b22b933Srs200217 <rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
259*4b22b933Srs200217
260*4b22b933Srs200217 Revision 1.127 2004/12/07 20:42:34 cheshire
261*4b22b933Srs200217 Add explicit context parameter to mDNS_RemoveRecordFromService()
262*4b22b933Srs200217
263*4b22b933Srs200217 Revision 1.126 2004/12/07 17:23:55 ksekar
264*4b22b933Srs200217 Fixed LogOperation
265*4b22b933Srs200217
266*4b22b933Srs200217 Revision 1.125 2004/12/06 21:15:23 ksekar
267*4b22b933Srs200217 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
268*4b22b933Srs200217
269*4b22b933Srs200217 Revision 1.124 2004/11/30 02:19:14 cheshire
270*4b22b933Srs200217 <rdar://problem/3827971> Raise maxfds.rlim_cur for mDNSResponder
271*4b22b933Srs200217
272*4b22b933Srs200217 Revision 1.123 2004/11/29 23:50:57 cheshire
273*4b22b933Srs200217 Checkin 1.122 not necessary
274*4b22b933Srs200217
275*4b22b933Srs200217 Revision 1.122 2004/11/24 17:55:01 ksekar
276*4b22b933Srs200217 Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
277*4b22b933Srs200217
278*4b22b933Srs200217 Revision 1.121 2004/11/24 04:45:52 cheshire
279*4b22b933Srs200217 Spelling mistake
280*4b22b933Srs200217
281*4b22b933Srs200217 Revision 1.120 2004/11/24 00:10:44 cheshire
282*4b22b933Srs200217 <rdar://problem/3869241> For unicast operations, verify that service types are legal
283*4b22b933Srs200217
284*4b22b933Srs200217 Revision 1.119 2004/11/23 23:54:17 ksekar
285*4b22b933Srs200217 <rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
286*4b22b933Srs200217 can crash mDNSResponder
287*4b22b933Srs200217
288*4b22b933Srs200217 Revision 1.118 2004/11/23 22:33:01 cheshire
289*4b22b933Srs200217 <rdar://problem/3654910> Remove temporary workaround code for iChat
290*4b22b933Srs200217
291*4b22b933Srs200217 Revision 1.117 2004/11/23 20:23:10 ksekar
292*4b22b933Srs200217 Fixed LogOperation that causes crash on connected service deregistrations
293*4b22b933Srs200217
294*4b22b933Srs200217 Revision 1.116 2004/11/23 03:39:47 cheshire
295*4b22b933Srs200217 Let interface name/index mapping capability live directly in JNISupport.c,
296*4b22b933Srs200217 instead of having to call through to the daemon via IPC to get this information.
297*4b22b933Srs200217
298*4b22b933Srs200217 Revision 1.115 2004/11/13 00:12:53 ksekar
299*4b22b933Srs200217 Fixed some LogOperation printf converstions for debug builds.
300*4b22b933Srs200217
301*4b22b933Srs200217 Revision 1.114 2004/11/12 18:25:45 shersche
302*4b22b933Srs200217 Tidy up cross platform usleep code fragment.
303*4b22b933Srs200217
304*4b22b933Srs200217 Revision 1.113 2004/11/12 03:21:41 rpantos
305*4b22b933Srs200217 rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
306*4b22b933Srs200217
307*4b22b933Srs200217 Revision 1.112 2004/11/11 16:58:32 ksekar
308*4b22b933Srs200217 Removed unused code (previously wrapped in #if 0)
309*4b22b933Srs200217
310*4b22b933Srs200217 Revision 1.111 2004/11/05 22:47:37 shersche
311*4b22b933Srs200217 Conditionally compile usleep(1000) to be Sleep(1) on Windows
312*4b22b933Srs200217 Submitted by: Pavel Repin <prepin@gmail.com>
313*4b22b933Srs200217
314*4b22b933Srs200217 Revision 1.110 2004/11/05 19:56:56 ksekar
315*4b22b933Srs200217 <rdar://problem/3862646> We no longer need to browse .Mac domains by
316*4b22b933Srs200217 default - changed #if 0 to more descriptive #ifdef _HAVE_SETDOMAIN_SUPPORT_
317*4b22b933Srs200217
318*4b22b933Srs200217 Revision 1.109 2004/11/04 03:40:45 cheshire
319*4b22b933Srs200217 More debugging messages
320*4b22b933Srs200217
321*4b22b933Srs200217 Revision 1.108 2004/11/03 02:25:51 cheshire
322*4b22b933Srs200217 <rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
323*4b22b933Srs200217
324*4b22b933Srs200217 Revision 1.107 2004/11/02 19:39:23 ksekar
325*4b22b933Srs200217 <rdar://problem/3862646> We no longer need to browse .Mac domains by default
326*4b22b933Srs200217
327*4b22b933Srs200217 Revision 1.106 2004/11/02 02:12:21 cheshire
328*4b22b933Srs200217 <rdar://problem/3839111> Remove unnecessary memory allocations
329*4b22b933Srs200217
330*4b22b933Srs200217 Revision 1.105 2004/10/28 19:07:19 cheshire
331*4b22b933Srs200217 Add some more debugging checks and improved LogOperation() messages
332*4b22b933Srs200217
333*4b22b933Srs200217 Revision 1.104 2004/10/26 18:53:15 cheshire
334*4b22b933Srs200217 Avoid unused variable warning
335*4b22b933Srs200217
336*4b22b933Srs200217 Revision 1.103 2004/10/26 07:15:55 cheshire
337*4b22b933Srs200217 Add file descriptor number to all LogOperation messages
338*4b22b933Srs200217
339*4b22b933Srs200217 Revision 1.102 2004/10/26 06:11:42 cheshire
340*4b22b933Srs200217 Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
341*4b22b933Srs200217
342*4b22b933Srs200217 Revision 1.101 2004/10/26 04:31:44 cheshire
343*4b22b933Srs200217 Rename CountSubTypes() as ChopSubTypes()
344*4b22b933Srs200217
345*4b22b933Srs200217 Revision 1.100 2004/10/26 01:17:48 cheshire
346*4b22b933Srs200217 Use "#if 0" instead of commenting out code
347*4b22b933Srs200217
348*4b22b933Srs200217 Revision 1.99 2004/10/19 21:33:22 cheshire
349*4b22b933Srs200217 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
350*4b22b933Srs200217 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
351*4b22b933Srs200217 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
352*4b22b933Srs200217
353*4b22b933Srs200217 Revision 1.98 2004/10/14 01:59:33 cheshire
354*4b22b933Srs200217 <rdar://problem/3839208> UDS resolves don't work for uDNS services
355*4b22b933Srs200217
356*4b22b933Srs200217 Revision 1.97 2004/10/13 00:58:35 cheshire
357*4b22b933Srs200217 <rdar://problem/3832738> Registering a proxy doesn't work
358*4b22b933Srs200217
359*4b22b933Srs200217 Revision 1.96 2004/09/30 00:25:00 ksekar
360*4b22b933Srs200217 <rdar://problem/3695802> Dynamically update default registration domains on config change
361*4b22b933Srs200217
362*4b22b933Srs200217 Revision 1.95 2004/09/26 23:20:36 ksekar
363*4b22b933Srs200217 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
364*4b22b933Srs200217
365*4b22b933Srs200217 Revision 1.94 2004/09/22 18:27:06 ksekar
366*4b22b933Srs200217 <rdar://problem/3811427> allow DNSServiceAddRecord to pass zero to get
367*4b22b933Srs200217 default record TTL
368*4b22b933Srs200217
369*4b22b933Srs200217 Revision 1.93 2004/09/22 02:39:44 cheshire
370*4b22b933Srs200217 <rdar://problem/3810757> Allow DNSServiceRegisterRecord to pass zero to get default record TTL
371*4b22b933Srs200217
372*4b22b933Srs200217 Revision 1.92 2004/09/22 02:34:04 cheshire
373*4b22b933Srs200217 Rename parameter "ttl" to "GetTTL" for clarity
374*4b22b933Srs200217
375*4b22b933Srs200217 Revision 1.91 2004/09/22 02:25:43 cheshire
376*4b22b933Srs200217 Fix spelling errors
377*4b22b933Srs200217
378*4b22b933Srs200217 Revision 1.90 2004/09/21 23:40:12 ksekar
379*4b22b933Srs200217 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
380*4b22b933Srs200217
381*4b22b933Srs200217 Revision 1.89 2004/09/21 23:29:51 cheshire
382*4b22b933Srs200217 <rdar://problem/3680045> DNSServiceResolve should delay sending packets
383*4b22b933Srs200217
384*4b22b933Srs200217 Revision 1.88 2004/09/21 23:12:46 cheshire
385*4b22b933Srs200217 Reorder initialization of question fields to match structure order
386*4b22b933Srs200217
387*4b22b933Srs200217 Revision 1.87 2004/09/21 22:18:33 cheshire
388*4b22b933Srs200217 In SIGINFO output, display a '-' next to records that have the Unique bit set
389*4b22b933Srs200217
390*4b22b933Srs200217 Revision 1.86 2004/09/21 21:05:11 cheshire
391*4b22b933Srs200217 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
392*4b22b933Srs200217 into mDNSShared/uds_daemon.c
393*4b22b933Srs200217
394*4b22b933Srs200217 Revision 1.85 2004/09/18 01:11:58 ksekar
395*4b22b933Srs200217 <rdar://problem/3806734> Add a user's default domain to empty-string browse list
396*4b22b933Srs200217
397*4b22b933Srs200217 Revision 1.84 2004/09/17 01:08:55 cheshire
398*4b22b933Srs200217 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
399*4b22b933Srs200217 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
400*4b22b933Srs200217 declared in that file are ONLY appropriate to single-address-space embedded applications.
401*4b22b933Srs200217 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
402*4b22b933Srs200217
403*4b22b933Srs200217 Revision 1.83 2004/09/16 23:26:33 cheshire
404*4b22b933Srs200217 Move version check inside preceeding "if" that checks we have a complete header
405*4b22b933Srs200217
406*4b22b933Srs200217 Revision 1.82 2004/09/16 23:14:25 cheshire
407*4b22b933Srs200217 Changes for Windows compatibility
408*4b22b933Srs200217
409*4b22b933Srs200217 Revision 1.81 2004/09/16 21:46:38 ksekar
410*4b22b933Srs200217 <rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area domain
411*4b22b933Srs200217
412*4b22b933Srs200217 Revision 1.80 2004/09/16 01:58:23 cheshire
413*4b22b933Srs200217 Fix compiler warnings
414*4b22b933Srs200217
415*4b22b933Srs200217 Revision 1.79 2004/09/16 00:24:49 cheshire
416*4b22b933Srs200217 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
417*4b22b933Srs200217
418*4b22b933Srs200217 Revision 1.78 2004/09/15 21:44:20 cheshire
419*4b22b933Srs200217 <rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
420*4b22b933Srs200217 Show time value in log to help diagnose errors
421*4b22b933Srs200217
422*4b22b933Srs200217 Revision 1.77 2004/09/15 00:19:18 cheshire
423*4b22b933Srs200217 <rdar://problem/3785823> read_rr_from_ipc_msg should use mDNS_SetupResourceRecord()
424*4b22b933Srs200217
425*4b22b933Srs200217 Revision 1.76 2004/09/02 06:39:52 cheshire
426*4b22b933Srs200217 Minor textual cleanup for clarity
427*4b22b933Srs200217
428*4b22b933Srs200217 Revision 1.75 2004/09/02 03:48:47 cheshire
429*4b22b933Srs200217 <rdar://problem/3709039> Disable targeted unicast query support by default
430*4b22b933Srs200217 1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
431*4b22b933Srs200217 2. New field AllowRemoteQuery in AuthRecord structure
432*4b22b933Srs200217 3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
433*4b22b933Srs200217 4. mDNS.c only answers remote queries if AllowRemoteQuery is set
434*4b22b933Srs200217
435*4b22b933Srs200217 Revision 1.74 2004/08/25 02:32:47 cheshire
436*4b22b933Srs200217 Minor cleanup: replace "®type[0]" with "regtype"
437*4b22b933Srs200217
438*4b22b933Srs200217 Revision 1.73 2004/08/25 02:30:40 cheshire
439*4b22b933Srs200217 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
440*4b22b933Srs200217
441*4b22b933Srs200217 Revision 1.72 2004/08/14 03:22:42 cheshire
442*4b22b933Srs200217 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
443*4b22b933Srs200217 Add GetUserSpecifiedDDNSName() routine
444*4b22b933Srs200217 Convert ServiceRegDomain to domainname instead of C string
445*4b22b933Srs200217 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
446*4b22b933Srs200217
447*4b22b933Srs200217 Revision 1.71 2004/08/11 04:21:21 rpantos
448*4b22b933Srs200217 Fix Windows build.
449*4b22b933Srs200217
450*4b22b933Srs200217 Revision 1.70 2004/08/11 02:07:00 cheshire
451*4b22b933Srs200217 Remove "mDNS *globalInstance" parameter from udsserver_init()
452*4b22b933Srs200217 Move CheckForDuplicateRegistrations from daemon.c
453*4b22b933Srs200217 <rdar://problem/3501938> No warning when accidentally registering the same service multiple times using socket API
454*4b22b933Srs200217
455*4b22b933Srs200217 Revision 1.69 2004/08/10 16:14:48 cheshire
456*4b22b933Srs200217 Fix debug builds (oops)
457*4b22b933Srs200217
458*4b22b933Srs200217 Revision 1.68 2004/08/10 06:24:56 cheshire
459*4b22b933Srs200217 Use types with precisely defined sizes for 'op' and 'reg_index', for better
460*4b22b933Srs200217 compatibility if the daemon and the client stub are built using different compilers
461*4b22b933Srs200217
462*4b22b933Srs200217 Revision 1.67 2004/07/27 07:14:16 shersche
463*4b22b933Srs200217 make error socket non-blocking after call to connect()
464*4b22b933Srs200217
465*4b22b933Srs200217 Revision 1.66 2004/07/13 21:24:25 rpantos
466*4b22b933Srs200217 Fix for <rdar://problem/3701120>.
467*4b22b933Srs200217
468*4b22b933Srs200217 Revision 1.65 2004/06/26 03:17:14 shersche
469*4b22b933Srs200217 implement cross-platform strerror function
470*4b22b933Srs200217
471*4b22b933Srs200217 Submitted by: herscher
472*4b22b933Srs200217
473*4b22b933Srs200217 Revision 1.64 2004/06/25 00:26:27 rpantos
474*4b22b933Srs200217 Changes to fix the Posix build on Solaris.
475*4b22b933Srs200217
476*4b22b933Srs200217 Revision 1.63 2004/06/24 03:43:44 rpantos
477*4b22b933Srs200217 Fix previous checkin so it builds on Windows.
478*4b22b933Srs200217
479*4b22b933Srs200217 Revision 1.62 2004/06/24 00:57:08 ksekar
480*4b22b933Srs200217 Replaced code acccidentally removed in checkin 1.59.
481*4b22b933Srs200217
482*4b22b933Srs200217 Revision 1.61 2004/06/19 00:09:39 cheshire
483*4b22b933Srs200217 Remove unused strsep() implementation
484*4b22b933Srs200217
485*4b22b933Srs200217 Revision 1.60 2004/06/18 19:10:00 cheshire
486*4b22b933Srs200217 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
487*4b22b933Srs200217
488*4b22b933Srs200217 Revision 1.59 2004/06/18 05:10:31 rpantos
489*4b22b933Srs200217 Changes to allow code to be used on Windows
490*4b22b933Srs200217
491*4b22b933Srs200217 Revision 1.58 2004/06/15 03:54:08 cheshire
492*4b22b933Srs200217 Include mDNS_TimeNow(&mDNSStorage) in SIGINFO output
493*4b22b933Srs200217
494*4b22b933Srs200217 Revision 1.57 2004/06/12 01:47:27 ksekar
495*4b22b933Srs200217 <rdar://problem/3690241>: BBEdit crashes when trying to check for newer version
496*4b22b933Srs200217 udsserver_idle compared time in ticks to interval in seconds.
497*4b22b933Srs200217
498*4b22b933Srs200217 Revision 1.56 2004/06/12 01:35:47 cheshire
499*4b22b933Srs200217 Changes for Windows compatibility
500*4b22b933Srs200217
501*4b22b933Srs200217 Revision 1.55 2004/06/05 00:04:27 cheshire
502*4b22b933Srs200217 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
503*4b22b933Srs200217
504*4b22b933Srs200217 Revision 1.54 2004/06/01 22:22:52 ksekar
505*4b22b933Srs200217 <rdar://problem/3668635>: wide-area default registrations should be in
506*4b22b933Srs200217 .local too
507*4b22b933Srs200217
508*4b22b933Srs200217 Revision 1.53 2004/05/28 23:42:37 ksekar
509*4b22b933Srs200217 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
510*4b22b933Srs200217
511*4b22b933Srs200217 Revision 1.52 2004/05/26 00:39:49 ksekar
512*4b22b933Srs200217 <rdar://problem/3667105>: wide-area DNS-SD servers don't appear in
513*4b22b933Srs200217 Finder
514*4b22b933Srs200217 Use local-only InterfaceID for GetDomains calls for sockets-API
515*4b22b933Srs200217
516*4b22b933Srs200217 Revision 1.51 2004/05/18 23:51:27 cheshire
517*4b22b933Srs200217 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
518*4b22b933Srs200217
519*4b22b933Srs200217 Revision 1.50 2004/05/14 16:39:47 ksekar
520*4b22b933Srs200217 Browse for iChat locally for now.
521*4b22b933Srs200217
522*4b22b933Srs200217 Revision 1.49 2004/05/13 21:33:52 ksekar
523*4b22b933Srs200217 Clean up non-local registration control via config file. Force iChat
524*4b22b933Srs200217 registrations to be local for now.
525*4b22b933Srs200217
526*4b22b933Srs200217 Revision 1.48 2004/05/13 04:13:19 ksekar
527*4b22b933Srs200217 Updated SIGINFO handler for multi-domain browses
528*4b22b933Srs200217
529*4b22b933Srs200217 Revision 1.47 2004/05/12 22:04:01 ksekar
530*4b22b933Srs200217 Implemented multi-domain browsing by default for uds_daemon.
531*4b22b933Srs200217
532*4b22b933Srs200217 Revision 1.46 2004/05/06 18:42:58 ksekar
533*4b22b933Srs200217 General dns_sd.h API cleanup, including the following radars:
534*4b22b933Srs200217 <rdar://problem/3592068>: Remove flags with zero value
535*4b22b933Srs200217 <rdar://problem/3479569>: Passing in NULL causes a crash.
536*4b22b933Srs200217
537*4b22b933Srs200217 Revision 1.45 2004/03/12 08:49:28 cheshire
538*4b22b933Srs200217 #include <sys/socket.h>
539*4b22b933Srs200217
540*4b22b933Srs200217 Revision 1.44 2004/02/25 01:25:27 ksekar
541*4b22b933Srs200217 <rdar://problem/3569212>: DNSServiceRegisterRecord flags not error-checked
542*4b22b933Srs200217
543*4b22b933Srs200217 Revision 1.43 2004/02/24 01:46:40 cheshire
544*4b22b933Srs200217 Manually reinstate lost checkin 1.36
545*4b22b933Srs200217
546*4b22b933Srs200217 Revision 1.42 2004/02/05 19:39:29 cheshire
547*4b22b933Srs200217 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
548*4b22b933Srs200217 so that all platforms get this functionality
549*4b22b933Srs200217
550*4b22b933Srs200217 Revision 1.41 2004/02/03 18:59:02 cheshire
551*4b22b933Srs200217 Change "char *domain" parameter for format_enumeration_reply to "const char *domain"
552*4b22b933Srs200217
553*4b22b933Srs200217 Revision 1.40 2004/01/28 03:41:00 cheshire
554*4b22b933Srs200217 <rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
555*4b22b933Srs200217
556*4b22b933Srs200217 Revision 1.39 2004/01/25 00:03:21 cheshire
557*4b22b933Srs200217 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
558*4b22b933Srs200217
559*4b22b933Srs200217 Revision 1.38 2004/01/19 19:51:46 cheshire
560*4b22b933Srs200217 Fix compiler error (mixed declarations and code) on some versions of Linux
561*4b22b933Srs200217
562*4b22b933Srs200217 Revision 1.37 2003/12/08 21:11:42 rpantos
563*4b22b933Srs200217 Changes necessary to support mDNSResponder on Linux.
564*4b22b933Srs200217
565*4b22b933Srs200217 Revision 1.36 2003/12/04 23:40:57 cheshire
566*4b22b933Srs200217 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
567*4b22b933Srs200217 Fix some more code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
568*4b22b933Srs200217
569*4b22b933Srs200217 Revision 1.35 2003/12/03 19:10:22 ksekar
570*4b22b933Srs200217 <rdar://problem/3498644>: malloc'd data not zero'd
571*4b22b933Srs200217
572*4b22b933Srs200217 Revision 1.34 2003/12/03 02:00:01 ksekar
573*4b22b933Srs200217 <rdar://problem/3498644>: malloc'd data not zero'd
574*4b22b933Srs200217
575*4b22b933Srs200217 Revision 1.33 2003/11/22 01:18:46 ksekar
576*4b22b933Srs200217 <rdar://problem/3486646>: config change handler not called for dns-sd services
577*4b22b933Srs200217
578*4b22b933Srs200217 Revision 1.32 2003/11/20 21:46:12 ksekar
579*4b22b933Srs200217 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
580*4b22b933Srs200217
581*4b22b933Srs200217 Revision 1.31 2003/11/20 20:33:05 ksekar
582*4b22b933Srs200217 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
583*4b22b933Srs200217
584*4b22b933Srs200217 Revision 1.30 2003/11/20 02:10:55 ksekar
585*4b22b933Srs200217 <rdar://problem/3486643>: cleanup DNSServiceAdd/RemoveRecord
586*4b22b933Srs200217
587*4b22b933Srs200217 Revision 1.29 2003/11/14 21:18:32 cheshire
588*4b22b933Srs200217 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
589*4b22b933Srs200217 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
590*4b22b933Srs200217
591*4b22b933Srs200217 Revision 1.28 2003/11/08 22:18:29 cheshire
592*4b22b933Srs200217 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
593*4b22b933Srs200217
594*4b22b933Srs200217 Revision 1.27 2003/11/05 22:44:57 ksekar
595*4b22b933Srs200217 <rdar://problem/3335230>: No bounds checking when reading data from client
596*4b22b933Srs200217 Reviewed by: Stuart Cheshire
597*4b22b933Srs200217
598*4b22b933Srs200217 Revision 1.26 2003/10/23 17:51:04 ksekar
599*4b22b933Srs200217 <rdar://problem/3335216>: handle blocked clients more efficiently
600*4b22b933Srs200217 Changed gettimeofday() to mDNS_TimeNow(&mDNSStorage);
601*4b22b933Srs200217
602*4b22b933Srs200217 Revision 1.25 2003/10/22 23:37:49 ksekar
603*4b22b933Srs200217 <rdar://problem/3459141>: crash/hang in abort_client
604*4b22b933Srs200217
605*4b22b933Srs200217 Revision 1.24 2003/10/21 20:59:40 ksekar
606*4b22b933Srs200217 <rdar://problem/3335216>: handle blocked clients more efficiently
607*4b22b933Srs200217
608*4b22b933Srs200217 Revision 1.23 2003/09/23 02:12:43 cheshire
609*4b22b933Srs200217 Also include port number in list of services registered via new UDS API
610*4b22b933Srs200217
611*4b22b933Srs200217 Revision 1.22 2003/08/19 16:03:55 ksekar
612*4b22b933Srs200217 <rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
613*4b22b933Srs200217 Check termination_context for NULL before dereferencing.
614*4b22b933Srs200217
615*4b22b933Srs200217 Revision 1.21 2003/08/19 05:39:43 cheshire
616*4b22b933Srs200217 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
617*4b22b933Srs200217
618*4b22b933Srs200217 Revision 1.20 2003/08/16 03:39:01 cheshire
619*4b22b933Srs200217 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
620*4b22b933Srs200217
621*4b22b933Srs200217 Revision 1.19 2003/08/15 20:16:03 cheshire
622*4b22b933Srs200217 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
623*4b22b933Srs200217 We want to avoid touching the rdata pages, so we don't page them in.
624*4b22b933Srs200217 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
625*4b22b933Srs200217 Moved this from the RData to the ResourceRecord object.
626*4b22b933Srs200217 2. To avoid unnecessarily touching the rdata just to compare it,
627*4b22b933Srs200217 compute a hash of the rdata and store the hash in the ResourceRecord object.
628*4b22b933Srs200217
629*4b22b933Srs200217 Revision 1.18 2003/08/15 00:38:00 ksekar
630*4b22b933Srs200217 <rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
631*4b22b933Srs200217
632*4b22b933Srs200217 Revision 1.17 2003/08/14 02:18:21 cheshire
633*4b22b933Srs200217 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
634*4b22b933Srs200217
635*4b22b933Srs200217 Revision 1.16 2003/08/13 23:58:52 ksekar
636*4b22b933Srs200217 <rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
637*4b22b933Srs200217 Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
638*4b22b933Srs200217
639*4b22b933Srs200217 Revision 1.15 2003/08/13 17:30:33 ksekar
640*4b22b933Srs200217 <rdar://problem/3374671>: DNSServiceAddRecord doesn't work
641*4b22b933Srs200217 Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
642*4b22b933Srs200217
643*4b22b933Srs200217 Revision 1.14 2003/08/12 19:56:25 cheshire
644*4b22b933Srs200217 Update to APSL 2.0
645*4b22b933Srs200217
646*4b22b933Srs200217 */
647*4b22b933Srs200217
648*4b22b933Srs200217 #pragma ident "%Z%%M% %I% %E% SMI"
649*4b22b933Srs200217
650*4b22b933Srs200217 #if defined(_WIN32)
651*4b22b933Srs200217 #include <process.h>
652*4b22b933Srs200217 #define MDNS_LAZY_REGISTER_SEARCH_DOMAINS
653*4b22b933Srs200217 #define dnssd_strerror(X) win32_strerror(X)
654*4b22b933Srs200217 #define usleep(X) Sleep(((X)+999)/1000)
655*4b22b933Srs200217 static char * win32_strerror(int inErrorCode);
656*4b22b933Srs200217 #else
657*4b22b933Srs200217 #include <fcntl.h>
658*4b22b933Srs200217 #include <errno.h>
659*4b22b933Srs200217 #include <sys/ioctl.h>
660*4b22b933Srs200217 #include <sys/types.h>
661*4b22b933Srs200217 #include <sys/time.h>
662*4b22b933Srs200217 #include <sys/resource.h>
663*4b22b933Srs200217 #define dnssd_strerror(X) strerror(X)
664*4b22b933Srs200217 #endif
665*4b22b933Srs200217
666*4b22b933Srs200217 #include <stdlib.h>
667*4b22b933Srs200217 #include <stdio.h>
668*4b22b933Srs200217 #include "mDNSEmbeddedAPI.h"
669*4b22b933Srs200217 #include "DNSCommon.h"
670*4b22b933Srs200217 #include "uds_daemon.h"
671*4b22b933Srs200217 #include "dns_sd.h"
672*4b22b933Srs200217 #include "dnssd_ipc.h"
673*4b22b933Srs200217
674*4b22b933Srs200217 // Apple specific configuration functionality, not required for other platforms
675*4b22b933Srs200217 #ifdef __MACOSX__
676*4b22b933Srs200217 #include <sys/ucred.h>
677*4b22b933Srs200217 #ifndef LOCAL_PEERCRED
678*4b22b933Srs200217 #define LOCAL_PEERCRED 0x001 /* retrieve peer credentials */
679*4b22b933Srs200217 #endif // LOCAL_PEERCRED
680*4b22b933Srs200217 #endif //__MACOSX__
681*4b22b933Srs200217
682*4b22b933Srs200217 #if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
683*4b22b933Srs200217 extern mStatus dDNS_RegisterSearchDomains( mDNS * const m );
684*4b22b933Srs200217 #endif
685*4b22b933Srs200217
686*4b22b933Srs200217 // Types and Data Structures
687*4b22b933Srs200217 // ----------------------------------------------------------------------
688*4b22b933Srs200217
689*4b22b933Srs200217 typedef enum
690*4b22b933Srs200217 {
691*4b22b933Srs200217 t_uninitialized,
692*4b22b933Srs200217 t_morecoming,
693*4b22b933Srs200217 t_complete,
694*4b22b933Srs200217 t_error,
695*4b22b933Srs200217 t_terminated
696*4b22b933Srs200217 } transfer_state;
697*4b22b933Srs200217
698*4b22b933Srs200217 typedef void (*req_termination_fn)(void *);
699*4b22b933Srs200217
700*4b22b933Srs200217 typedef struct registered_record_entry
701*4b22b933Srs200217 {
702*4b22b933Srs200217 uint32_t key;
703*4b22b933Srs200217 AuthRecord *rr;
704*4b22b933Srs200217 struct registered_record_entry *next;
705*4b22b933Srs200217 client_context_t client_context;
706*4b22b933Srs200217 struct request_state *rstate;
707*4b22b933Srs200217 } registered_record_entry;
708*4b22b933Srs200217
709*4b22b933Srs200217 // A single registered service: ServiceRecordSet + bookkeeping
710*4b22b933Srs200217 // Note that we duplicate some fields from parent service_info object
711*4b22b933Srs200217 // to facilitate cleanup, when instances and parent may be deallocated at different times.
712*4b22b933Srs200217 typedef struct service_instance
713*4b22b933Srs200217 {
714*4b22b933Srs200217 struct service_instance *next;
715*4b22b933Srs200217 mDNSBool autoname; // Set if this name is tied to the Computer Name
716*4b22b933Srs200217 mDNSBool autorename; // Set if this client wants us to automatically rename on conflict
717*4b22b933Srs200217 mDNSBool allowremotequery; // Respond to unicast queries from outside the local link?
718*4b22b933Srs200217 mDNSBool rename_on_memfree; // Set on config change when we deregister original name
719*4b22b933Srs200217 domainlabel name;
720*4b22b933Srs200217 domainname domain;
721*4b22b933Srs200217 mDNSBool default_local; // is this the "local." from an empty-string registration?
722*4b22b933Srs200217 struct request_state *request;
723*4b22b933Srs200217 dnssd_sock_t sd;
724*4b22b933Srs200217 AuthRecord *subtypes;
725*4b22b933Srs200217 ServiceRecordSet srs; // note - must be last field in struct
726*4b22b933Srs200217 } service_instance;
727*4b22b933Srs200217
728*4b22b933Srs200217 // A client-created service. May reference several service_info objects if default
729*4b22b933Srs200217 // settings cause registration in multiple domains.
730*4b22b933Srs200217 typedef struct
731*4b22b933Srs200217 {
732*4b22b933Srs200217 uint16_t txtlen;
733*4b22b933Srs200217 void *txtdata;
734*4b22b933Srs200217 mDNSIPPort port;
735*4b22b933Srs200217 domainlabel name;
736*4b22b933Srs200217 char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
737*4b22b933Srs200217 domainname type;
738*4b22b933Srs200217 mDNSBool default_domain;
739*4b22b933Srs200217 domainname host;
740*4b22b933Srs200217 mDNSBool autoname; // Set if this name is tied to the Computer Name
741*4b22b933Srs200217 mDNSBool autorename; // Set if this client wants us to automatically rename on conflict
742*4b22b933Srs200217 mDNSBool allowremotequery; // Respond to unicast queries from outside the local link?
743*4b22b933Srs200217 int num_subtypes;
744*4b22b933Srs200217 mDNSInterfaceID InterfaceID;
745*4b22b933Srs200217 service_instance *instances;
746*4b22b933Srs200217 struct request_state *request;
747*4b22b933Srs200217 } service_info;
748*4b22b933Srs200217
749*4b22b933Srs200217 // for multi-domain default browsing
750*4b22b933Srs200217 typedef struct browser_t
751*4b22b933Srs200217 {
752*4b22b933Srs200217 DNSQuestion q;
753*4b22b933Srs200217 domainname domain;
754*4b22b933Srs200217 struct browser_t *next;
755*4b22b933Srs200217 } browser_t;
756*4b22b933Srs200217
757*4b22b933Srs200217 // parent struct for browser instances: list pointer plus metadata
758*4b22b933Srs200217 typedef struct
759*4b22b933Srs200217 {
760*4b22b933Srs200217 mDNSBool default_domain;
761*4b22b933Srs200217 mDNSBool ForceMCast;
762*4b22b933Srs200217 domainname regtype;
763*4b22b933Srs200217 mDNSInterfaceID interface_id;
764*4b22b933Srs200217 struct request_state *rstate;
765*4b22b933Srs200217 browser_t *browsers;
766*4b22b933Srs200217 } browser_info_t;
767*4b22b933Srs200217
768*4b22b933Srs200217 typedef struct
769*4b22b933Srs200217 {
770*4b22b933Srs200217 mStatus err; // Note: This field is in NETWORK byte order
771*4b22b933Srs200217 int nwritten;
772*4b22b933Srs200217 dnssd_sock_t sd;
773*4b22b933Srs200217 } undelivered_error_t;
774*4b22b933Srs200217
775*4b22b933Srs200217 typedef struct request_state
776*4b22b933Srs200217 {
777*4b22b933Srs200217 // connection structures
778*4b22b933Srs200217 dnssd_sock_t sd;
779*4b22b933Srs200217
780*4b22b933Srs200217 // state of read (in case message is read over several recv() calls)
781*4b22b933Srs200217 transfer_state ts;
782*4b22b933Srs200217 uint32_t hdr_bytes; // bytes of header already read
783*4b22b933Srs200217 ipc_msg_hdr hdr;
784*4b22b933Srs200217 uint32_t data_bytes; // bytes of message data already read
785*4b22b933Srs200217 char *msgbuf; // pointer to data storage to pass to free()
786*4b22b933Srs200217 char *msgdata; // pointer to data to be read from (may be modified)
787*4b22b933Srs200217 int bufsize; // size of data storage
788*4b22b933Srs200217
789*4b22b933Srs200217 // reply, termination, error, and client context info
790*4b22b933Srs200217 int no_reply; // don't send asynchronous replies to client
791*4b22b933Srs200217 int time_blocked; // record time of a blocked client
792*4b22b933Srs200217 void *client_context; // don't touch this - pointer only valid in client's addr space
793*4b22b933Srs200217 struct reply_state *replies; // corresponding (active) reply list
794*4b22b933Srs200217 undelivered_error_t *u_err;
795*4b22b933Srs200217 void *termination_context;
796*4b22b933Srs200217 req_termination_fn terminate;
797*4b22b933Srs200217
798*4b22b933Srs200217 //!!!KRS toss these pointers in a union
799*4b22b933Srs200217 // registration context associated with this request (null if not applicable)
800*4b22b933Srs200217 registered_record_entry *reg_recs; // muliple registrations for a connection-oriented request
801*4b22b933Srs200217 service_info *service_registration;
802*4b22b933Srs200217 browser_info_t *browser_info;
803*4b22b933Srs200217 struct request_state *next;
804*4b22b933Srs200217 } request_state;
805*4b22b933Srs200217
806*4b22b933Srs200217 // struct physically sits between ipc message header and call-specific fields in the message buffer
807*4b22b933Srs200217 typedef struct
808*4b22b933Srs200217 {
809*4b22b933Srs200217 DNSServiceFlags flags; // Note: This field is in NETWORK byte order
810*4b22b933Srs200217 uint32_t ifi; // Note: This field is in NETWORK byte order
811*4b22b933Srs200217 DNSServiceErrorType error; // Note: This field is in NETWORK byte order
812*4b22b933Srs200217 } reply_hdr;
813*4b22b933Srs200217
814*4b22b933Srs200217 typedef struct reply_state
815*4b22b933Srs200217 {
816*4b22b933Srs200217 // state of the transmission
817*4b22b933Srs200217 dnssd_sock_t sd;
818*4b22b933Srs200217 transfer_state ts;
819*4b22b933Srs200217 uint32_t nwriten;
820*4b22b933Srs200217 uint32_t len;
821*4b22b933Srs200217 // context of the reply
822*4b22b933Srs200217 struct request_state *request; // the request that this answers
823*4b22b933Srs200217 struct reply_state *next; // if there are multiple unsent replies
824*4b22b933Srs200217 // pointer into message buffer - allows fields to be changed after message is formatted
825*4b22b933Srs200217 ipc_msg_hdr *mhdr;
826*4b22b933Srs200217 reply_hdr *rhdr;
827*4b22b933Srs200217 char *sdata; // pointer to start of call-specific data
828*4b22b933Srs200217 // pointer to malloc'd buffer
829*4b22b933Srs200217 char *msgbuf;
830*4b22b933Srs200217 } reply_state;
831*4b22b933Srs200217
832*4b22b933Srs200217 // domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
833*4b22b933Srs200217 // structures to handle callbacks
834*4b22b933Srs200217 typedef struct
835*4b22b933Srs200217 {
836*4b22b933Srs200217 DNSQuestion question;
837*4b22b933Srs200217 mDNS_DomainType type;
838*4b22b933Srs200217 request_state *rstate;
839*4b22b933Srs200217 } domain_enum_t;
840*4b22b933Srs200217
841*4b22b933Srs200217 typedef struct
842*4b22b933Srs200217 {
843*4b22b933Srs200217 domain_enum_t *all;
844*4b22b933Srs200217 domain_enum_t *def;
845*4b22b933Srs200217 request_state *rstate;
846*4b22b933Srs200217 } enum_termination_t;
847*4b22b933Srs200217
848*4b22b933Srs200217 typedef struct
849*4b22b933Srs200217 {
850*4b22b933Srs200217 request_state *rstate;
851*4b22b933Srs200217 DNSQuestion qtxt;
852*4b22b933Srs200217 DNSQuestion qsrv;
853*4b22b933Srs200217 // const ResourceRecord *txt;
854*4b22b933Srs200217 // const ResourceRecord *srv;
855*4b22b933Srs200217 mDNSBool srv;
856*4b22b933Srs200217 mDNSBool txt;
857*4b22b933Srs200217 rdataSRV srvdata;
858*4b22b933Srs200217 mDNSu16 txtlen;
859*4b22b933Srs200217 mDNSu8 txtdata[AbsoluteMaxDNSMessageData];
860*4b22b933Srs200217 } resolve_termination_t;
861*4b22b933Srs200217
862*4b22b933Srs200217 #ifdef _HAVE_SETDOMAIN_SUPPORT_
863*4b22b933Srs200217 typedef struct default_browse_list_t
864*4b22b933Srs200217 {
865*4b22b933Srs200217 struct default_browse_list_t *next;
866*4b22b933Srs200217 uid_t uid;
867*4b22b933Srs200217 AuthRecord ptr_rec;
868*4b22b933Srs200217 } default_browse_list_t;
869*4b22b933Srs200217
870*4b22b933Srs200217 static default_browse_list_t *default_browse_list = NULL;
871*4b22b933Srs200217 #endif // _HAVE_SETDOMAIN_SUPPORT_
872*4b22b933Srs200217
873*4b22b933Srs200217 // globals
874*4b22b933Srs200217 mDNSexport mDNS mDNSStorage;
875*4b22b933Srs200217 #define gmDNS (&mDNSStorage)
876*4b22b933Srs200217
877*4b22b933Srs200217 static dnssd_sock_t listenfd = dnssd_InvalidSocket;
878*4b22b933Srs200217 static request_state * all_requests = NULL;
879*4b22b933Srs200217
880*4b22b933Srs200217 #define MAX_TIME_BLOCKED 60 * mDNSPlatformOneSecond // try to send data to a blocked client for 60 seconds before
881*4b22b933Srs200217 // terminating connection
882*4b22b933Srs200217 #define MSG_PAD_BYTES 5 // pad message buffer (read from client) with n zero'd bytes to guarantee
883*4b22b933Srs200217 // n get_string() calls w/o buffer overrun
884*4b22b933Srs200217 // private function prototypes
885*4b22b933Srs200217 mDNSlocal void connect_callback(void *info);
886*4b22b933Srs200217 mDNSlocal int read_msg(request_state *rs);
887*4b22b933Srs200217 mDNSlocal int send_msg(reply_state *rs);
888*4b22b933Srs200217 mDNSlocal void abort_request(request_state *rs);
889*4b22b933Srs200217 mDNSlocal void request_callback(void *info);
890*4b22b933Srs200217 mDNSlocal void handle_resolve_request(request_state *rstate);
891*4b22b933Srs200217 mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
892*4b22b933Srs200217 mDNSlocal void question_termination_callback(void *context);
893*4b22b933Srs200217 mDNSlocal void handle_browse_request(request_state *request);
894*4b22b933Srs200217 mDNSlocal void browse_termination_callback(void *context);
895*4b22b933Srs200217 mDNSlocal void handle_regservice_request(request_state *request);
896*4b22b933Srs200217 mDNSlocal void regservice_termination_callback(void *context);
897*4b22b933Srs200217 mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
898*4b22b933Srs200217 mDNSlocal mStatus handle_add_request(request_state *rstate);
899*4b22b933Srs200217 mDNSlocal mStatus handle_update_request(request_state *rstate);
900*4b22b933Srs200217 mDNSlocal void append_reply(request_state *req, reply_state *rep);
901*4b22b933Srs200217 mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain);
902*4b22b933Srs200217 mDNSlocal void enum_termination_callback(void *context);
903*4b22b933Srs200217 mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
904*4b22b933Srs200217 mDNSlocal void handle_query_request(request_state *rstate);
905*4b22b933Srs200217 mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
906*4b22b933Srs200217 mDNSlocal void handle_enum_request(request_state *rstate);
907*4b22b933Srs200217 mDNSlocal mStatus handle_regrecord_request(request_state *rstate);
908*4b22b933Srs200217 mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result);
909*4b22b933Srs200217 mDNSlocal void connected_registration_termination(void *context);
910*4b22b933Srs200217 mDNSlocal void handle_reconfirm_request(request_state *rstate);
911*4b22b933Srs200217 mDNSlocal AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flags);
912*4b22b933Srs200217 mDNSlocal mStatus handle_removerecord_request(request_state *rstate);
913*4b22b933Srs200217 mDNSlocal void reset_connected_rstate(request_state *rstate);
914*4b22b933Srs200217 mDNSlocal int deliver_error(request_state *rstate, mStatus err);
915*4b22b933Srs200217 mDNSlocal int deliver_async_error(request_state *rs, reply_op_t op, mStatus err);
916*4b22b933Srs200217 mDNSlocal transfer_state send_undelivered_error(request_state *rs);
917*4b22b933Srs200217 mDNSlocal reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request);
918*4b22b933Srs200217 mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd);
919*4b22b933Srs200217 mDNSlocal void my_perror(char *errmsg);
920*4b22b933Srs200217 mDNSlocal void unlink_request(request_state *rs);
921*4b22b933Srs200217 mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
922*4b22b933Srs200217 mDNSlocal void resolve_termination_callback(void *context);
923*4b22b933Srs200217 mDNSlocal int validate_message(request_state *rstate);
924*4b22b933Srs200217 mDNSlocal mStatus remove_extra(request_state *rstate, service_instance *serv);
925*4b22b933Srs200217 mDNSlocal mStatus remove_record(request_state *rstate);
926*4b22b933Srs200217 mDNSlocal void free_service_instance(service_instance *srv);
927*4b22b933Srs200217 mDNSlocal uint32_t dnssd_htonl(uint32_t l);
928*4b22b933Srs200217 mDNSlocal void handle_setdomain_request(request_state *rstate);
929*4b22b933Srs200217
930*4b22b933Srs200217 // initialization, setup/teardown functions
931*4b22b933Srs200217
932*4b22b933Srs200217 // If a platform specifies its own PID file name, we use that
933*4b22b933Srs200217 #ifndef PID_FILE
934*4b22b933Srs200217 #define PID_FILE "/var/run/mDNSResponder.pid"
935*4b22b933Srs200217 #endif
936*4b22b933Srs200217
LogClientInfo(request_state * req)937*4b22b933Srs200217 mDNSlocal void LogClientInfo(request_state *req)
938*4b22b933Srs200217 {
939*4b22b933Srs200217 void *t = req->termination_context;
940*4b22b933Srs200217 if (t)
941*4b22b933Srs200217 {
942*4b22b933Srs200217 if (req->terminate == regservice_termination_callback)
943*4b22b933Srs200217 {
944*4b22b933Srs200217 service_instance *ptr;
945*4b22b933Srs200217 for (ptr = ((service_info *)t)->instances; ptr; ptr = ptr->next)
946*4b22b933Srs200217 LogMsgNoIdent("%3d: DNSServiceRegister %##s %u", req->sd, ptr->srs.RR_SRV.resrec.name->c, SRS_PORT(&ptr->srs));
947*4b22b933Srs200217 }
948*4b22b933Srs200217 else if (req->terminate == browse_termination_callback)
949*4b22b933Srs200217 {
950*4b22b933Srs200217 browser_t *blist;
951*4b22b933Srs200217 for (blist = req->browser_info->browsers; blist; blist = blist->next)
952*4b22b933Srs200217 LogMsgNoIdent("%3d: DNSServiceBrowse %##s", req->sd, blist->q.qname.c);
953*4b22b933Srs200217 }
954*4b22b933Srs200217 else if (req->terminate == resolve_termination_callback)
955*4b22b933Srs200217 LogMsgNoIdent("%3d: DNSServiceResolve %##s", req->sd, ((resolve_termination_t *)t)->qsrv.qname.c);
956*4b22b933Srs200217 else if (req->terminate == question_termination_callback)
957*4b22b933Srs200217 LogMsgNoIdent("%3d: DNSServiceQueryRecord %##s", req->sd, ((DNSQuestion *) t)->qname.c);
958*4b22b933Srs200217 else if (req->terminate == enum_termination_callback)
959*4b22b933Srs200217 LogMsgNoIdent("%3d: DNSServiceEnumerateDomains %##s", req->sd, ((enum_termination_t *) t)->all->question.qname.c);
960*4b22b933Srs200217 }
961*4b22b933Srs200217 }
962*4b22b933Srs200217
FatalError(char * errmsg)963*4b22b933Srs200217 mDNSlocal void FatalError(char *errmsg)
964*4b22b933Srs200217 {
965*4b22b933Srs200217 LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
966*4b22b933Srs200217 *(long*)0 = 0; // On OS X abort() doesn't generate a crash log, but writing to zero does
967*4b22b933Srs200217 abort(); // On platforms where writing to zero doesn't generate an exception, abort instead
968*4b22b933Srs200217 }
969*4b22b933Srs200217
udsserver_init(void)970*4b22b933Srs200217 int udsserver_init(void)
971*4b22b933Srs200217 {
972*4b22b933Srs200217 dnssd_sockaddr_t laddr;
973*4b22b933Srs200217 int ret;
974*4b22b933Srs200217 #if defined(_WIN32)
975*4b22b933Srs200217 u_long opt = 1;
976*4b22b933Srs200217 #endif
977*4b22b933Srs200217
978*4b22b933Srs200217 // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
979*4b22b933Srs200217 if (PID_FILE[0])
980*4b22b933Srs200217 {
981*4b22b933Srs200217 FILE *fp = fopen(PID_FILE, "w");
982*4b22b933Srs200217 if (fp != NULL)
983*4b22b933Srs200217 {
984*4b22b933Srs200217 fprintf(fp, "%d\n", getpid());
985*4b22b933Srs200217 fclose(fp);
986*4b22b933Srs200217 }
987*4b22b933Srs200217 }
988*4b22b933Srs200217
989*4b22b933Srs200217 if ((listenfd = socket(AF_DNSSD, SOCK_STREAM, 0)) == dnssd_InvalidSocket)
990*4b22b933Srs200217 {
991*4b22b933Srs200217 my_perror("ERROR: socket(AF_DNSSD, SOCK_STREAM, 0); failed");
992*4b22b933Srs200217 goto error;
993*4b22b933Srs200217 }
994*4b22b933Srs200217
995*4b22b933Srs200217 bzero(&laddr, sizeof(laddr));
996*4b22b933Srs200217
997*4b22b933Srs200217 #if defined(USE_TCP_LOOPBACK)
998*4b22b933Srs200217 {
999*4b22b933Srs200217 laddr.sin_family = AF_INET;
1000*4b22b933Srs200217 laddr.sin_port = htons(MDNS_TCP_SERVERPORT);
1001*4b22b933Srs200217 laddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
1002*4b22b933Srs200217 ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
1003*4b22b933Srs200217 if (ret < 0)
1004*4b22b933Srs200217 {
1005*4b22b933Srs200217 my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
1006*4b22b933Srs200217 goto error;
1007*4b22b933Srs200217 }
1008*4b22b933Srs200217 }
1009*4b22b933Srs200217 #else
1010*4b22b933Srs200217 {
1011*4b22b933Srs200217 mode_t mask = umask(0);
1012*4b22b933Srs200217 unlink(MDNS_UDS_SERVERPATH); //OK if this fails
1013*4b22b933Srs200217 laddr.sun_family = AF_LOCAL;
1014*4b22b933Srs200217 #ifndef NOT_HAVE_SA_LEN
1015*4b22b933Srs200217 // According to Stevens (section 3.2), there is no portable way to
1016*4b22b933Srs200217 // determine whether sa_len is defined on a particular platform.
1017*4b22b933Srs200217 laddr.sun_len = sizeof(struct sockaddr_un);
1018*4b22b933Srs200217 #endif
1019*4b22b933Srs200217 strcpy(laddr.sun_path, MDNS_UDS_SERVERPATH);
1020*4b22b933Srs200217 ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
1021*4b22b933Srs200217 umask(mask);
1022*4b22b933Srs200217 if (ret < 0)
1023*4b22b933Srs200217 {
1024*4b22b933Srs200217 my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
1025*4b22b933Srs200217 goto error;
1026*4b22b933Srs200217 }
1027*4b22b933Srs200217 }
1028*4b22b933Srs200217 #endif
1029*4b22b933Srs200217
1030*4b22b933Srs200217 #if defined(_WIN32)
1031*4b22b933Srs200217 //
1032*4b22b933Srs200217 // SEH: do we even need to do this on windows? this socket
1033*4b22b933Srs200217 // will be given to WSAEventSelect which will automatically
1034*4b22b933Srs200217 // set it to non-blocking
1035*4b22b933Srs200217 //
1036*4b22b933Srs200217 if (ioctlsocket(listenfd, FIONBIO, &opt) != 0)
1037*4b22b933Srs200217 #else
1038*4b22b933Srs200217 if (fcntl(listenfd, F_SETFL, O_NONBLOCK) != 0)
1039*4b22b933Srs200217 #endif
1040*4b22b933Srs200217 {
1041*4b22b933Srs200217 my_perror("ERROR: could not set listen socket to non-blocking mode");
1042*4b22b933Srs200217 goto error;
1043*4b22b933Srs200217 }
1044*4b22b933Srs200217
1045*4b22b933Srs200217 if (listen(listenfd, LISTENQ) != 0)
1046*4b22b933Srs200217 {
1047*4b22b933Srs200217 my_perror("ERROR: could not listen on listen socket");
1048*4b22b933Srs200217 goto error;
1049*4b22b933Srs200217 }
1050*4b22b933Srs200217
1051*4b22b933Srs200217 if (mStatus_NoError != udsSupportAddFDToEventLoop(listenfd, connect_callback, (void *) NULL))
1052*4b22b933Srs200217 {
1053*4b22b933Srs200217 my_perror("ERROR: could not add listen socket to event loop");
1054*4b22b933Srs200217 goto error;
1055*4b22b933Srs200217 }
1056*4b22b933Srs200217
1057*4b22b933Srs200217 #if !defined(PLATFORM_NO_RLIMIT)
1058*4b22b933Srs200217 {
1059*4b22b933Srs200217 // Set maximum number of open file descriptors
1060*4b22b933Srs200217 #define MIN_OPENFILES 10240
1061*4b22b933Srs200217 struct rlimit maxfds, newfds;
1062*4b22b933Srs200217
1063*4b22b933Srs200217 // Due to bugs in OS X (<rdar://problem/2941095>, <rdar://problem/3342704>, <rdar://problem/3839173>)
1064*4b22b933Srs200217 // you have to get and set rlimits once before getrlimit will return sensible values
1065*4b22b933Srs200217 if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
1066*4b22b933Srs200217 if (setrlimit(RLIMIT_NOFILE, &maxfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
1067*4b22b933Srs200217
1068*4b22b933Srs200217 if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
1069*4b22b933Srs200217 newfds.rlim_max = (maxfds.rlim_max > MIN_OPENFILES) ? maxfds.rlim_max : MIN_OPENFILES;
1070*4b22b933Srs200217 newfds.rlim_cur = (maxfds.rlim_cur > MIN_OPENFILES) ? maxfds.rlim_cur : MIN_OPENFILES;
1071*4b22b933Srs200217 if (newfds.rlim_max != maxfds.rlim_max || newfds.rlim_cur != maxfds.rlim_cur)
1072*4b22b933Srs200217 if (setrlimit(RLIMIT_NOFILE, &newfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
1073*4b22b933Srs200217
1074*4b22b933Srs200217 if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
1075*4b22b933Srs200217 debugf("maxfds.rlim_max %d", (long)maxfds.rlim_max);
1076*4b22b933Srs200217 debugf("maxfds.rlim_cur %d", (long)maxfds.rlim_cur);
1077*4b22b933Srs200217 }
1078*4b22b933Srs200217 #endif
1079*4b22b933Srs200217
1080*4b22b933Srs200217 return 0;
1081*4b22b933Srs200217
1082*4b22b933Srs200217 error:
1083*4b22b933Srs200217
1084*4b22b933Srs200217 my_perror("ERROR: udsserver_init");
1085*4b22b933Srs200217 return -1;
1086*4b22b933Srs200217 }
1087*4b22b933Srs200217
udsserver_exit(void)1088*4b22b933Srs200217 int udsserver_exit(void)
1089*4b22b933Srs200217 {
1090*4b22b933Srs200217 dnssd_close(listenfd);
1091*4b22b933Srs200217
1092*4b22b933Srs200217 #if !defined(USE_TCP_LOOPBACK)
1093*4b22b933Srs200217 // Currently, we're unable to remove /var/run/mdnsd because we've changed to userid "nobody"
1094*4b22b933Srs200217 // to give up unnecessary privilege, but we need to be root to remove this Unix Domain Socket.
1095*4b22b933Srs200217 // It would be nice if we could find a solution to this problem
1096*4b22b933Srs200217 if (unlink(MDNS_UDS_SERVERPATH))
1097*4b22b933Srs200217 debugf("Unable to remove %s", MDNS_UDS_SERVERPATH);
1098*4b22b933Srs200217 #endif
1099*4b22b933Srs200217
1100*4b22b933Srs200217 if (PID_FILE[0]) unlink(PID_FILE);
1101*4b22b933Srs200217
1102*4b22b933Srs200217 return 0;
1103*4b22b933Srs200217 }
1104*4b22b933Srs200217
udsserver_idle(mDNSs32 nextevent)1105*4b22b933Srs200217 mDNSs32 udsserver_idle(mDNSs32 nextevent)
1106*4b22b933Srs200217 {
1107*4b22b933Srs200217 request_state *req = all_requests, *tmp, *prev = NULL;
1108*4b22b933Srs200217 reply_state *fptr;
1109*4b22b933Srs200217 transfer_state result;
1110*4b22b933Srs200217 mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
1111*4b22b933Srs200217
1112*4b22b933Srs200217 while(req)
1113*4b22b933Srs200217 {
1114*4b22b933Srs200217 result = t_uninitialized;
1115*4b22b933Srs200217 if (req->u_err)
1116*4b22b933Srs200217 result = send_undelivered_error(req);
1117*4b22b933Srs200217 if (result != t_error && result != t_morecoming && // don't try to send msg if send_error failed
1118*4b22b933Srs200217 (req->ts == t_complete || req->ts == t_morecoming))
1119*4b22b933Srs200217 {
1120*4b22b933Srs200217 while(req->replies)
1121*4b22b933Srs200217 {
1122*4b22b933Srs200217 if (req->replies->next) req->replies->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsMoreComing);
1123*4b22b933Srs200217 result = send_msg(req->replies);
1124*4b22b933Srs200217 if (result == t_complete)
1125*4b22b933Srs200217 {
1126*4b22b933Srs200217 fptr = req->replies;
1127*4b22b933Srs200217 req->replies = req->replies->next;
1128*4b22b933Srs200217 freeL("udsserver_idle", fptr);
1129*4b22b933Srs200217 req->time_blocked = 0; // reset failure counter after successful send
1130*4b22b933Srs200217 }
1131*4b22b933Srs200217 else if (result == t_terminated || result == t_error)
1132*4b22b933Srs200217 {
1133*4b22b933Srs200217 abort_request(req);
1134*4b22b933Srs200217 break;
1135*4b22b933Srs200217 }
1136*4b22b933Srs200217 else if (result == t_morecoming) break; // client's queues are full, move to next
1137*4b22b933Srs200217 }
1138*4b22b933Srs200217 }
1139*4b22b933Srs200217 if (result == t_morecoming)
1140*4b22b933Srs200217 {
1141*4b22b933Srs200217 if (!req->time_blocked) req->time_blocked = now;
1142*4b22b933Srs200217 debugf("udsserver_idle: client has been blocked for %ld seconds", (now - req->time_blocked) / mDNSPlatformOneSecond);
1143*4b22b933Srs200217 if (now - req->time_blocked >= MAX_TIME_BLOCKED)
1144*4b22b933Srs200217 {
1145*4b22b933Srs200217 LogMsg("Could not write data to client %d after %ld seconds - aborting connection", req->sd, MAX_TIME_BLOCKED / mDNSPlatformOneSecond);
1146*4b22b933Srs200217 LogClientInfo(req);
1147*4b22b933Srs200217 abort_request(req);
1148*4b22b933Srs200217 result = t_terminated;
1149*4b22b933Srs200217 }
1150*4b22b933Srs200217 else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond; // try again in a second
1151*4b22b933Srs200217 }
1152*4b22b933Srs200217 if (result == t_terminated || result == t_error)
1153*4b22b933Srs200217 //since we're already doing a list traversal, we unlink the request manually instead of calling unlink_request()
1154*4b22b933Srs200217 {
1155*4b22b933Srs200217 tmp = req;
1156*4b22b933Srs200217 if (prev) prev->next = req->next;
1157*4b22b933Srs200217 if (req == all_requests) all_requests = all_requests->next;
1158*4b22b933Srs200217 req = req->next;
1159*4b22b933Srs200217 freeL("udsserver_idle", tmp);
1160*4b22b933Srs200217 }
1161*4b22b933Srs200217 else
1162*4b22b933Srs200217 {
1163*4b22b933Srs200217 prev = req;
1164*4b22b933Srs200217 req = req->next;
1165*4b22b933Srs200217 }
1166*4b22b933Srs200217 }
1167*4b22b933Srs200217 return nextevent;
1168*4b22b933Srs200217 }
1169*4b22b933Srs200217
udsserver_info(mDNS * const m)1170*4b22b933Srs200217 mDNSexport void udsserver_info(mDNS *const m)
1171*4b22b933Srs200217 {
1172*4b22b933Srs200217 mDNSs32 now = mDNS_TimeNow(m);
1173*4b22b933Srs200217 mDNSu32 CacheUsed = 0, CacheActive = 0;
1174*4b22b933Srs200217 mDNSu32 slot;
1175*4b22b933Srs200217 CacheGroup *cg;
1176*4b22b933Srs200217 CacheRecord *rr;
1177*4b22b933Srs200217 request_state *req;
1178*4b22b933Srs200217
1179*4b22b933Srs200217 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
1180*4b22b933Srs200217
1181*4b22b933Srs200217 LogMsgNoIdent("Slt Q TTL U Type if len rdata");
1182*4b22b933Srs200217 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
1183*4b22b933Srs200217 for(cg = m->rrcache_hash[slot]; cg; cg=cg->next)
1184*4b22b933Srs200217 {
1185*4b22b933Srs200217 CacheUsed++; // Count one cache entity for the CacheGroup object
1186*4b22b933Srs200217 for (rr = cg->members; rr; rr=rr->next)
1187*4b22b933Srs200217 {
1188*4b22b933Srs200217 mDNSs32 remain = rr->resrec.rroriginalttl - (now - rr->TimeRcvd) / mDNSPlatformOneSecond;
1189*4b22b933Srs200217 CacheUsed++;
1190*4b22b933Srs200217 if (rr->CRActiveQuestion) CacheActive++;
1191*4b22b933Srs200217 LogMsgNoIdent("%3d %s%6ld %s %-6s%-6s%s",
1192*4b22b933Srs200217 slot,
1193*4b22b933Srs200217 rr->CRActiveQuestion ? "*" : " ",
1194*4b22b933Srs200217 remain,
1195*4b22b933Srs200217 (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "-" : " ",
1196*4b22b933Srs200217 DNSTypeName(rr->resrec.rrtype),
1197*4b22b933Srs200217 ((NetworkInterfaceInfo *)rr->resrec.InterfaceID)->ifname,
1198*4b22b933Srs200217 CRDisplayString(m, rr));
1199*4b22b933Srs200217 usleep(1000); // Limit rate a little so we don't flood syslog too fast
1200*4b22b933Srs200217 }
1201*4b22b933Srs200217 }
1202*4b22b933Srs200217
1203*4b22b933Srs200217 if (m->rrcache_totalused != CacheUsed)
1204*4b22b933Srs200217 LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
1205*4b22b933Srs200217 if (m->rrcache_active != CacheActive)
1206*4b22b933Srs200217 LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
1207*4b22b933Srs200217 LogMsgNoIdent("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed, CacheActive);
1208*4b22b933Srs200217
1209*4b22b933Srs200217 for (req = all_requests; req; req=req->next)
1210*4b22b933Srs200217 LogClientInfo(req);
1211*4b22b933Srs200217
1212*4b22b933Srs200217 now = mDNS_TimeNow(m);
1213*4b22b933Srs200217 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
1214*4b22b933Srs200217 }
1215*4b22b933Srs200217
1216*4b22b933Srs200217 #if __MACOSX__ && MACOSX_MDNS_MALLOC_DEBUGGING
uds_validatelists(void)1217*4b22b933Srs200217 mDNSexport void uds_validatelists(void)
1218*4b22b933Srs200217 {
1219*4b22b933Srs200217 request_state *req;
1220*4b22b933Srs200217 for (req = all_requests; req; req=req->next)
1221*4b22b933Srs200217 if (req->sd < 0 && req->sd != -2)
1222*4b22b933Srs200217 LogMemCorruption("UDS request list: %p is garbage (%X)", req, req->sd);
1223*4b22b933Srs200217 }
1224*4b22b933Srs200217 #endif
1225*4b22b933Srs200217
rename_service(service_instance * srv)1226*4b22b933Srs200217 mDNSlocal void rename_service(service_instance *srv)
1227*4b22b933Srs200217 {
1228*4b22b933Srs200217 if (srv->autoname && !SameDomainLabel(srv->name.c, gmDNS->nicelabel.c))
1229*4b22b933Srs200217 {
1230*4b22b933Srs200217 srv->rename_on_memfree = 1;
1231*4b22b933Srs200217 if (mDNS_DeregisterService(gmDNS, &srv->srs)) // If service deregistered already, we can re-register immediately
1232*4b22b933Srs200217 regservice_callback(gmDNS, &srv->srs, mStatus_MemFree);
1233*4b22b933Srs200217 }
1234*4b22b933Srs200217 }
1235*4b22b933Srs200217
udsserver_handle_configchange(void)1236*4b22b933Srs200217 mDNSexport void udsserver_handle_configchange(void)
1237*4b22b933Srs200217 {
1238*4b22b933Srs200217 request_state *req;
1239*4b22b933Srs200217
1240*4b22b933Srs200217 for (req = all_requests; req; req = req->next)
1241*4b22b933Srs200217 {
1242*4b22b933Srs200217 if (req->service_registration)
1243*4b22b933Srs200217 {
1244*4b22b933Srs200217 service_instance *ptr;
1245*4b22b933Srs200217 for (ptr = req->service_registration->instances; ptr; ptr = ptr->next)
1246*4b22b933Srs200217 rename_service(ptr);
1247*4b22b933Srs200217 }
1248*4b22b933Srs200217 }
1249*4b22b933Srs200217 }
1250*4b22b933Srs200217
connect_callback(void * info)1251*4b22b933Srs200217 mDNSlocal void connect_callback(void *info)
1252*4b22b933Srs200217 {
1253*4b22b933Srs200217 dnssd_sock_t sd;
1254*4b22b933Srs200217 dnssd_socklen_t len;
1255*4b22b933Srs200217 unsigned long optval;
1256*4b22b933Srs200217 dnssd_sockaddr_t cliaddr;
1257*4b22b933Srs200217 request_state *rstate;
1258*4b22b933Srs200217 (void)info; // Unused
1259*4b22b933Srs200217
1260*4b22b933Srs200217 len = (dnssd_socklen_t) sizeof(cliaddr);
1261*4b22b933Srs200217
1262*4b22b933Srs200217 sd = accept(listenfd, (struct sockaddr*) &cliaddr, &len);
1263*4b22b933Srs200217
1264*4b22b933Srs200217 if (sd == dnssd_InvalidSocket)
1265*4b22b933Srs200217 {
1266*4b22b933Srs200217 if (dnssd_errno() == dnssd_EWOULDBLOCK) return;
1267*4b22b933Srs200217 my_perror("ERROR: accept");
1268*4b22b933Srs200217 return;
1269*4b22b933Srs200217 }
1270*4b22b933Srs200217 optval = 1;
1271*4b22b933Srs200217
1272*4b22b933Srs200217 #ifdef SO_NOSIGPIPE
1273*4b22b933Srs200217 // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
1274*4b22b933Srs200217 if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
1275*4b22b933Srs200217 {
1276*4b22b933Srs200217 my_perror("ERROR: setsockopt - SO_NOSIGPIPE - aborting client");
1277*4b22b933Srs200217 dnssd_close(sd);
1278*4b22b933Srs200217 return;
1279*4b22b933Srs200217 }
1280*4b22b933Srs200217 #endif
1281*4b22b933Srs200217
1282*4b22b933Srs200217 #if defined(_WIN32)
1283*4b22b933Srs200217 if (ioctlsocket(sd, FIONBIO, &optval) != 0)
1284*4b22b933Srs200217 #else
1285*4b22b933Srs200217 if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
1286*4b22b933Srs200217 #endif
1287*4b22b933Srs200217 {
1288*4b22b933Srs200217 my_perror("ERROR: fcntl(sd, F_SETFL, O_NONBLOCK) - aborting client");
1289*4b22b933Srs200217 dnssd_close(sd);
1290*4b22b933Srs200217 return;
1291*4b22b933Srs200217 }
1292*4b22b933Srs200217
1293*4b22b933Srs200217 // allocate a request_state struct that will live with the socket
1294*4b22b933Srs200217 rstate = mallocL("connect_callback", sizeof(request_state));
1295*4b22b933Srs200217 if (!rstate) FatalError("ERROR: malloc");
1296*4b22b933Srs200217 bzero(rstate, sizeof(request_state));
1297*4b22b933Srs200217 rstate->ts = t_morecoming;
1298*4b22b933Srs200217 rstate->sd = sd;
1299*4b22b933Srs200217
1300*4b22b933Srs200217 LogOperation("%3d: Adding FD", rstate->sd);
1301*4b22b933Srs200217 if ( mStatus_NoError != udsSupportAddFDToEventLoop( sd, request_callback, rstate))
1302*4b22b933Srs200217 return;
1303*4b22b933Srs200217 rstate->next = all_requests;
1304*4b22b933Srs200217 all_requests = rstate;
1305*4b22b933Srs200217 }
1306*4b22b933Srs200217
1307*4b22b933Srs200217 // handler
request_callback(void * info)1308*4b22b933Srs200217 mDNSlocal void request_callback(void *info)
1309*4b22b933Srs200217 {
1310*4b22b933Srs200217 request_state *rstate = info;
1311*4b22b933Srs200217 transfer_state result;
1312*4b22b933Srs200217 dnssd_sockaddr_t cliaddr;
1313*4b22b933Srs200217 int dedicated_error_socket;
1314*4b22b933Srs200217 #if defined(_WIN32)
1315*4b22b933Srs200217 u_long opt = 1;
1316*4b22b933Srs200217 #endif
1317*4b22b933Srs200217
1318*4b22b933Srs200217 result = read_msg(rstate);
1319*4b22b933Srs200217 if (result == t_morecoming)
1320*4b22b933Srs200217 {
1321*4b22b933Srs200217 return;
1322*4b22b933Srs200217 }
1323*4b22b933Srs200217 if (result == t_terminated)
1324*4b22b933Srs200217 {
1325*4b22b933Srs200217 abort_request(rstate);
1326*4b22b933Srs200217 unlink_request(rstate);
1327*4b22b933Srs200217 return;
1328*4b22b933Srs200217 }
1329*4b22b933Srs200217 if (result == t_error)
1330*4b22b933Srs200217 {
1331*4b22b933Srs200217 abort_request(rstate);
1332*4b22b933Srs200217 unlink_request(rstate);
1333*4b22b933Srs200217 return;
1334*4b22b933Srs200217 }
1335*4b22b933Srs200217
1336*4b22b933Srs200217 if (rstate->hdr.version != VERSION)
1337*4b22b933Srs200217 {
1338*4b22b933Srs200217 LogMsg("ERROR: client incompatible with daemon (client version = %d, "
1339*4b22b933Srs200217 "daemon version = %d)\n", rstate->hdr.version, VERSION);
1340*4b22b933Srs200217 abort_request(rstate);
1341*4b22b933Srs200217 unlink_request(rstate);
1342*4b22b933Srs200217 return;
1343*4b22b933Srs200217 }
1344*4b22b933Srs200217
1345*4b22b933Srs200217 if (validate_message(rstate) < 0)
1346*4b22b933Srs200217 {
1347*4b22b933Srs200217 // note that we cannot deliver an error message if validation fails, since the path to the error socket
1348*4b22b933Srs200217 // may be contained in the (invalid) message body for some message types
1349*4b22b933Srs200217 abort_request(rstate);
1350*4b22b933Srs200217 unlink_request(rstate);
1351*4b22b933Srs200217 LogMsg("Invalid message sent by client - may indicate a malicious program running on this machine!");
1352*4b22b933Srs200217 return;
1353*4b22b933Srs200217 }
1354*4b22b933Srs200217
1355*4b22b933Srs200217 // check if client wants silent operation
1356*4b22b933Srs200217 if (rstate->hdr.flags & IPC_FLAGS_NOREPLY) rstate->no_reply = 1;
1357*4b22b933Srs200217
1358*4b22b933Srs200217 dedicated_error_socket = (rstate->hdr.op == reg_record_request || rstate->hdr.op == add_record_request ||
1359*4b22b933Srs200217 rstate->hdr.op == update_record_request || rstate->hdr.op == remove_record_request);
1360*4b22b933Srs200217
1361*4b22b933Srs200217 if (((rstate->hdr.flags & IPC_FLAGS_REUSE_SOCKET) == 0) != dedicated_error_socket)
1362*4b22b933Srs200217 LogMsg("WARNING: client request %d with incorrect flags setting 0x%X", rstate->hdr.op, rstate->hdr.flags);
1363*4b22b933Srs200217
1364*4b22b933Srs200217 // check if primary socket is to be used for synchronous errors, else open new socket
1365*4b22b933Srs200217 if (dedicated_error_socket)
1366*4b22b933Srs200217 {
1367*4b22b933Srs200217 mStatus err = 0;
1368*4b22b933Srs200217 int nwritten;
1369*4b22b933Srs200217 dnssd_sock_t errfd = socket(AF_DNSSD, SOCK_STREAM, 0);
1370*4b22b933Srs200217 if (errfd == dnssd_InvalidSocket)
1371*4b22b933Srs200217 {
1372*4b22b933Srs200217 my_perror("ERROR: socket");
1373*4b22b933Srs200217 abort_request(rstate);
1374*4b22b933Srs200217 unlink_request(rstate);
1375*4b22b933Srs200217 return;
1376*4b22b933Srs200217 }
1377*4b22b933Srs200217
1378*4b22b933Srs200217 //LogOperation("request_callback: Opened dedicated errfd %d", errfd);
1379*4b22b933Srs200217
1380*4b22b933Srs200217 #if defined(USE_TCP_LOOPBACK)
1381*4b22b933Srs200217 {
1382*4b22b933Srs200217 mDNSOpaque16 port;
1383*4b22b933Srs200217 port.b[0] = rstate->msgdata[0];
1384*4b22b933Srs200217 port.b[1] = rstate->msgdata[1];
1385*4b22b933Srs200217 rstate->msgdata += 2;
1386*4b22b933Srs200217 cliaddr.sin_family = AF_INET;
1387*4b22b933Srs200217 cliaddr.sin_port = port.NotAnInteger;
1388*4b22b933Srs200217 cliaddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
1389*4b22b933Srs200217 }
1390*4b22b933Srs200217 #else
1391*4b22b933Srs200217 {
1392*4b22b933Srs200217 char ctrl_path[MAX_CTLPATH];
1393*4b22b933Srs200217 get_string(&rstate->msgdata, ctrl_path, 256); // path is first element in message buffer
1394*4b22b933Srs200217 bzero(&cliaddr, sizeof(cliaddr));
1395*4b22b933Srs200217 cliaddr.sun_family = AF_LOCAL;
1396*4b22b933Srs200217 strcpy(cliaddr.sun_path, ctrl_path);
1397*4b22b933Srs200217 }
1398*4b22b933Srs200217 #endif
1399*4b22b933Srs200217 //LogOperation("request_callback: Connecting to “%s”", cliaddr.sun_path);
1400*4b22b933Srs200217 if (connect(errfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
1401*4b22b933Srs200217 {
1402*4b22b933Srs200217 //LogOperation("request_callback: Couldn't connect to “%s”", cliaddr.sun_path);
1403*4b22b933Srs200217 my_perror("ERROR: connect");
1404*4b22b933Srs200217 abort_request(rstate);
1405*4b22b933Srs200217 unlink_request(rstate);
1406*4b22b933Srs200217 return;
1407*4b22b933Srs200217 }
1408*4b22b933Srs200217 #if defined(_WIN32)
1409*4b22b933Srs200217 if (ioctlsocket(errfd, FIONBIO, &opt) != 0)
1410*4b22b933Srs200217 #else
1411*4b22b933Srs200217 if (fcntl(errfd, F_SETFL, O_NONBLOCK) != 0)
1412*4b22b933Srs200217 #endif
1413*4b22b933Srs200217 {
1414*4b22b933Srs200217 my_perror("ERROR: could not set control socket to non-blocking mode");
1415*4b22b933Srs200217 abort_request(rstate);
1416*4b22b933Srs200217 unlink_request(rstate);
1417*4b22b933Srs200217 return;
1418*4b22b933Srs200217 }
1419*4b22b933Srs200217
1420*4b22b933Srs200217 switch(rstate->hdr.op)
1421*4b22b933Srs200217 {
1422*4b22b933Srs200217 case reg_record_request: err = handle_regrecord_request (rstate); break;
1423*4b22b933Srs200217 case add_record_request: err = handle_add_request (rstate); break;
1424*4b22b933Srs200217 case update_record_request: err = handle_update_request (rstate); break;
1425*4b22b933Srs200217 case remove_record_request: err = handle_removerecord_request(rstate); break;
1426*4b22b933Srs200217 default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
1427*4b22b933Srs200217 }
1428*4b22b933Srs200217
1429*4b22b933Srs200217 //LogOperation("request_callback: Returning error code %d on socket %d", err, errfd);
1430*4b22b933Srs200217 err = dnssd_htonl(err);
1431*4b22b933Srs200217 nwritten = send(errfd, (dnssd_sockbuf_t) &err, sizeof(err), 0);
1432*4b22b933Srs200217 // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a four-byte write for us.
1433*4b22b933Srs200217 // If not, we don't attempt to handle this failure, but we do log it.
1434*4b22b933Srs200217 if (nwritten < (int)sizeof(err))
1435*4b22b933Srs200217 LogMsg("ERROR: failed to write error response back to caller: %d %d %s",
1436*4b22b933Srs200217 nwritten, dnssd_errno(), dnssd_strerror(dnssd_errno()));
1437*4b22b933Srs200217 //else LogOperation("request_callback: Returned error code %d on socket %d", err, errfd);
1438*4b22b933Srs200217 dnssd_close(errfd);
1439*4b22b933Srs200217 //LogOperation("request_callback: Closed errfd %d", errfd);
1440*4b22b933Srs200217 reset_connected_rstate(rstate); // Reset ready to accept the next request on this pipe
1441*4b22b933Srs200217 }
1442*4b22b933Srs200217 else
1443*4b22b933Srs200217 {
1444*4b22b933Srs200217 switch(rstate->hdr.op)
1445*4b22b933Srs200217 {
1446*4b22b933Srs200217 case resolve_request: handle_resolve_request (rstate); break;
1447*4b22b933Srs200217 case query_request: handle_query_request (rstate); break;
1448*4b22b933Srs200217 case browse_request: handle_browse_request (rstate); break;
1449*4b22b933Srs200217 case reg_service_request: handle_regservice_request(rstate); break;
1450*4b22b933Srs200217 case enumeration_request: handle_enum_request (rstate); break;
1451*4b22b933Srs200217 case reconfirm_record_request: handle_reconfirm_request (rstate); break;
1452*4b22b933Srs200217 case setdomain_request: handle_setdomain_request (rstate); break;
1453*4b22b933Srs200217 default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
1454*4b22b933Srs200217 }
1455*4b22b933Srs200217 }
1456*4b22b933Srs200217 }
1457*4b22b933Srs200217
1458*4b22b933Srs200217 // mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
1459*4b22b933Srs200217 // the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
1460*4b22b933Srs200217 // to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
1461*4b22b933Srs200217 // the mDNSCore operation if the client dies or closes its socket.
1462*4b22b933Srs200217
1463*4b22b933Srs200217 // query and resolve calls have separate request handlers that parse the arguments from the client and
1464*4b22b933Srs200217 // massage the name parameters appropriately, but the rest of the operations (making the query call,
1465*4b22b933Srs200217 // delivering the result to the client, and termination) are identical.
1466*4b22b933Srs200217
handle_query_request(request_state * rstate)1467*4b22b933Srs200217 mDNSlocal void handle_query_request(request_state *rstate)
1468*4b22b933Srs200217 {
1469*4b22b933Srs200217 DNSServiceFlags flags;
1470*4b22b933Srs200217 uint32_t ifi;
1471*4b22b933Srs200217 char name[256];
1472*4b22b933Srs200217 uint16_t rrtype, rrclass;
1473*4b22b933Srs200217 char *ptr;
1474*4b22b933Srs200217 mStatus result;
1475*4b22b933Srs200217 mDNSInterfaceID InterfaceID;
1476*4b22b933Srs200217 DNSQuestion *q;
1477*4b22b933Srs200217
1478*4b22b933Srs200217 if (rstate->ts != t_complete)
1479*4b22b933Srs200217 {
1480*4b22b933Srs200217 LogMsg("ERROR: handle_query_request - transfer state != t_complete");
1481*4b22b933Srs200217 goto error;
1482*4b22b933Srs200217 }
1483*4b22b933Srs200217 ptr = rstate->msgdata;
1484*4b22b933Srs200217 if (!ptr)
1485*4b22b933Srs200217 {
1486*4b22b933Srs200217 LogMsg("ERROR: handle_query_request - NULL msgdata");
1487*4b22b933Srs200217 goto error;
1488*4b22b933Srs200217 }
1489*4b22b933Srs200217
1490*4b22b933Srs200217 flags = get_flags(&ptr);
1491*4b22b933Srs200217 ifi = get_long(&ptr);
1492*4b22b933Srs200217 if (get_string(&ptr, name, 256) < 0) goto bad_param;
1493*4b22b933Srs200217 rrtype = get_short(&ptr);
1494*4b22b933Srs200217 rrclass = get_short(&ptr);
1495*4b22b933Srs200217 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
1496*4b22b933Srs200217 if (ifi && !InterfaceID) goto bad_param;
1497*4b22b933Srs200217
1498*4b22b933Srs200217 q = mallocL("DNSQuestion", sizeof(DNSQuestion));
1499*4b22b933Srs200217 if (!q) FatalError("ERROR: handle_query - malloc");
1500*4b22b933Srs200217 bzero(q, sizeof(DNSQuestion));
1501*4b22b933Srs200217
1502*4b22b933Srs200217 q->InterfaceID = InterfaceID;
1503*4b22b933Srs200217 q->Target = zeroAddr;
1504*4b22b933Srs200217 if (!MakeDomainNameFromDNSNameString(&q->qname, name)) { freeL("DNSQuestion", q); goto bad_param; }
1505*4b22b933Srs200217 q->qtype = rrtype;
1506*4b22b933Srs200217 q->qclass = rrclass;
1507*4b22b933Srs200217 q->LongLived = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
1508*4b22b933Srs200217 q->ExpectUnique = mDNSfalse;
1509*4b22b933Srs200217 q->ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
1510*4b22b933Srs200217 q->ReturnCNAME = (flags & kDNSServiceFlagsReturnCNAME) != 0;
1511*4b22b933Srs200217 q->QuestionCallback = question_result_callback;
1512*4b22b933Srs200217 q->QuestionContext = rstate;
1513*4b22b933Srs200217
1514*4b22b933Srs200217 rstate->termination_context = q;
1515*4b22b933Srs200217 rstate->terminate = question_termination_callback;
1516*4b22b933Srs200217
1517*4b22b933Srs200217 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) START", rstate->sd, q->qname.c, DNSTypeName(q->qtype));
1518*4b22b933Srs200217 result = mDNS_StartQuery(gmDNS, q);
1519*4b22b933Srs200217 if (result != mStatus_NoError) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result);
1520*4b22b933Srs200217
1521*4b22b933Srs200217 if (result) rstate->terminate = NULL;
1522*4b22b933Srs200217 if (deliver_error(rstate, result) < 0) goto error;
1523*4b22b933Srs200217 return;
1524*4b22b933Srs200217
1525*4b22b933Srs200217 bad_param:
1526*4b22b933Srs200217 deliver_error(rstate, mStatus_BadParamErr);
1527*4b22b933Srs200217 rstate->terminate = NULL; // don't try to terminate insuccessful Core calls
1528*4b22b933Srs200217 error:
1529*4b22b933Srs200217 abort_request(rstate);
1530*4b22b933Srs200217 unlink_request(rstate);
1531*4b22b933Srs200217 return;
1532*4b22b933Srs200217 }
1533*4b22b933Srs200217
handle_resolve_request(request_state * rstate)1534*4b22b933Srs200217 mDNSlocal void handle_resolve_request(request_state *rstate)
1535*4b22b933Srs200217 {
1536*4b22b933Srs200217 DNSServiceFlags flags;
1537*4b22b933Srs200217 uint32_t interfaceIndex;
1538*4b22b933Srs200217 mDNSInterfaceID InterfaceID;
1539*4b22b933Srs200217 char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
1540*4b22b933Srs200217 char *ptr; // message data pointer
1541*4b22b933Srs200217 domainname fqdn;
1542*4b22b933Srs200217 resolve_termination_t *term;
1543*4b22b933Srs200217 mStatus err;
1544*4b22b933Srs200217
1545*4b22b933Srs200217 if (rstate->ts != t_complete)
1546*4b22b933Srs200217 {
1547*4b22b933Srs200217 LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
1548*4b22b933Srs200217 abort_request(rstate);
1549*4b22b933Srs200217 unlink_request(rstate);
1550*4b22b933Srs200217 return;
1551*4b22b933Srs200217 }
1552*4b22b933Srs200217
1553*4b22b933Srs200217 // extract the data from the message
1554*4b22b933Srs200217 ptr = rstate->msgdata;
1555*4b22b933Srs200217 if (!ptr)
1556*4b22b933Srs200217 {
1557*4b22b933Srs200217 LogMsg("ERROR: handle_resolve_request - NULL msgdata");
1558*4b22b933Srs200217 abort_request(rstate);
1559*4b22b933Srs200217 unlink_request(rstate);
1560*4b22b933Srs200217 return;
1561*4b22b933Srs200217 }
1562*4b22b933Srs200217 flags = get_flags(&ptr);
1563*4b22b933Srs200217 interfaceIndex = get_long(&ptr);
1564*4b22b933Srs200217 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
1565*4b22b933Srs200217 if (interfaceIndex && !InterfaceID)
1566*4b22b933Srs200217 { LogMsg("ERROR: handle_resolve_request - Couldn't find InterfaceID for interfaceIndex %d", interfaceIndex); goto bad_param; }
1567*4b22b933Srs200217 if (get_string(&ptr, name, 256) < 0 ||
1568*4b22b933Srs200217 get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1569*4b22b933Srs200217 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
1570*4b22b933Srs200217 { LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); goto bad_param; }
1571*4b22b933Srs200217
1572*4b22b933Srs200217 // free memory in rstate since we don't need it anymore
1573*4b22b933Srs200217 freeL("handle_resolve_request", rstate->msgbuf);
1574*4b22b933Srs200217 rstate->msgbuf = NULL;
1575*4b22b933Srs200217
1576*4b22b933Srs200217 if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
1577*4b22b933Srs200217 { LogMsg("ERROR: handle_resolve_request - Couldn't build_domainname_from_strings “%s” “%s” “%s”", name, regtype, domain); goto bad_param; }
1578*4b22b933Srs200217
1579*4b22b933Srs200217 // set up termination info
1580*4b22b933Srs200217 term = mallocL("handle_resolve_request", sizeof(resolve_termination_t));
1581*4b22b933Srs200217 bzero(term, sizeof(*term));
1582*4b22b933Srs200217 if (!term) FatalError("ERROR: malloc");
1583*4b22b933Srs200217
1584*4b22b933Srs200217 // format questions
1585*4b22b933Srs200217 term->qsrv.InterfaceID = InterfaceID;
1586*4b22b933Srs200217 term->qsrv.Target = zeroAddr;
1587*4b22b933Srs200217 memcpy(&term->qsrv.qname, &fqdn, MAX_DOMAIN_NAME);
1588*4b22b933Srs200217 term->qsrv.qtype = kDNSType_SRV;
1589*4b22b933Srs200217 term->qsrv.qclass = kDNSClass_IN;
1590*4b22b933Srs200217 term->qsrv.LongLived = mDNSfalse;
1591*4b22b933Srs200217 term->qsrv.ExpectUnique = mDNStrue;
1592*4b22b933Srs200217 term->qsrv.ForceMCast = mDNSfalse;
1593*4b22b933Srs200217 term->qsrv.QuestionCallback = resolve_result_callback;
1594*4b22b933Srs200217 term->qsrv.QuestionContext = rstate;
1595*4b22b933Srs200217
1596*4b22b933Srs200217 term->qtxt.InterfaceID = InterfaceID;
1597*4b22b933Srs200217 term->qtxt.Target = zeroAddr;
1598*4b22b933Srs200217 memcpy(&term->qtxt.qname, &fqdn, MAX_DOMAIN_NAME);
1599*4b22b933Srs200217 term->qtxt.qtype = kDNSType_TXT;
1600*4b22b933Srs200217 term->qtxt.qclass = kDNSClass_IN;
1601*4b22b933Srs200217 term->qtxt.LongLived = mDNSfalse;
1602*4b22b933Srs200217 term->qtxt.ExpectUnique = mDNStrue;
1603*4b22b933Srs200217 term->qtxt.ForceMCast = mDNSfalse;
1604*4b22b933Srs200217 term->qtxt.QuestionCallback = resolve_result_callback;
1605*4b22b933Srs200217 term->qtxt.QuestionContext = rstate;
1606*4b22b933Srs200217
1607*4b22b933Srs200217 term->rstate = rstate;
1608*4b22b933Srs200217 rstate->termination_context = term;
1609*4b22b933Srs200217 rstate->terminate = resolve_termination_callback;
1610*4b22b933Srs200217
1611*4b22b933Srs200217 // ask the questions
1612*4b22b933Srs200217 LogOperation("%3d: DNSServiceResolve(%##s) START", rstate->sd, term->qsrv.qname.c);
1613*4b22b933Srs200217 err = mDNS_StartQuery(gmDNS, &term->qsrv);
1614*4b22b933Srs200217 if (!err) err = mDNS_StartQuery(gmDNS, &term->qtxt);
1615*4b22b933Srs200217
1616*4b22b933Srs200217 if (err)
1617*4b22b933Srs200217 {
1618*4b22b933Srs200217 freeL("handle_resolve_request", term);
1619*4b22b933Srs200217 rstate->terminate = NULL; // prevent abort_request() from invoking termination callback
1620*4b22b933Srs200217 }
1621*4b22b933Srs200217 if (deliver_error(rstate, err) < 0 || err)
1622*4b22b933Srs200217 {
1623*4b22b933Srs200217 abort_request(rstate);
1624*4b22b933Srs200217 unlink_request(rstate);
1625*4b22b933Srs200217 }
1626*4b22b933Srs200217 return;
1627*4b22b933Srs200217
1628*4b22b933Srs200217 bad_param:
1629*4b22b933Srs200217 deliver_error(rstate, mStatus_BadParamErr);
1630*4b22b933Srs200217 abort_request(rstate);
1631*4b22b933Srs200217 unlink_request(rstate);
1632*4b22b933Srs200217 }
1633*4b22b933Srs200217
resolve_termination_callback(void * context)1634*4b22b933Srs200217 mDNSlocal void resolve_termination_callback(void *context)
1635*4b22b933Srs200217 {
1636*4b22b933Srs200217 resolve_termination_t *term = context;
1637*4b22b933Srs200217 request_state *rs;
1638*4b22b933Srs200217
1639*4b22b933Srs200217 if (!term)
1640*4b22b933Srs200217 {
1641*4b22b933Srs200217 LogMsg("ERROR: resolve_termination_callback: double termination");
1642*4b22b933Srs200217 return;
1643*4b22b933Srs200217 }
1644*4b22b933Srs200217 rs = term->rstate;
1645*4b22b933Srs200217 LogOperation("%3d: DNSServiceResolve(%##s) STOP", rs->sd, term->qtxt.qname.c);
1646*4b22b933Srs200217
1647*4b22b933Srs200217 mDNS_StopQuery(gmDNS, &term->qtxt);
1648*4b22b933Srs200217 mDNS_StopQuery(gmDNS, &term->qsrv);
1649*4b22b933Srs200217
1650*4b22b933Srs200217 freeL("resolve_termination_callback", term);
1651*4b22b933Srs200217 rs->termination_context = NULL;
1652*4b22b933Srs200217 }
1653*4b22b933Srs200217
resolve_result_callback(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,mDNSBool AddRecord)1654*4b22b933Srs200217 mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1655*4b22b933Srs200217 {
1656*4b22b933Srs200217 size_t len = 0;
1657*4b22b933Srs200217 char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
1658*4b22b933Srs200217 char *data;
1659*4b22b933Srs200217 transfer_state result;
1660*4b22b933Srs200217 reply_state *rep;
1661*4b22b933Srs200217 request_state *rs = question->QuestionContext;
1662*4b22b933Srs200217 resolve_termination_t *res = rs->termination_context;
1663*4b22b933Srs200217 (void)m; // Unused
1664*4b22b933Srs200217
1665*4b22b933Srs200217 LogOperation("%3d: DNSServiceResolve(%##s, %s) %s %s",
1666*4b22b933Srs200217 rs->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
1667*4b22b933Srs200217
1668*4b22b933Srs200217 // This code used to do this trick of just keeping a copy of the pointer to
1669*4b22b933Srs200217 // the answer record in the cache, but the unicast query code doesn't currently
1670*4b22b933Srs200217 // put its answer records in the cache, so for now we can't do this.
1671*4b22b933Srs200217
1672*4b22b933Srs200217 if (!AddRecord)
1673*4b22b933Srs200217 {
1674*4b22b933Srs200217 // After unicast query code is updated to store its records in the common cache, use this...
1675*4b22b933Srs200217 // if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
1676*4b22b933Srs200217 // if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
1677*4b22b933Srs200217 // intead of this...
1678*4b22b933Srs200217 if (answer->rrtype == kDNSType_SRV && res->srv && SameRDataBody(answer, (RDataBody *)&res->srvdata))
1679*4b22b933Srs200217 res->srv = mDNSfalse;
1680*4b22b933Srs200217 if (answer->rrtype == kDNSType_TXT && res->txt && answer->rdlength == res->txtlen && SameRDataBody(answer, (RDataBody *)&res->txtdata))
1681*4b22b933Srs200217 res->txt = mDNSfalse;
1682*4b22b933Srs200217 return;
1683*4b22b933Srs200217 }
1684*4b22b933Srs200217
1685*4b22b933Srs200217 // After unicast query code is updated to store its records in the common cache, use this...
1686*4b22b933Srs200217 // if (answer->rrtype == kDNSType_SRV) res->srv = answer;
1687*4b22b933Srs200217 // if (answer->rrtype == kDNSType_TXT) res->txt = answer;
1688*4b22b933Srs200217 // intead of this...
1689*4b22b933Srs200217 if (answer->rrtype == kDNSType_SRV)
1690*4b22b933Srs200217 {
1691*4b22b933Srs200217 res->srvdata = answer->rdata->u.srv;
1692*4b22b933Srs200217 res->srv = mDNStrue;
1693*4b22b933Srs200217 }
1694*4b22b933Srs200217 if (answer->rrtype == kDNSType_TXT)
1695*4b22b933Srs200217 {
1696*4b22b933Srs200217 if (answer->rdlength > AbsoluteMaxDNSMessageData) return;
1697*4b22b933Srs200217 res->txtlen = answer->rdlength;
1698*4b22b933Srs200217 mDNSPlatformMemCopy(answer->rdata->u.data, res->txtdata, res->txtlen);
1699*4b22b933Srs200217 res->txt = mDNStrue;
1700*4b22b933Srs200217 }
1701*4b22b933Srs200217
1702*4b22b933Srs200217 if (!res->txt || !res->srv) return; // only deliver result to client if we have both answers
1703*4b22b933Srs200217
1704*4b22b933Srs200217 ConvertDomainNameToCString(answer->name, fullname);
1705*4b22b933Srs200217 ConvertDomainNameToCString(&res->srvdata.target, target);
1706*4b22b933Srs200217
1707*4b22b933Srs200217 // calculate reply length
1708*4b22b933Srs200217 len += sizeof(DNSServiceFlags);
1709*4b22b933Srs200217 len += sizeof(uint32_t); // interface index
1710*4b22b933Srs200217 len += sizeof(DNSServiceErrorType);
1711*4b22b933Srs200217 len += strlen(fullname) + 1;
1712*4b22b933Srs200217 len += strlen(target) + 1;
1713*4b22b933Srs200217 len += 2 * sizeof(uint16_t); // port, txtLen
1714*4b22b933Srs200217 len += res->txtlen;
1715*4b22b933Srs200217
1716*4b22b933Srs200217 // allocate/init reply header
1717*4b22b933Srs200217 rep = create_reply(resolve_reply_op, len, rs);
1718*4b22b933Srs200217 rep->rhdr->flags = dnssd_htonl(0);
1719*4b22b933Srs200217 rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
1720*4b22b933Srs200217 rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
1721*4b22b933Srs200217
1722*4b22b933Srs200217 data = rep->sdata;
1723*4b22b933Srs200217
1724*4b22b933Srs200217 // write reply data to message
1725*4b22b933Srs200217 put_string(fullname, &data);
1726*4b22b933Srs200217 put_string(target, &data);
1727*4b22b933Srs200217 *data++ = res->srvdata.port.b[0];
1728*4b22b933Srs200217 *data++ = res->srvdata.port.b[1];
1729*4b22b933Srs200217 put_short(res->txtlen, &data);
1730*4b22b933Srs200217 put_rdata(res->txtlen, res->txtdata, &data);
1731*4b22b933Srs200217
1732*4b22b933Srs200217 result = send_msg(rep);
1733*4b22b933Srs200217 if (result == t_error || result == t_terminated)
1734*4b22b933Srs200217 {
1735*4b22b933Srs200217 abort_request(rs);
1736*4b22b933Srs200217 unlink_request(rs);
1737*4b22b933Srs200217 freeL("resolve_result_callback", rep);
1738*4b22b933Srs200217 }
1739*4b22b933Srs200217 else if (result == t_complete) freeL("resolve_result_callback", rep);
1740*4b22b933Srs200217 else append_reply(rs, rep);
1741*4b22b933Srs200217 }
1742*4b22b933Srs200217
1743*4b22b933Srs200217 // what gets called when a resolve is completed and we need to send the data back to the client
question_result_callback(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,mDNSBool AddRecord)1744*4b22b933Srs200217 mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1745*4b22b933Srs200217 {
1746*4b22b933Srs200217 char *data;
1747*4b22b933Srs200217 char name[MAX_ESCAPED_DOMAIN_NAME];
1748*4b22b933Srs200217 request_state *req = question->QuestionContext;
1749*4b22b933Srs200217 reply_state *rep;
1750*4b22b933Srs200217 size_t len;
1751*4b22b933Srs200217 (void)m; // Unused
1752*4b22b933Srs200217
1753*4b22b933Srs200217 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) RESULT %s", req->sd, question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer));
1754*4b22b933Srs200217 //mDNS_StopQuery(m, question);
1755*4b22b933Srs200217
1756*4b22b933Srs200217 if (answer->rdlength == 0)
1757*4b22b933Srs200217 {
1758*4b22b933Srs200217 deliver_async_error(req, query_reply_op, kDNSServiceErr_NoSuchRecord);
1759*4b22b933Srs200217 return;
1760*4b22b933Srs200217 }
1761*4b22b933Srs200217
1762*4b22b933Srs200217 // calculate reply data length
1763*4b22b933Srs200217 len = sizeof(DNSServiceFlags);
1764*4b22b933Srs200217 len += 2 * sizeof(uint32_t); // if index + ttl
1765*4b22b933Srs200217 len += sizeof(DNSServiceErrorType);
1766*4b22b933Srs200217 len += 3 * sizeof(uint16_t); // type, class, rdlen
1767*4b22b933Srs200217 len += answer->rdlength;
1768*4b22b933Srs200217 ConvertDomainNameToCString(answer->name, name);
1769*4b22b933Srs200217 len += strlen(name) + 1;
1770*4b22b933Srs200217
1771*4b22b933Srs200217 rep = create_reply(query_reply_op, len, req);
1772*4b22b933Srs200217
1773*4b22b933Srs200217 rep->rhdr->flags = dnssd_htonl(AddRecord ? kDNSServiceFlagsAdd : 0);
1774*4b22b933Srs200217 rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
1775*4b22b933Srs200217 rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
1776*4b22b933Srs200217
1777*4b22b933Srs200217 data = rep->sdata;
1778*4b22b933Srs200217
1779*4b22b933Srs200217 put_string(name, &data);
1780*4b22b933Srs200217 put_short(answer->rrtype, &data);
1781*4b22b933Srs200217 put_short(answer->rrclass, &data);
1782*4b22b933Srs200217 put_short(answer->rdlength, &data);
1783*4b22b933Srs200217 put_rdata(answer->rdlength, answer->rdata->u.data, &data);
1784*4b22b933Srs200217 put_long(AddRecord ? answer->rroriginalttl : 0, &data);
1785*4b22b933Srs200217
1786*4b22b933Srs200217 append_reply(req, rep);
1787*4b22b933Srs200217 return;
1788*4b22b933Srs200217 }
1789*4b22b933Srs200217
question_termination_callback(void * context)1790*4b22b933Srs200217 mDNSlocal void question_termination_callback(void *context)
1791*4b22b933Srs200217 {
1792*4b22b933Srs200217 DNSQuestion *q = context;
1793*4b22b933Srs200217 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP", ((request_state *)q->QuestionContext)->sd, q->qname.c, DNSTypeName(q->qtype));
1794*4b22b933Srs200217 mDNS_StopQuery(gmDNS, q); // no need to error check
1795*4b22b933Srs200217 freeL("question_termination_callback", q);
1796*4b22b933Srs200217 }
1797*4b22b933Srs200217
1798*4b22b933Srs200217 // If there's a comma followed by another character,
1799*4b22b933Srs200217 // FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
1800*4b22b933Srs200217 // Otherwise, it returns a pointer to the final nul at the end of the string
FindFirstSubType(char * p)1801*4b22b933Srs200217 mDNSlocal char *FindFirstSubType(char *p)
1802*4b22b933Srs200217 {
1803*4b22b933Srs200217 while (*p)
1804*4b22b933Srs200217 {
1805*4b22b933Srs200217 if (p[0] == '\\' && p[1]) p += 2;
1806*4b22b933Srs200217 else if (p[0] == ',' && p[1]) { *p++ = 0; return(p); }
1807*4b22b933Srs200217 else p++;
1808*4b22b933Srs200217 }
1809*4b22b933Srs200217 return(p);
1810*4b22b933Srs200217 }
1811*4b22b933Srs200217
1812*4b22b933Srs200217 // If there's a comma followed by another character,
1813*4b22b933Srs200217 // FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
1814*4b22b933Srs200217 // If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
1815*4b22b933Srs200217 // Otherwise, it returns a pointer to the final nul at the end of the string
FindNextSubType(char * p)1816*4b22b933Srs200217 mDNSlocal char *FindNextSubType(char *p)
1817*4b22b933Srs200217 {
1818*4b22b933Srs200217 while (*p)
1819*4b22b933Srs200217 {
1820*4b22b933Srs200217 if (p[0] == '\\' && p[1]) // If escape character
1821*4b22b933Srs200217 p += 2; // ignore following character
1822*4b22b933Srs200217 else if (p[0] == ',') // If we found a comma
1823*4b22b933Srs200217 {
1824*4b22b933Srs200217 if (p[1]) *p++ = 0;
1825*4b22b933Srs200217 return(p);
1826*4b22b933Srs200217 }
1827*4b22b933Srs200217 else if (p[0] == '.')
1828*4b22b933Srs200217 return(mDNSNULL);
1829*4b22b933Srs200217 else p++;
1830*4b22b933Srs200217 }
1831*4b22b933Srs200217 return(p);
1832*4b22b933Srs200217 }
1833*4b22b933Srs200217
1834*4b22b933Srs200217 // Returns -1 if illegal subtype found
ChopSubTypes(char * regtype)1835*4b22b933Srs200217 mDNSexport mDNSs32 ChopSubTypes(char *regtype)
1836*4b22b933Srs200217 {
1837*4b22b933Srs200217 mDNSs32 NumSubTypes = 0;
1838*4b22b933Srs200217 char *stp = FindFirstSubType(regtype);
1839*4b22b933Srs200217 while (stp && *stp) // If we found a comma...
1840*4b22b933Srs200217 {
1841*4b22b933Srs200217 if (*stp == ',') return(-1);
1842*4b22b933Srs200217 NumSubTypes++;
1843*4b22b933Srs200217 stp = FindNextSubType(stp);
1844*4b22b933Srs200217 }
1845*4b22b933Srs200217 if (!stp) return(-1);
1846*4b22b933Srs200217 return(NumSubTypes);
1847*4b22b933Srs200217 }
1848*4b22b933Srs200217
AllocateSubTypes(mDNSs32 NumSubTypes,char * p)1849*4b22b933Srs200217 mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
1850*4b22b933Srs200217 {
1851*4b22b933Srs200217 AuthRecord *st = mDNSNULL;
1852*4b22b933Srs200217 if (NumSubTypes)
1853*4b22b933Srs200217 {
1854*4b22b933Srs200217 mDNSs32 i;
1855*4b22b933Srs200217 st = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
1856*4b22b933Srs200217 if (!st) return(mDNSNULL);
1857*4b22b933Srs200217 for (i = 0; i < NumSubTypes; i++)
1858*4b22b933Srs200217 {
1859*4b22b933Srs200217 mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
1860*4b22b933Srs200217 while (*p) p++;
1861*4b22b933Srs200217 p++;
1862*4b22b933Srs200217 if (!MakeDomainNameFromDNSNameString(st[i].resrec.name, p))
1863*4b22b933Srs200217 { freeL("ServiceSubTypes", st); return(mDNSNULL); }
1864*4b22b933Srs200217 }
1865*4b22b933Srs200217 }
1866*4b22b933Srs200217 return(st);
1867*4b22b933Srs200217 }
1868*4b22b933Srs200217
1869*4b22b933Srs200217 #ifdef _HAVE_SETDOMAIN_SUPPORT_
free_defdomain(mDNS * const m,AuthRecord * const rr,mStatus result)1870*4b22b933Srs200217 mDNSlocal void free_defdomain(mDNS *const m, AuthRecord *const rr, mStatus result)
1871*4b22b933Srs200217 {
1872*4b22b933Srs200217 (void)m; // unused
1873*4b22b933Srs200217 if (result == mStatus_MemFree) free(rr->RecordContext); // context is the enclosing list structure
1874*4b22b933Srs200217 }
1875*4b22b933Srs200217 #endif
1876*4b22b933Srs200217
handle_setdomain_request(request_state * request)1877*4b22b933Srs200217 mDNSlocal void handle_setdomain_request(request_state *request)
1878*4b22b933Srs200217 {
1879*4b22b933Srs200217 mStatus err = mStatus_NoError;
1880*4b22b933Srs200217 char *ptr;
1881*4b22b933Srs200217 char domainstr[MAX_ESCAPED_DOMAIN_NAME];
1882*4b22b933Srs200217 domainname domain;
1883*4b22b933Srs200217 DNSServiceFlags flags;
1884*4b22b933Srs200217 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1885*4b22b933Srs200217 struct xucred xuc;
1886*4b22b933Srs200217 socklen_t xuclen;
1887*4b22b933Srs200217 #endif
1888*4b22b933Srs200217
1889*4b22b933Srs200217 if (request->ts != t_complete)
1890*4b22b933Srs200217 {
1891*4b22b933Srs200217 LogMsg("ERROR: handle_setdomain_request - transfer state != t_complete");
1892*4b22b933Srs200217 abort_request(request);
1893*4b22b933Srs200217 unlink_request(request);
1894*4b22b933Srs200217 return;
1895*4b22b933Srs200217 }
1896*4b22b933Srs200217
1897*4b22b933Srs200217 // extract flags/domain from message
1898*4b22b933Srs200217 ptr = request->msgdata;
1899*4b22b933Srs200217 flags = get_flags(&ptr);
1900*4b22b933Srs200217 if (get_string(&ptr, domainstr, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1901*4b22b933Srs200217 !MakeDomainNameFromDNSNameString(&domain, domainstr))
1902*4b22b933Srs200217 { err = mStatus_BadParamErr; goto end; }
1903*4b22b933Srs200217
1904*4b22b933Srs200217 freeL("handle_setdomain_request", request->msgbuf);
1905*4b22b933Srs200217 request->msgbuf = NULL;
1906*4b22b933Srs200217
1907*4b22b933Srs200217 debugf("%3d: DNSServiceSetDefaultDomainForUser(%##s)", request->sd, domain.c);
1908*4b22b933Srs200217
1909*4b22b933Srs200217 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1910*4b22b933Srs200217 // this functionality currently only used for Apple-specific configuration, so we don't burned other platforms by mandating
1911*4b22b933Srs200217 // the existence of this socket option
1912*4b22b933Srs200217 xuclen = sizeof(xuc);
1913*4b22b933Srs200217 if (getsockopt(request->sd, 0, LOCAL_PEERCRED, &xuc, &xuclen))
1914*4b22b933Srs200217 { my_perror("ERROR: getsockopt, LOCAL_PEERCRED"); err = mStatus_UnknownErr; goto end; }
1915*4b22b933Srs200217 if (xuc.cr_version != XUCRED_VERSION) { LogMsg("getsockopt, LOCAL_PEERCRED - bad version"); err = mStatus_UnknownErr; goto end; }
1916*4b22b933Srs200217 LogMsg("Default domain %s %s for UID %d", domainstr, flags & kDNSServiceFlagsAdd ? "set" : "removed", xuc.cr_uid);
1917*4b22b933Srs200217
1918*4b22b933Srs200217 if (flags & kDNSServiceFlagsAdd)
1919*4b22b933Srs200217 {
1920*4b22b933Srs200217 // register a local-only PRT record
1921*4b22b933Srs200217 default_browse_list_t *newelem = malloc(sizeof(default_browse_list_t));
1922*4b22b933Srs200217 if (!newelem) { LogMsg("ERROR: malloc"); err = mStatus_NoMemoryErr; goto end; }
1923*4b22b933Srs200217 mDNS_SetupResourceRecord(&newelem->ptr_rec, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, free_defdomain, newelem);
1924*4b22b933Srs200217 MakeDomainNameFromDNSNameString(&newelem->ptr_rec.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault]);
1925*4b22b933Srs200217 AppendDNSNameString (&newelem->ptr_rec.resrec.name, "local");
1926*4b22b933Srs200217 AssignDomainName(&newelem->ptr_rec.resrec.rdata->u.name, &domain);
1927*4b22b933Srs200217 newelem->uid = xuc.cr_uid;
1928*4b22b933Srs200217 err = mDNS_Register(gmDNS, &newelem->ptr_rec);
1929*4b22b933Srs200217 if (err) free(newelem);
1930*4b22b933Srs200217 else
1931*4b22b933Srs200217 {
1932*4b22b933Srs200217 // link into list
1933*4b22b933Srs200217 newelem->next = default_browse_list;
1934*4b22b933Srs200217 default_browse_list = newelem;
1935*4b22b933Srs200217 }
1936*4b22b933Srs200217
1937*4b22b933Srs200217 }
1938*4b22b933Srs200217 else
1939*4b22b933Srs200217 {
1940*4b22b933Srs200217 // remove - find in list, deregister
1941*4b22b933Srs200217 default_browse_list_t *ptr = default_browse_list, *prev = NULL;
1942*4b22b933Srs200217 while (ptr)
1943*4b22b933Srs200217 {
1944*4b22b933Srs200217 if (SameDomainName(&ptr->ptr_rec.resrec.rdata->u.name, &domain))
1945*4b22b933Srs200217 {
1946*4b22b933Srs200217 if (prev) prev->next = ptr->next;
1947*4b22b933Srs200217 else default_browse_list = ptr->next;
1948*4b22b933Srs200217 err = mDNS_Deregister(gmDNS, &ptr->ptr_rec);
1949*4b22b933Srs200217 break;
1950*4b22b933Srs200217 }
1951*4b22b933Srs200217 prev = ptr;
1952*4b22b933Srs200217 ptr = ptr->next;
1953*4b22b933Srs200217 }
1954*4b22b933Srs200217 if (!ptr) { LogMsg("Attempt to remove nonexistent domain %s for UID %d", domainstr, xuc.cr_uid); err = mStatus_Invalid; }
1955*4b22b933Srs200217 }
1956*4b22b933Srs200217 #else
1957*4b22b933Srs200217 err = mStatus_NoError;
1958*4b22b933Srs200217 #endif // _HAVE_SETDOMAIN_SUPPORT_
1959*4b22b933Srs200217
1960*4b22b933Srs200217 end:
1961*4b22b933Srs200217 deliver_error(request, err);
1962*4b22b933Srs200217 abort_request(request);
1963*4b22b933Srs200217 unlink_request(request);
1964*4b22b933Srs200217 }
1965*4b22b933Srs200217
1966*4b22b933Srs200217 // Generates a response message giving name, type, domain, plus interface index,
1967*4b22b933Srs200217 // suitable for a browse result or service registration result.
1968*4b22b933Srs200217 // On successful completion rep is set to point to a malloc'd reply_state struct
GenerateNTDResponse(domainname * servicename,mDNSInterfaceID id,request_state * request,reply_state ** rep)1969*4b22b933Srs200217 mDNSlocal mStatus GenerateNTDResponse(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep)
1970*4b22b933Srs200217 {
1971*4b22b933Srs200217 domainlabel name;
1972*4b22b933Srs200217 domainname type, dom;
1973*4b22b933Srs200217 *rep = NULL;
1974*4b22b933Srs200217 if (!DeconstructServiceName(servicename, &name, &type, &dom))
1975*4b22b933Srs200217 return kDNSServiceErr_Invalid;
1976*4b22b933Srs200217 else
1977*4b22b933Srs200217 {
1978*4b22b933Srs200217 char namestr[MAX_DOMAIN_LABEL+1];
1979*4b22b933Srs200217 char typestr[MAX_ESCAPED_DOMAIN_NAME];
1980*4b22b933Srs200217 char domstr [MAX_ESCAPED_DOMAIN_NAME];
1981*4b22b933Srs200217 int len;
1982*4b22b933Srs200217 char *data;
1983*4b22b933Srs200217
1984*4b22b933Srs200217 ConvertDomainLabelToCString_unescaped(&name, namestr);
1985*4b22b933Srs200217 ConvertDomainNameToCString(&type, typestr);
1986*4b22b933Srs200217 ConvertDomainNameToCString(&dom, domstr);
1987*4b22b933Srs200217
1988*4b22b933Srs200217 // Calculate reply data length
1989*4b22b933Srs200217 len = sizeof(DNSServiceFlags);
1990*4b22b933Srs200217 len += sizeof(uint32_t); // if index
1991*4b22b933Srs200217 len += sizeof(DNSServiceErrorType);
1992*4b22b933Srs200217 len += (int) (strlen(namestr) + 1);
1993*4b22b933Srs200217 len += (int) (strlen(typestr) + 1);
1994*4b22b933Srs200217 len += (int) (strlen(domstr) + 1);
1995*4b22b933Srs200217
1996*4b22b933Srs200217 // Build reply header
1997*4b22b933Srs200217 *rep = create_reply(query_reply_op, len, request);
1998*4b22b933Srs200217 (*rep)->rhdr->flags = dnssd_htonl(0);
1999*4b22b933Srs200217 (*rep)->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, id));
2000*4b22b933Srs200217 (*rep)->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
2001*4b22b933Srs200217
2002*4b22b933Srs200217 // Build reply body
2003*4b22b933Srs200217 data = (*rep)->sdata;
2004*4b22b933Srs200217 put_string(namestr, &data);
2005*4b22b933Srs200217 put_string(typestr, &data);
2006*4b22b933Srs200217 put_string(domstr, &data);
2007*4b22b933Srs200217
2008*4b22b933Srs200217 return mStatus_NoError;
2009*4b22b933Srs200217 }
2010*4b22b933Srs200217 }
2011*4b22b933Srs200217
FoundInstance(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,mDNSBool AddRecord)2012*4b22b933Srs200217 mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
2013*4b22b933Srs200217 {
2014*4b22b933Srs200217 request_state *req = question->QuestionContext;
2015*4b22b933Srs200217 reply_state *rep;
2016*4b22b933Srs200217 (void)m; // Unused
2017*4b22b933Srs200217
2018*4b22b933Srs200217 if (answer->rrtype != kDNSType_PTR)
2019*4b22b933Srs200217 { LogMsg("%3d: FoundInstance: Should not be called with rrtype %d (not a PTR record)", req->sd, answer->rrtype); return; }
2020*4b22b933Srs200217
2021*4b22b933Srs200217 if (GenerateNTDResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep) != mStatus_NoError)
2022*4b22b933Srs200217 {
2023*4b22b933Srs200217 LogMsg("%3d: FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
2024*4b22b933Srs200217 req->sd, answer->name->c, answer->rdata->u.name.c);
2025*4b22b933Srs200217 return;
2026*4b22b933Srs200217 }
2027*4b22b933Srs200217
2028*4b22b933Srs200217 LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
2029*4b22b933Srs200217 req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
2030*4b22b933Srs200217
2031*4b22b933Srs200217 if (AddRecord) rep->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsAdd);
2032*4b22b933Srs200217 append_reply(req, rep);
2033*4b22b933Srs200217 }
2034*4b22b933Srs200217
add_domain_to_browser(browser_info_t * info,const domainname * d)2035*4b22b933Srs200217 mDNSlocal mStatus add_domain_to_browser(browser_info_t *info, const domainname *d)
2036*4b22b933Srs200217 {
2037*4b22b933Srs200217 browser_t *b, *p;
2038*4b22b933Srs200217 mStatus err;
2039*4b22b933Srs200217
2040*4b22b933Srs200217 for (p = info->browsers; p; p = p->next)
2041*4b22b933Srs200217 {
2042*4b22b933Srs200217 if (SameDomainName(&p->domain, d))
2043*4b22b933Srs200217 { debugf("add_domain_to_browser - attempt to add domain %##d already in list", d->c); return mStatus_AlreadyRegistered; }
2044*4b22b933Srs200217 }
2045*4b22b933Srs200217
2046*4b22b933Srs200217 b = mallocL("browser_t", sizeof(*b));
2047*4b22b933Srs200217 if (!b) return mStatus_NoMemoryErr;
2048*4b22b933Srs200217 AssignDomainName(&b->domain, d);
2049*4b22b933Srs200217 err = mDNS_StartBrowse(gmDNS, &b->q, &info->regtype, d, info->interface_id, info->ForceMCast, FoundInstance, info->rstate);
2050*4b22b933Srs200217 if (err)
2051*4b22b933Srs200217 {
2052*4b22b933Srs200217 LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err, info->regtype.c, d->c);
2053*4b22b933Srs200217 freeL("browser_t", b);
2054*4b22b933Srs200217 }
2055*4b22b933Srs200217 else
2056*4b22b933Srs200217 {
2057*4b22b933Srs200217 b->next = info->browsers;
2058*4b22b933Srs200217 info->browsers = b;
2059*4b22b933Srs200217 }
2060*4b22b933Srs200217 return err;
2061*4b22b933Srs200217 }
2062*4b22b933Srs200217
handle_browse_request(request_state * request)2063*4b22b933Srs200217 mDNSlocal void handle_browse_request(request_state *request)
2064*4b22b933Srs200217 {
2065*4b22b933Srs200217 DNSServiceFlags flags;
2066*4b22b933Srs200217 uint32_t interfaceIndex;
2067*4b22b933Srs200217 mDNSInterfaceID InterfaceID;
2068*4b22b933Srs200217 char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
2069*4b22b933Srs200217 domainname typedn, d, temp;
2070*4b22b933Srs200217 mDNSs32 NumSubTypes;
2071*4b22b933Srs200217 char *ptr;
2072*4b22b933Srs200217 mStatus err = mStatus_NoError;
2073*4b22b933Srs200217 DNameListElem *search_domain_list, *sdom;
2074*4b22b933Srs200217 browser_info_t *info = NULL;
2075*4b22b933Srs200217
2076*4b22b933Srs200217 if (request->ts != t_complete)
2077*4b22b933Srs200217 {
2078*4b22b933Srs200217 LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
2079*4b22b933Srs200217 abort_request(request);
2080*4b22b933Srs200217 unlink_request(request);
2081*4b22b933Srs200217 return;
2082*4b22b933Srs200217 }
2083*4b22b933Srs200217
2084*4b22b933Srs200217 // extract data from message
2085*4b22b933Srs200217 ptr = request->msgdata;
2086*4b22b933Srs200217 flags = get_flags(&ptr);
2087*4b22b933Srs200217 interfaceIndex = get_long(&ptr);
2088*4b22b933Srs200217 if (get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
2089*4b22b933Srs200217 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
2090*4b22b933Srs200217 { err = mStatus_BadParamErr; goto error; }
2091*4b22b933Srs200217 freeL("handle_browse_request", request->msgbuf);
2092*4b22b933Srs200217 request->msgbuf = NULL;
2093*4b22b933Srs200217
2094*4b22b933Srs200217 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
2095*4b22b933Srs200217 if (interfaceIndex && !InterfaceID) { err = mStatus_BadParamErr; goto error; }
2096*4b22b933Srs200217
2097*4b22b933Srs200217 #if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
2098*4b22b933Srs200217 if ( !domain || ( domain[0] == '\0' ) )
2099*4b22b933Srs200217 {
2100*4b22b933Srs200217 dDNS_RegisterSearchDomains( gmDNS );
2101*4b22b933Srs200217 }
2102*4b22b933Srs200217 #endif
2103*4b22b933Srs200217
2104*4b22b933Srs200217 typedn.c[0] = 0;
2105*4b22b933Srs200217 NumSubTypes = ChopSubTypes(regtype); // Note: Modifies regtype string to remove trailing subtypes
2106*4b22b933Srs200217 if (NumSubTypes < 0 || NumSubTypes > 1) { err = mStatus_BadParamErr; goto error; }
2107*4b22b933Srs200217 if (NumSubTypes == 1 && !AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1))
2108*4b22b933Srs200217 { err = mStatus_BadParamErr; goto error; }
2109*4b22b933Srs200217
2110*4b22b933Srs200217 if (!regtype[0] || !AppendDNSNameString(&typedn, regtype)) { err = mStatus_BadParamErr; goto error; }
2111*4b22b933Srs200217
2112*4b22b933Srs200217 if (!MakeDomainNameFromDNSNameString(&temp, regtype)) { err = mStatus_BadParamErr; goto error; }
2113*4b22b933Srs200217 if (temp.c[0] > 15 && domain[0] == 0) strcpy(domain, "local."); // For over-long service types, we only allow domain "local"
2114*4b22b933Srs200217
2115*4b22b933Srs200217 // allocate and set up browser info
2116*4b22b933Srs200217 info = mallocL("browser_info_t", sizeof(*info));
2117*4b22b933Srs200217 if (!info) { err = mStatus_NoMemoryErr; goto error; }
2118*4b22b933Srs200217
2119*4b22b933Srs200217 request->browser_info = info;
2120*4b22b933Srs200217 info->ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
2121*4b22b933Srs200217 info->interface_id = InterfaceID;
2122*4b22b933Srs200217 AssignDomainName(&info->regtype, &typedn);
2123*4b22b933Srs200217 info->rstate = request;
2124*4b22b933Srs200217 info->default_domain = !domain[0];
2125*4b22b933Srs200217 info->browsers = NULL;
2126*4b22b933Srs200217
2127*4b22b933Srs200217 // setup termination context
2128*4b22b933Srs200217 request->termination_context = info;
2129*4b22b933Srs200217 request->terminate = browse_termination_callback;
2130*4b22b933Srs200217
2131*4b22b933Srs200217 LogOperation("%3d: DNSServiceBrowse(\"%##s\", \"%s\") START", request->sd, info->regtype.c, domain);
2132*4b22b933Srs200217 if (domain[0])
2133*4b22b933Srs200217 {
2134*4b22b933Srs200217 if (!MakeDomainNameFromDNSNameString(&d, domain)) { err = mStatus_BadParamErr; goto error; }
2135*4b22b933Srs200217 err = add_domain_to_browser(info, &d);
2136*4b22b933Srs200217 }
2137*4b22b933Srs200217
2138*4b22b933Srs200217 else
2139*4b22b933Srs200217 {
2140*4b22b933Srs200217 search_domain_list = mDNSPlatformGetSearchDomainList();
2141*4b22b933Srs200217 for (sdom = search_domain_list; sdom; sdom = sdom->next)
2142*4b22b933Srs200217 {
2143*4b22b933Srs200217 err = add_domain_to_browser(info, &sdom->name);
2144*4b22b933Srs200217 if (err)
2145*4b22b933Srs200217 {
2146*4b22b933Srs200217 if (SameDomainName(&sdom->name, &localdomain)) break;
2147*4b22b933Srs200217 else err = mStatus_NoError; // suppress errors for non-local "default" domains
2148*4b22b933Srs200217 }
2149*4b22b933Srs200217
2150*4b22b933Srs200217 }
2151*4b22b933Srs200217 mDNS_FreeDNameList(search_domain_list);
2152*4b22b933Srs200217 }
2153*4b22b933Srs200217
2154*4b22b933Srs200217 deliver_error(request, err);
2155*4b22b933Srs200217 return;
2156*4b22b933Srs200217
2157*4b22b933Srs200217 error:
2158*4b22b933Srs200217 if (info) freeL("browser_info_t", info);
2159*4b22b933Srs200217 if (request->termination_context) request->termination_context = NULL;
2160*4b22b933Srs200217 deliver_error(request, err);
2161*4b22b933Srs200217 abort_request(request);
2162*4b22b933Srs200217 unlink_request(request);
2163*4b22b933Srs200217 }
2164*4b22b933Srs200217
browse_termination_callback(void * context)2165*4b22b933Srs200217 mDNSlocal void browse_termination_callback(void *context)
2166*4b22b933Srs200217 {
2167*4b22b933Srs200217 browser_info_t *info = context;
2168*4b22b933Srs200217 browser_t *ptr;
2169*4b22b933Srs200217
2170*4b22b933Srs200217 if (!info) return;
2171*4b22b933Srs200217
2172*4b22b933Srs200217 while(info->browsers)
2173*4b22b933Srs200217 {
2174*4b22b933Srs200217 ptr = info->browsers;
2175*4b22b933Srs200217 info->browsers = ptr->next;
2176*4b22b933Srs200217 LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info->rstate->sd, ptr->q.qname.c);
2177*4b22b933Srs200217 mDNS_StopBrowse(gmDNS, &ptr->q); // no need to error-check result
2178*4b22b933Srs200217 freeL("browse_termination_callback", ptr);
2179*4b22b933Srs200217 }
2180*4b22b933Srs200217
2181*4b22b933Srs200217 info->rstate->termination_context = NULL;
2182*4b22b933Srs200217 freeL("browser_info", info);
2183*4b22b933Srs200217 }
2184*4b22b933Srs200217
udsserver_default_browse_domain_changed(const domainname * d,mDNSBool add)2185*4b22b933Srs200217 mDNSexport void udsserver_default_browse_domain_changed(const domainname *d, mDNSBool add)
2186*4b22b933Srs200217 {
2187*4b22b933Srs200217 request_state *r;
2188*4b22b933Srs200217
2189*4b22b933Srs200217 for (r = all_requests; r; r = r->next)
2190*4b22b933Srs200217 {
2191*4b22b933Srs200217 browser_info_t *info = r->browser_info;
2192*4b22b933Srs200217
2193*4b22b933Srs200217 if (!info || !info->default_domain) continue;
2194*4b22b933Srs200217 if (add) add_domain_to_browser(info, d);
2195*4b22b933Srs200217 else
2196*4b22b933Srs200217 {
2197*4b22b933Srs200217 browser_t **ptr = &info->browsers;
2198*4b22b933Srs200217 while (*ptr)
2199*4b22b933Srs200217 {
2200*4b22b933Srs200217 if (SameDomainName(&(*ptr)->domain, d))
2201*4b22b933Srs200217 {
2202*4b22b933Srs200217 browser_t *remove = *ptr;
2203*4b22b933Srs200217 *ptr = (*ptr)->next;
2204*4b22b933Srs200217 if (remove->q.LongLived)
2205*4b22b933Srs200217 {
2206*4b22b933Srs200217 // Give goodbyes for known answers.
2207*4b22b933Srs200217 // Note that this a special case where we know that the QuestionCallback function is our own
2208*4b22b933Srs200217 // code (it's FoundInstance), and that callback routine doesn't ever cancel its operation, so we
2209*4b22b933Srs200217 // don't need to guard against the question being cancelled mid-loop the way the mDNSCore routines do.
2210*4b22b933Srs200217 CacheRecord *ka = remove->q.uDNS_info.knownAnswers;
2211*4b22b933Srs200217 while (ka) { remove->q.QuestionCallback(gmDNS, &remove->q, &ka->resrec, mDNSfalse); ka = ka->next; }
2212*4b22b933Srs200217 }
2213*4b22b933Srs200217 mDNS_StopBrowse(gmDNS, &remove->q);
2214*4b22b933Srs200217 freeL("browser_t", remove);
2215*4b22b933Srs200217 return;
2216*4b22b933Srs200217 }
2217*4b22b933Srs200217 ptr = &(*ptr)->next;
2218*4b22b933Srs200217 }
2219*4b22b933Srs200217 LogMsg("Requested removal of default domain %##s not in list for sd %d", d->c, r->sd);
2220*4b22b933Srs200217 }
2221*4b22b933Srs200217 }
2222*4b22b933Srs200217 }
2223*4b22b933Srs200217
2224*4b22b933Srs200217 // Count how many other service records we have locally with the same name, but different rdata.
2225*4b22b933Srs200217 // For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
2226*4b22b933Srs200217 // the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
CountPeerRegistrations(mDNS * const m,ServiceRecordSet * const srs)2227*4b22b933Srs200217 mDNSexport int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs)
2228*4b22b933Srs200217 {
2229*4b22b933Srs200217 int count = 0;
2230*4b22b933Srs200217 ResourceRecord *r = &srs->RR_SRV.resrec;
2231*4b22b933Srs200217 AuthRecord *rr;
2232*4b22b933Srs200217 ServiceRecordSet *s;
2233*4b22b933Srs200217
2234*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next)
2235*4b22b933Srs200217 if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
2236*4b22b933Srs200217 count++;
2237*4b22b933Srs200217
2238*4b22b933Srs200217 for (rr = m->uDNS_info.RecordRegistrations; rr; rr=rr->next)
2239*4b22b933Srs200217 if (rr->uDNS_info.state != regState_Unregistered && rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
2240*4b22b933Srs200217 count++;
2241*4b22b933Srs200217
2242*4b22b933Srs200217 for (s = m->uDNS_info.ServiceRegistrations; s; s = s->next)
2243*4b22b933Srs200217 if (s->uDNS_info.state != regState_Unregistered && SameDomainName(s->RR_SRV.resrec.name, r->name) && !SameRData(&s->RR_SRV.resrec, r))
2244*4b22b933Srs200217 count++;
2245*4b22b933Srs200217
2246*4b22b933Srs200217 verbosedebugf("%d peer registrations for %##s", count, r->name->c);
2247*4b22b933Srs200217 return(count);
2248*4b22b933Srs200217 }
2249*4b22b933Srs200217
CountExistingRegistrations(domainname * srv,mDNSIPPort port)2250*4b22b933Srs200217 mDNSexport int CountExistingRegistrations(domainname *srv, mDNSIPPort port)
2251*4b22b933Srs200217 {
2252*4b22b933Srs200217 int count = 0;
2253*4b22b933Srs200217 AuthRecord *rr;
2254*4b22b933Srs200217 for (rr = gmDNS->ResourceRecords; rr; rr=rr->next)
2255*4b22b933Srs200217 if (rr->resrec.rrtype == kDNSType_SRV &&
2256*4b22b933Srs200217 rr->resrec.rdata->u.srv.port.NotAnInteger == port.NotAnInteger &&
2257*4b22b933Srs200217 SameDomainName(rr->resrec.name, srv))
2258*4b22b933Srs200217 count++;
2259*4b22b933Srs200217 return(count);
2260*4b22b933Srs200217 }
2261*4b22b933Srs200217
register_service_instance(request_state * request,const domainname * domain)2262*4b22b933Srs200217 mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain)
2263*4b22b933Srs200217 {
2264*4b22b933Srs200217 service_info *info = request->service_registration;
2265*4b22b933Srs200217 service_instance *ptr, *instance;
2266*4b22b933Srs200217 int instance_size;
2267*4b22b933Srs200217 mStatus result;
2268*4b22b933Srs200217
2269*4b22b933Srs200217 for (ptr = info->instances; ptr; ptr = ptr->next)
2270*4b22b933Srs200217 {
2271*4b22b933Srs200217 if (SameDomainName(&ptr->domain, domain))
2272*4b22b933Srs200217 { LogMsg("register_service_instance: domain %##s already registered", domain->c); return mStatus_AlreadyRegistered; }
2273*4b22b933Srs200217 }
2274*4b22b933Srs200217
2275*4b22b933Srs200217 instance_size = sizeof(*instance);
2276*4b22b933Srs200217 if (info->txtlen > sizeof(RDataBody)) instance_size += (info->txtlen - sizeof(RDataBody));
2277*4b22b933Srs200217 instance = mallocL("service_instance", instance_size);
2278*4b22b933Srs200217 if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
2279*4b22b933Srs200217
2280*4b22b933Srs200217 instance->subtypes = AllocateSubTypes(info->num_subtypes, info->type_as_string);
2281*4b22b933Srs200217 if (info->num_subtypes && !instance->subtypes)
2282*4b22b933Srs200217 { free_service_instance(instance); instance = NULL; FatalError("ERROR: malloc"); }
2283*4b22b933Srs200217 instance->request = request;
2284*4b22b933Srs200217 instance->sd = request->sd;
2285*4b22b933Srs200217 instance->autoname = info->autoname;
2286*4b22b933Srs200217 instance->autorename = info->autorename;
2287*4b22b933Srs200217 instance->allowremotequery = info->allowremotequery;
2288*4b22b933Srs200217 instance->rename_on_memfree = 0;
2289*4b22b933Srs200217 instance->name = info->name;
2290*4b22b933Srs200217 AssignDomainName(&instance->domain, domain);
2291*4b22b933Srs200217 instance->default_local = (info->default_domain && SameDomainName(domain, &localdomain));
2292*4b22b933Srs200217 result = mDNS_RegisterService(gmDNS, &instance->srs, &instance->name, &info->type, domain, info->host.c[0] ? &info->host : NULL, info->port,
2293*4b22b933Srs200217 info->txtdata, info->txtlen, instance->subtypes, info->num_subtypes, info->InterfaceID, regservice_callback, instance);
2294*4b22b933Srs200217
2295*4b22b933Srs200217 if (result) free_service_instance(instance);
2296*4b22b933Srs200217 else
2297*4b22b933Srs200217 {
2298*4b22b933Srs200217 instance->next = info->instances;
2299*4b22b933Srs200217 info->instances = instance;
2300*4b22b933Srs200217 }
2301*4b22b933Srs200217 return result;
2302*4b22b933Srs200217 }
2303*4b22b933Srs200217
udsserver_default_reg_domain_changed(const domainname * d,mDNSBool add)2304*4b22b933Srs200217 mDNSexport void udsserver_default_reg_domain_changed(const domainname *d, mDNSBool add)
2305*4b22b933Srs200217 {
2306*4b22b933Srs200217 request_state *rstate;
2307*4b22b933Srs200217 service_info *info;
2308*4b22b933Srs200217
2309*4b22b933Srs200217 LogMsg("%s registration domain %##s", add ? "Adding" : "Removing", d->c);
2310*4b22b933Srs200217 for (rstate = all_requests; rstate; rstate = rstate->next)
2311*4b22b933Srs200217 {
2312*4b22b933Srs200217 if (rstate->terminate != regservice_termination_callback) continue;
2313*4b22b933Srs200217 info = rstate->service_registration;
2314*4b22b933Srs200217 if (!info) { LogMsg("udsserver_default_reg_domain_changed - NULL service info"); continue; } // this should never happen
2315*4b22b933Srs200217 if (!info->default_domain) continue;
2316*4b22b933Srs200217
2317*4b22b933Srs200217 // valid default registration
2318*4b22b933Srs200217 if (add) register_service_instance(rstate, d);
2319*4b22b933Srs200217 else
2320*4b22b933Srs200217 {
2321*4b22b933Srs200217 // find the instance to remove
2322*4b22b933Srs200217 service_instance *si = rstate->service_registration->instances, *prev = NULL;
2323*4b22b933Srs200217 while (si)
2324*4b22b933Srs200217 {
2325*4b22b933Srs200217 if (SameDomainName(&si->domain, d))
2326*4b22b933Srs200217 {
2327*4b22b933Srs200217 mStatus err;
2328*4b22b933Srs200217 if (prev) prev->next = si->next;
2329*4b22b933Srs200217 else info->instances = si->next;
2330*4b22b933Srs200217 err = mDNS_DeregisterService(gmDNS, &si->srs);
2331*4b22b933Srs200217 if (err)
2332*4b22b933Srs200217 {
2333*4b22b933Srs200217 LogMsg("udsserver_default_reg_domain_changed - mDNS_DeregisterService err %d", err);
2334*4b22b933Srs200217 free_service_instance(si);
2335*4b22b933Srs200217 }
2336*4b22b933Srs200217 break;
2337*4b22b933Srs200217 }
2338*4b22b933Srs200217 prev = si;
2339*4b22b933Srs200217 si = si->next;
2340*4b22b933Srs200217 }
2341*4b22b933Srs200217 if (!si) debugf("udsserver_default_reg_domain_changed - domain %##s not registered", d->c); // normal if registration failed
2342*4b22b933Srs200217 }
2343*4b22b933Srs200217 }
2344*4b22b933Srs200217 }
2345*4b22b933Srs200217
2346*4b22b933Srs200217 // service registration
handle_regservice_request(request_state * request)2347*4b22b933Srs200217 mDNSlocal void handle_regservice_request(request_state *request)
2348*4b22b933Srs200217 {
2349*4b22b933Srs200217 DNSServiceFlags flags;
2350*4b22b933Srs200217 uint32_t ifi;
2351*4b22b933Srs200217 char name[1024]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
2352*4b22b933Srs200217 char domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
2353*4b22b933Srs200217 char *ptr;
2354*4b22b933Srs200217 domainname d, srv;
2355*4b22b933Srs200217 mStatus result;
2356*4b22b933Srs200217 service_info *service = NULL;
2357*4b22b933Srs200217
2358*4b22b933Srs200217 if (request->ts != t_complete)
2359*4b22b933Srs200217 {
2360*4b22b933Srs200217 LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
2361*4b22b933Srs200217 abort_request(request);
2362*4b22b933Srs200217 unlink_request(request);
2363*4b22b933Srs200217 return;
2364*4b22b933Srs200217 }
2365*4b22b933Srs200217
2366*4b22b933Srs200217 service = mallocL("service_info", sizeof(*service));
2367*4b22b933Srs200217 if (!service) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; }
2368*4b22b933Srs200217
2369*4b22b933Srs200217 service->instances = NULL;
2370*4b22b933Srs200217 service->request = request;
2371*4b22b933Srs200217 service->txtlen = 0;
2372*4b22b933Srs200217 service->txtdata = NULL;
2373*4b22b933Srs200217 request->service_registration = service;
2374*4b22b933Srs200217 request->termination_context = request->service_registration;
2375*4b22b933Srs200217 request->terminate = regservice_termination_callback;
2376*4b22b933Srs200217
2377*4b22b933Srs200217 // extract data from message
2378*4b22b933Srs200217 ptr = request->msgdata;
2379*4b22b933Srs200217 flags = get_flags(&ptr);
2380*4b22b933Srs200217 ifi = get_long(&ptr);
2381*4b22b933Srs200217 service->InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
2382*4b22b933Srs200217 if (ifi && !service->InterfaceID)
2383*4b22b933Srs200217 { LogMsg("ERROR: handle_regservice_request - Couldn't find InterfaceID for interfaceIndex %d", ifi); goto bad_param; }
2384*4b22b933Srs200217 if (get_string(&ptr, name, sizeof(name)) < 0 ||
2385*4b22b933Srs200217 get_string(&ptr, service->type_as_string, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
2386*4b22b933Srs200217 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
2387*4b22b933Srs200217 get_string(&ptr, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
2388*4b22b933Srs200217 { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); goto bad_param; }
2389*4b22b933Srs200217
2390*4b22b933Srs200217 service->port.b[0] = *ptr++;
2391*4b22b933Srs200217 service->port.b[1] = *ptr++;
2392*4b22b933Srs200217
2393*4b22b933Srs200217 service->txtlen = get_short(&ptr);
2394*4b22b933Srs200217 if (service->txtlen)
2395*4b22b933Srs200217 {
2396*4b22b933Srs200217 service->txtdata = mallocL("txtdata", service->txtlen);
2397*4b22b933Srs200217 if (!service->txtdata) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; }
2398*4b22b933Srs200217 memcpy(service->txtdata, get_rdata(&ptr, service->txtlen), service->txtlen);
2399*4b22b933Srs200217 }
2400*4b22b933Srs200217 else service->txtdata = NULL;
2401*4b22b933Srs200217
2402*4b22b933Srs200217 // Check for sub-types after the service type
2403*4b22b933Srs200217 service->num_subtypes = ChopSubTypes(service->type_as_string); // Note: Modifies regtype string to remove trailing subtypes
2404*4b22b933Srs200217 if (service->num_subtypes < 0)
2405*4b22b933Srs200217 { LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", service->type_as_string); goto bad_param; }
2406*4b22b933Srs200217
2407*4b22b933Srs200217 // Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
2408*4b22b933Srs200217 if (!*service->type_as_string || !MakeDomainNameFromDNSNameString(&service->type, service->type_as_string))
2409*4b22b933Srs200217 { LogMsg("ERROR: handle_regservice_request - service->type_as_string bad %s", service->type_as_string); goto bad_param; }
2410*4b22b933Srs200217
2411*4b22b933Srs200217 if (!name[0])
2412*4b22b933Srs200217 {
2413*4b22b933Srs200217 service->name = (gmDNS)->nicelabel;
2414*4b22b933Srs200217 service->autoname = mDNStrue;
2415*4b22b933Srs200217 }
2416*4b22b933Srs200217 else
2417*4b22b933Srs200217 {
2418*4b22b933Srs200217 // If the client is allowing AutoRename, then truncate name to legal length before converting it to a DomainLabel
2419*4b22b933Srs200217 if ((flags & kDNSServiceFlagsNoAutoRename) == 0)
2420*4b22b933Srs200217 {
2421*4b22b933Srs200217 int newlen = TruncateUTF8ToLength((mDNSu8*)name, mDNSPlatformStrLen(name), MAX_DOMAIN_LABEL);
2422*4b22b933Srs200217 name[newlen] = 0;
2423*4b22b933Srs200217 }
2424*4b22b933Srs200217 if (!MakeDomainLabelFromLiteralString(&service->name, name))
2425*4b22b933Srs200217 { LogMsg("ERROR: handle_regservice_request - name bad %s", name); goto bad_param; }
2426*4b22b933Srs200217 service->autoname = mDNSfalse;
2427*4b22b933Srs200217 }
2428*4b22b933Srs200217
2429*4b22b933Srs200217 if (*domain)
2430*4b22b933Srs200217 {
2431*4b22b933Srs200217 service->default_domain = mDNSfalse;
2432*4b22b933Srs200217 if (!MakeDomainNameFromDNSNameString(&d, domain))
2433*4b22b933Srs200217 { LogMsg("ERROR: handle_regservice_request - domain bad %s", domain); goto bad_param; }
2434*4b22b933Srs200217 }
2435*4b22b933Srs200217 else
2436*4b22b933Srs200217 {
2437*4b22b933Srs200217 service->default_domain = mDNStrue;
2438*4b22b933Srs200217 MakeDomainNameFromDNSNameString(&d, "local.");
2439*4b22b933Srs200217 }
2440*4b22b933Srs200217
2441*4b22b933Srs200217 if (!ConstructServiceName(&srv, &service->name, &service->type, &d))
2442*4b22b933Srs200217 { LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”", service->name.c, service->type.c, d.c); goto bad_param; }
2443*4b22b933Srs200217
2444*4b22b933Srs200217 if (!MakeDomainNameFromDNSNameString(&service->host, host))
2445*4b22b933Srs200217 { LogMsg("ERROR: handle_regservice_request - host bad %s", host); goto bad_param; }
2446*4b22b933Srs200217 service->autorename = (flags & kDNSServiceFlagsNoAutoRename ) == 0;
2447*4b22b933Srs200217 service->allowremotequery = (flags & kDNSServiceFlagsAllowRemoteQuery) != 0;
2448*4b22b933Srs200217
2449*4b22b933Srs200217 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
2450*4b22b933Srs200217 // a port number of zero. When two instances of the protected client are allowed to run on one
2451*4b22b933Srs200217 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
2452*4b22b933Srs200217 if (service->port.NotAnInteger)
2453*4b22b933Srs200217 {
2454*4b22b933Srs200217 int count = CountExistingRegistrations(&srv, service->port);
2455*4b22b933Srs200217 if (count)
2456*4b22b933Srs200217 LogMsg("Client application registered %d identical instances of service %##s port %u.",
2457*4b22b933Srs200217 count+1, srv.c, mDNSVal16(service->port));
2458*4b22b933Srs200217 }
2459*4b22b933Srs200217
2460*4b22b933Srs200217 LogOperation("%3d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", \"%s\", %u) START",
2461*4b22b933Srs200217 request->sd, name, service->type_as_string, domain, host, mDNSVal16(service->port));
2462*4b22b933Srs200217 result = register_service_instance(request, &d);
2463*4b22b933Srs200217
2464*4b22b933Srs200217 if (!result && !*domain)
2465*4b22b933Srs200217 {
2466*4b22b933Srs200217 DNameListElem *ptr, *def_domains = mDNSPlatformGetRegDomainList();
2467*4b22b933Srs200217 for (ptr = def_domains; ptr; ptr = ptr->next)
2468*4b22b933Srs200217 register_service_instance(request, &ptr->name);
2469*4b22b933Srs200217 // note that we don't report errors for non-local, non-explicit domains
2470*4b22b933Srs200217 mDNS_FreeDNameList(def_domains);
2471*4b22b933Srs200217 }
2472*4b22b933Srs200217
2473*4b22b933Srs200217 finish:
2474*4b22b933Srs200217 deliver_error(request, result);
2475*4b22b933Srs200217 if (result != mStatus_NoError)
2476*4b22b933Srs200217 {
2477*4b22b933Srs200217 abort_request(request);
2478*4b22b933Srs200217 unlink_request(request);
2479*4b22b933Srs200217 }
2480*4b22b933Srs200217 else
2481*4b22b933Srs200217 reset_connected_rstate(request); // prepare to receive add/remove messages
2482*4b22b933Srs200217
2483*4b22b933Srs200217 return;
2484*4b22b933Srs200217
2485*4b22b933Srs200217 bad_param:
2486*4b22b933Srs200217 //if (service) freeL("service_info", service); Don't think we should do this -- abort_request will free it a second time and crash
2487*4b22b933Srs200217 deliver_error(request, mStatus_BadParamErr);
2488*4b22b933Srs200217 abort_request(request);
2489*4b22b933Srs200217 unlink_request(request);
2490*4b22b933Srs200217 }
2491*4b22b933Srs200217
2492*4b22b933Srs200217 // service registration callback performs three duties - frees memory for deregistered services,
2493*4b22b933Srs200217 // handles name conflicts, and delivers completed registration information to the client (via
2494*4b22b933Srs200217 // process_service_registraion())
2495*4b22b933Srs200217
regservice_callback(mDNS * const m,ServiceRecordSet * const srs,mStatus result)2496*4b22b933Srs200217 mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
2497*4b22b933Srs200217 {
2498*4b22b933Srs200217 mStatus err;
2499*4b22b933Srs200217 mDNSBool SuppressError = mDNSfalse;
2500*4b22b933Srs200217 service_instance *instance = srs->ServiceContext;
2501*4b22b933Srs200217 (void)m; // Unused
2502*4b22b933Srs200217 if (!srs) { LogMsg("regservice_callback: srs is NULL %d", result); return; }
2503*4b22b933Srs200217 if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; }
2504*4b22b933Srs200217
2505*4b22b933Srs200217 if (instance->request && instance->request->service_registration)
2506*4b22b933Srs200217 {
2507*4b22b933Srs200217 service_info *info = instance->request->service_registration;
2508*4b22b933Srs200217 if (info->default_domain && !instance->default_local) SuppressError = mDNStrue;
2509*4b22b933Srs200217 // don't send errors up to client for wide-area, empty-string registrations
2510*4b22b933Srs200217 }
2511*4b22b933Srs200217
2512*4b22b933Srs200217 if (result == mStatus_NoError)
2513*4b22b933Srs200217 LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED ", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
2514*4b22b933Srs200217 else if (result == mStatus_MemFree)
2515*4b22b933Srs200217 LogOperation("%3d: DNSServiceRegister(%##s, %u) DEREGISTERED", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
2516*4b22b933Srs200217 else if (result == mStatus_NameConflict)
2517*4b22b933Srs200217 LogOperation("%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
2518*4b22b933Srs200217 else
2519*4b22b933Srs200217 LogOperation("%3d: DNSServiceRegister(%##s, %u) CALLBACK %d", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), result);
2520*4b22b933Srs200217
2521*4b22b933Srs200217 if (result == mStatus_NoError)
2522*4b22b933Srs200217 {
2523*4b22b933Srs200217 request_state *req = instance->request;
2524*4b22b933Srs200217 if (instance->allowremotequery)
2525*4b22b933Srs200217 {
2526*4b22b933Srs200217 ExtraResourceRecord *e;
2527*4b22b933Srs200217 srs->RR_ADV.AllowRemoteQuery = mDNStrue;
2528*4b22b933Srs200217 srs->RR_PTR.AllowRemoteQuery = mDNStrue;
2529*4b22b933Srs200217 srs->RR_SRV.AllowRemoteQuery = mDNStrue;
2530*4b22b933Srs200217 srs->RR_TXT.AllowRemoteQuery = mDNStrue;
2531*4b22b933Srs200217 for (e = instance->srs.Extras; e; e = e->next) e->r.AllowRemoteQuery = mDNStrue;
2532*4b22b933Srs200217 }
2533*4b22b933Srs200217
2534*4b22b933Srs200217 if (!req) LogMsg("ERROR: regservice_callback - null request object");
2535*4b22b933Srs200217 else
2536*4b22b933Srs200217 {
2537*4b22b933Srs200217 reply_state *rep;
2538*4b22b933Srs200217 if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep) != mStatus_NoError)
2539*4b22b933Srs200217 LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", req->sd, srs->RR_SRV.resrec.name->c);
2540*4b22b933Srs200217 else
2541*4b22b933Srs200217 {
2542*4b22b933Srs200217 transfer_state send_result = send_msg(rep);
2543*4b22b933Srs200217 if (send_result == t_error || send_result == t_terminated)
2544*4b22b933Srs200217 { abort_request(req); unlink_request(req); freeL("reply_state", rep); }
2545*4b22b933Srs200217 else if (send_result == t_complete) freeL("regservice_callback", rep);
2546*4b22b933Srs200217 else append_reply(req, rep);
2547*4b22b933Srs200217 }
2548*4b22b933Srs200217 }
2549*4b22b933Srs200217 if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
2550*4b22b933Srs200217 RecordUpdatedNiceLabel(m, 0); // Successfully got new name, tell user immediately
2551*4b22b933Srs200217 return;
2552*4b22b933Srs200217 }
2553*4b22b933Srs200217 else if (result == mStatus_MemFree)
2554*4b22b933Srs200217 {
2555*4b22b933Srs200217 if (instance->rename_on_memfree)
2556*4b22b933Srs200217 {
2557*4b22b933Srs200217 instance->rename_on_memfree = 0;
2558*4b22b933Srs200217 instance->name = gmDNS->nicelabel;
2559*4b22b933Srs200217 err = mDNS_RenameAndReregisterService(gmDNS, srs, &instance->name);
2560*4b22b933Srs200217 if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %ld", err);
2561*4b22b933Srs200217 // error should never happen - safest to log and continue
2562*4b22b933Srs200217 }
2563*4b22b933Srs200217 else
2564*4b22b933Srs200217 {
2565*4b22b933Srs200217 free_service_instance(instance);
2566*4b22b933Srs200217 return;
2567*4b22b933Srs200217 }
2568*4b22b933Srs200217 }
2569*4b22b933Srs200217 else if (result == mStatus_NameConflict)
2570*4b22b933Srs200217 {
2571*4b22b933Srs200217 if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
2572*4b22b933Srs200217 {
2573*4b22b933Srs200217 // On conflict for an autoname service, rename and reregister *all* autoname services
2574*4b22b933Srs200217 IncrementLabelSuffix(&m->nicelabel, mDNStrue);
2575*4b22b933Srs200217 m->MainCallback(m, mStatus_ConfigChanged);
2576*4b22b933Srs200217 }
2577*4b22b933Srs200217 else if (instance->autoname || instance->autorename)
2578*4b22b933Srs200217 {
2579*4b22b933Srs200217 mDNS_RenameAndReregisterService(gmDNS, srs, mDNSNULL);
2580*4b22b933Srs200217 return;
2581*4b22b933Srs200217 }
2582*4b22b933Srs200217 else
2583*4b22b933Srs200217 {
2584*4b22b933Srs200217 request_state *rs = instance->request;
2585*4b22b933Srs200217 if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
2586*4b22b933Srs200217 free_service_instance(instance);
2587*4b22b933Srs200217 if (!SuppressError && deliver_async_error(rs, reg_service_reply_op, result) < 0)
2588*4b22b933Srs200217 {
2589*4b22b933Srs200217 abort_request(rs);
2590*4b22b933Srs200217 unlink_request(rs);
2591*4b22b933Srs200217 }
2592*4b22b933Srs200217 return;
2593*4b22b933Srs200217 }
2594*4b22b933Srs200217 }
2595*4b22b933Srs200217 else
2596*4b22b933Srs200217 {
2597*4b22b933Srs200217 request_state *rs = instance->request;
2598*4b22b933Srs200217 if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
2599*4b22b933Srs200217 if (result != mStatus_NATTraversal) LogMsg("ERROR: unknown result in regservice_callback: %ld", result);
2600*4b22b933Srs200217 free_service_instance(instance);
2601*4b22b933Srs200217 if (!SuppressError && deliver_async_error(rs, reg_service_reply_op, result) < 0)
2602*4b22b933Srs200217 {
2603*4b22b933Srs200217 abort_request(rs);
2604*4b22b933Srs200217 unlink_request(rs);
2605*4b22b933Srs200217 }
2606*4b22b933Srs200217 return;
2607*4b22b933Srs200217 }
2608*4b22b933Srs200217 }
2609*4b22b933Srs200217
FreeExtraRR(mDNS * const m,AuthRecord * const rr,mStatus result)2610*4b22b933Srs200217 mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result)
2611*4b22b933Srs200217 {
2612*4b22b933Srs200217 ExtraResourceRecord *extra = (ExtraResourceRecord *)rr->RecordContext;
2613*4b22b933Srs200217 (void)m; //unused
2614*4b22b933Srs200217
2615*4b22b933Srs200217 if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; }
2616*4b22b933Srs200217
2617*4b22b933Srs200217 debugf("%##s: MemFree", rr->resrec.name->c);
2618*4b22b933Srs200217 if (rr->resrec.rdata != &rr->rdatastorage)
2619*4b22b933Srs200217 freeL("Extra RData", rr->resrec.rdata);
2620*4b22b933Srs200217 freeL("ExtraResourceRecord", extra);
2621*4b22b933Srs200217 }
2622*4b22b933Srs200217
add_record_to_service(request_state * rstate,service_instance * instance,uint16_t rrtype,uint16_t rdlen,char * rdata,uint32_t ttl)2623*4b22b933Srs200217 mDNSlocal mStatus add_record_to_service(request_state *rstate, service_instance *instance, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl)
2624*4b22b933Srs200217 {
2625*4b22b933Srs200217 ServiceRecordSet *srs = &instance->srs;
2626*4b22b933Srs200217 ExtraResourceRecord *extra;
2627*4b22b933Srs200217 mStatus result;
2628*4b22b933Srs200217 int size;
2629*4b22b933Srs200217
2630*4b22b933Srs200217 if (rdlen > sizeof(RDataBody)) size = rdlen;
2631*4b22b933Srs200217 else size = sizeof(RDataBody);
2632*4b22b933Srs200217
2633*4b22b933Srs200217 extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
2634*4b22b933Srs200217 if (!extra)
2635*4b22b933Srs200217 {
2636*4b22b933Srs200217 my_perror("ERROR: malloc");
2637*4b22b933Srs200217 return mStatus_NoMemoryErr;
2638*4b22b933Srs200217 }
2639*4b22b933Srs200217
2640*4b22b933Srs200217 bzero(extra, sizeof(ExtraResourceRecord)); // OK if oversized rdata not zero'd
2641*4b22b933Srs200217 extra->r.resrec.rrtype = rrtype;
2642*4b22b933Srs200217 extra->r.rdatastorage.MaxRDLength = (mDNSu16) size;
2643*4b22b933Srs200217 extra->r.resrec.rdlength = rdlen;
2644*4b22b933Srs200217 memcpy(&extra->r.rdatastorage.u.data, rdata, rdlen);
2645*4b22b933Srs200217
2646*4b22b933Srs200217 result = mDNS_AddRecordToService(gmDNS, srs , extra, &extra->r.rdatastorage, ttl);
2647*4b22b933Srs200217 if (result) { freeL("ExtraResourceRecord", extra); return result; }
2648*4b22b933Srs200217
2649*4b22b933Srs200217 extra->ClientID = rstate->hdr.reg_index;
2650*4b22b933Srs200217 return result;
2651*4b22b933Srs200217 }
2652*4b22b933Srs200217
handle_add_request(request_state * rstate)2653*4b22b933Srs200217 mDNSlocal mStatus handle_add_request(request_state *rstate)
2654*4b22b933Srs200217 {
2655*4b22b933Srs200217 uint32_t ttl;
2656*4b22b933Srs200217 uint16_t rrtype, rdlen;
2657*4b22b933Srs200217 char *ptr, *rdata;
2658*4b22b933Srs200217 mStatus result = mStatus_UnknownErr;
2659*4b22b933Srs200217 DNSServiceFlags flags;
2660*4b22b933Srs200217 service_info *srvinfo = rstate->service_registration;
2661*4b22b933Srs200217 service_instance *i;
2662*4b22b933Srs200217
2663*4b22b933Srs200217 if (!srvinfo) { LogMsg("handle_add_request called with NULL service_registration"); return(-1); }
2664*4b22b933Srs200217
2665*4b22b933Srs200217 ptr = rstate->msgdata;
2666*4b22b933Srs200217 flags = get_flags(&ptr);
2667*4b22b933Srs200217 rrtype = get_short(&ptr);
2668*4b22b933Srs200217 rdlen = get_short(&ptr);
2669*4b22b933Srs200217 rdata = get_rdata(&ptr, rdlen);
2670*4b22b933Srs200217 ttl = get_long(&ptr);
2671*4b22b933Srs200217
2672*4b22b933Srs200217 if (!ttl) ttl = DefaultTTLforRRType(rrtype);
2673*4b22b933Srs200217
2674*4b22b933Srs200217 LogOperation("%3d: DNSServiceAddRecord(%##s, %s)", rstate->sd,
2675*4b22b933Srs200217 (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype));
2676*4b22b933Srs200217
2677*4b22b933Srs200217 for (i = srvinfo->instances; i; i = i->next)
2678*4b22b933Srs200217 {
2679*4b22b933Srs200217 result = add_record_to_service(rstate, i, rrtype, rdlen, rdata, ttl);
2680*4b22b933Srs200217 if (result && i->default_local) break;
2681*4b22b933Srs200217 else result = mStatus_NoError; // suppress non-local default errors
2682*4b22b933Srs200217 }
2683*4b22b933Srs200217
2684*4b22b933Srs200217 return(result);
2685*4b22b933Srs200217 }
2686*4b22b933Srs200217
update_record(AuthRecord * rr,uint16_t rdlen,char * rdata,uint32_t ttl)2687*4b22b933Srs200217 mDNSlocal mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32_t ttl)
2688*4b22b933Srs200217 {
2689*4b22b933Srs200217 int rdsize;
2690*4b22b933Srs200217 RData *newrd;
2691*4b22b933Srs200217 mStatus result;
2692*4b22b933Srs200217
2693*4b22b933Srs200217 if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
2694*4b22b933Srs200217 else rdsize = sizeof(RDataBody);
2695*4b22b933Srs200217 newrd = mallocL("handle_update_request", sizeof(RData) - sizeof(RDataBody) + rdsize);
2696*4b22b933Srs200217 if (!newrd) FatalError("ERROR: malloc");
2697*4b22b933Srs200217 newrd->MaxRDLength = (mDNSu16) rdsize;
2698*4b22b933Srs200217 memcpy(&newrd->u, rdata, rdlen);
2699*4b22b933Srs200217
2700*4b22b933Srs200217 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2701*4b22b933Srs200217 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2702*4b22b933Srs200217 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2703*4b22b933Srs200217 if (rr->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; }
2704*4b22b933Srs200217
2705*4b22b933Srs200217 result = mDNS_Update(gmDNS, rr, ttl, rdlen, newrd, update_callback);
2706*4b22b933Srs200217 if (result) { LogMsg("ERROR: mDNS_Update - %ld", result); freeL("handle_update_request", newrd); }
2707*4b22b933Srs200217 return result;
2708*4b22b933Srs200217 }
2709*4b22b933Srs200217
handle_update_request(request_state * rstate)2710*4b22b933Srs200217 mDNSlocal mStatus handle_update_request(request_state *rstate)
2711*4b22b933Srs200217 {
2712*4b22b933Srs200217 uint16_t rdlen;
2713*4b22b933Srs200217 char *ptr, *rdata;
2714*4b22b933Srs200217 uint32_t ttl;
2715*4b22b933Srs200217 mStatus result = mStatus_BadReferenceErr;
2716*4b22b933Srs200217 service_info *srvinfo = rstate->service_registration;
2717*4b22b933Srs200217 service_instance *i;
2718*4b22b933Srs200217 AuthRecord *rr = NULL;
2719*4b22b933Srs200217
2720*4b22b933Srs200217 // get the message data
2721*4b22b933Srs200217 ptr = rstate->msgdata;
2722*4b22b933Srs200217 get_flags(&ptr); // flags unused
2723*4b22b933Srs200217 rdlen = get_short(&ptr);
2724*4b22b933Srs200217 rdata = get_rdata(&ptr, rdlen);
2725*4b22b933Srs200217 ttl = get_long(&ptr);
2726*4b22b933Srs200217
2727*4b22b933Srs200217 if (rstate->reg_recs)
2728*4b22b933Srs200217 {
2729*4b22b933Srs200217 // update an individually registered record
2730*4b22b933Srs200217 registered_record_entry *reptr;
2731*4b22b933Srs200217 for (reptr = rstate->reg_recs; reptr; reptr = reptr->next)
2732*4b22b933Srs200217 {
2733*4b22b933Srs200217 if (reptr->key == rstate->hdr.reg_index)
2734*4b22b933Srs200217 {
2735*4b22b933Srs200217 result = update_record(reptr->rr, rdlen, rdata, ttl);
2736*4b22b933Srs200217 goto end;
2737*4b22b933Srs200217 }
2738*4b22b933Srs200217 }
2739*4b22b933Srs200217 result = mStatus_BadReferenceErr;
2740*4b22b933Srs200217 goto end;
2741*4b22b933Srs200217 }
2742*4b22b933Srs200217
2743*4b22b933Srs200217 // update a record from a service record set
2744*4b22b933Srs200217 if (!srvinfo) { result = mStatus_BadReferenceErr; goto end; }
2745*4b22b933Srs200217 for (i = srvinfo->instances; i; i = i->next)
2746*4b22b933Srs200217 {
2747*4b22b933Srs200217 if (rstate->hdr.reg_index == TXT_RECORD_INDEX) rr = &i->srs.RR_TXT;
2748*4b22b933Srs200217 else
2749*4b22b933Srs200217 {
2750*4b22b933Srs200217 ExtraResourceRecord *e;
2751*4b22b933Srs200217 for (e = i->srs.Extras; e; e = e->next)
2752*4b22b933Srs200217 if (e->ClientID == rstate->hdr.reg_index) { rr = &e->r; break; }
2753*4b22b933Srs200217 }
2754*4b22b933Srs200217
2755*4b22b933Srs200217 if (!rr) { result = mStatus_BadReferenceErr; goto end; }
2756*4b22b933Srs200217 result = update_record(rr, rdlen, rdata, ttl);
2757*4b22b933Srs200217 if (result && i->default_local) goto end;
2758*4b22b933Srs200217 else result = mStatus_NoError; // suppress non-local default errors
2759*4b22b933Srs200217 }
2760*4b22b933Srs200217
2761*4b22b933Srs200217 end:
2762*4b22b933Srs200217 LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", rstate->sd,
2763*4b22b933Srs200217 (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL,
2764*4b22b933Srs200217 rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>");
2765*4b22b933Srs200217
2766*4b22b933Srs200217 return(result);
2767*4b22b933Srs200217 }
2768*4b22b933Srs200217
update_callback(mDNS * const m,AuthRecord * const rr,RData * oldrd)2769*4b22b933Srs200217 mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
2770*4b22b933Srs200217 {
2771*4b22b933Srs200217 (void)m; // Unused
2772*4b22b933Srs200217 if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd);
2773*4b22b933Srs200217 }
2774*4b22b933Srs200217
free_service_instance(service_instance * srv)2775*4b22b933Srs200217 mDNSlocal void free_service_instance(service_instance *srv)
2776*4b22b933Srs200217 {
2777*4b22b933Srs200217 request_state *rstate = srv->request;
2778*4b22b933Srs200217 ExtraResourceRecord *e = srv->srs.Extras, *tmp;
2779*4b22b933Srs200217
2780*4b22b933Srs200217 // clear pointers from parent struct
2781*4b22b933Srs200217 if (rstate)
2782*4b22b933Srs200217 {
2783*4b22b933Srs200217 service_instance *ptr = rstate->service_registration->instances, *prev = NULL;
2784*4b22b933Srs200217 while (ptr)
2785*4b22b933Srs200217 {
2786*4b22b933Srs200217 if (ptr == srv)
2787*4b22b933Srs200217 {
2788*4b22b933Srs200217 if (prev) prev->next = ptr->next;
2789*4b22b933Srs200217 else rstate->service_registration->instances = ptr->next;
2790*4b22b933Srs200217 break;
2791*4b22b933Srs200217 }
2792*4b22b933Srs200217 prev = ptr;
2793*4b22b933Srs200217 ptr = ptr->next;
2794*4b22b933Srs200217 }
2795*4b22b933Srs200217 }
2796*4b22b933Srs200217
2797*4b22b933Srs200217 while(e)
2798*4b22b933Srs200217 {
2799*4b22b933Srs200217 e->r.RecordContext = e;
2800*4b22b933Srs200217 tmp = e;
2801*4b22b933Srs200217 e = e->next;
2802*4b22b933Srs200217 FreeExtraRR(gmDNS, &tmp->r, mStatus_MemFree);
2803*4b22b933Srs200217 }
2804*4b22b933Srs200217
2805*4b22b933Srs200217 if (srv->subtypes) { freeL("regservice_callback", srv->subtypes); srv->subtypes = NULL; }
2806*4b22b933Srs200217 freeL("regservice_callback", srv);
2807*4b22b933Srs200217 }
2808*4b22b933Srs200217
regservice_termination_callback(void * context)2809*4b22b933Srs200217 mDNSlocal void regservice_termination_callback(void *context)
2810*4b22b933Srs200217 {
2811*4b22b933Srs200217 service_info *info = context;
2812*4b22b933Srs200217 service_instance *i, *p;
2813*4b22b933Srs200217 if (!info) { LogMsg("regservice_termination_callback context is NULL"); return; }
2814*4b22b933Srs200217 if (!info->request) { LogMsg("regservice_termination_callback info->request is NULL"); return; }
2815*4b22b933Srs200217 i = info->instances;
2816*4b22b933Srs200217 while (i)
2817*4b22b933Srs200217 {
2818*4b22b933Srs200217 p = i;
2819*4b22b933Srs200217 i = i->next;
2820*4b22b933Srs200217 p->request = NULL; // clear back pointer
2821*4b22b933Srs200217 // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
2822*4b22b933Srs200217 LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP", info->request->sd, p->srs.RR_SRV.resrec.name->c, mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port));
2823*4b22b933Srs200217 if (mDNS_DeregisterService(gmDNS, &p->srs)) free_service_instance(p);
2824*4b22b933Srs200217 }
2825*4b22b933Srs200217 info->request->service_registration = NULL; // clear pointer from request back to info
2826*4b22b933Srs200217 if (info->txtdata) { freeL("txtdata", info->txtdata); info->txtdata = NULL; }
2827*4b22b933Srs200217 freeL("service_info", info);
2828*4b22b933Srs200217 }
2829*4b22b933Srs200217
handle_regrecord_request(request_state * rstate)2830*4b22b933Srs200217 mDNSlocal mStatus handle_regrecord_request(request_state *rstate)
2831*4b22b933Srs200217 {
2832*4b22b933Srs200217 AuthRecord *rr;
2833*4b22b933Srs200217 registered_record_entry *re;
2834*4b22b933Srs200217 mStatus result;
2835*4b22b933Srs200217
2836*4b22b933Srs200217 if (rstate->ts != t_complete)
2837*4b22b933Srs200217 {
2838*4b22b933Srs200217 LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
2839*4b22b933Srs200217 abort_request(rstate);
2840*4b22b933Srs200217 unlink_request(rstate);
2841*4b22b933Srs200217 return(-1);
2842*4b22b933Srs200217 }
2843*4b22b933Srs200217
2844*4b22b933Srs200217 rr = read_rr_from_ipc_msg(rstate->msgdata, 1, 1);
2845*4b22b933Srs200217 if (!rr) return(mStatus_BadParamErr);
2846*4b22b933Srs200217
2847*4b22b933Srs200217 // allocate registration entry, link into list
2848*4b22b933Srs200217 re = mallocL("handle_regrecord_request", sizeof(registered_record_entry));
2849*4b22b933Srs200217 if (!re) FatalError("ERROR: malloc");
2850*4b22b933Srs200217 re->key = rstate->hdr.reg_index;
2851*4b22b933Srs200217 re->rr = rr;
2852*4b22b933Srs200217 re->rstate = rstate;
2853*4b22b933Srs200217 re->client_context = rstate->hdr.client_context;
2854*4b22b933Srs200217 rr->RecordContext = re;
2855*4b22b933Srs200217 rr->RecordCallback = regrecord_callback;
2856*4b22b933Srs200217 re->next = rstate->reg_recs;
2857*4b22b933Srs200217 rstate->reg_recs = re;
2858*4b22b933Srs200217
2859*4b22b933Srs200217 if (!rstate->terminate)
2860*4b22b933Srs200217 {
2861*4b22b933Srs200217 rstate->terminate = connected_registration_termination;
2862*4b22b933Srs200217 rstate->termination_context = rstate;
2863*4b22b933Srs200217 }
2864*4b22b933Srs200217
2865*4b22b933Srs200217 if (rr->resrec.rroriginalttl == 0)
2866*4b22b933Srs200217 rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
2867*4b22b933Srs200217
2868*4b22b933Srs200217 LogOperation("%3d: DNSServiceRegisterRecord %s", rstate->sd, RRDisplayString(gmDNS, &rr->resrec));
2869*4b22b933Srs200217 result = mDNS_Register(gmDNS, rr);
2870*4b22b933Srs200217 return(result);
2871*4b22b933Srs200217 }
2872*4b22b933Srs200217
regrecord_callback(mDNS * const m,AuthRecord * rr,mStatus result)2873*4b22b933Srs200217 mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result)
2874*4b22b933Srs200217 {
2875*4b22b933Srs200217 registered_record_entry *re = rr->RecordContext;
2876*4b22b933Srs200217 request_state *rstate = re ? re->rstate : NULL;
2877*4b22b933Srs200217 int len;
2878*4b22b933Srs200217 reply_state *reply;
2879*4b22b933Srs200217 transfer_state ts;
2880*4b22b933Srs200217 (void)m; // Unused
2881*4b22b933Srs200217
2882*4b22b933Srs200217 if (!re)
2883*4b22b933Srs200217 {
2884*4b22b933Srs200217 // parent struct alreadt freed by termination callback
2885*4b22b933Srs200217 if (!result) LogMsg("Error: regrecord_callback: successful registration of orphaned record");
2886*4b22b933Srs200217 else
2887*4b22b933Srs200217 {
2888*4b22b933Srs200217 if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
2889*4b22b933Srs200217 freeL("regrecord_callback", rr);
2890*4b22b933Srs200217 }
2891*4b22b933Srs200217 return;
2892*4b22b933Srs200217 }
2893*4b22b933Srs200217
2894*4b22b933Srs200217 // format result, add to the list for the request, including the client context in the header
2895*4b22b933Srs200217 len = sizeof(DNSServiceFlags);
2896*4b22b933Srs200217 len += sizeof(uint32_t); //interfaceIndex
2897*4b22b933Srs200217 len += sizeof(DNSServiceErrorType);
2898*4b22b933Srs200217
2899*4b22b933Srs200217 reply = create_reply(reg_record_reply_op, len, rstate);
2900*4b22b933Srs200217 reply->mhdr->client_context = re->client_context;
2901*4b22b933Srs200217 reply->rhdr->flags = dnssd_htonl(0);
2902*4b22b933Srs200217 reply->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID));
2903*4b22b933Srs200217 reply->rhdr->error = dnssd_htonl(result);
2904*4b22b933Srs200217
2905*4b22b933Srs200217 if (result)
2906*4b22b933Srs200217 {
2907*4b22b933Srs200217 // unlink from list, free memory
2908*4b22b933Srs200217 registered_record_entry **ptr = &re->rstate->reg_recs;
2909*4b22b933Srs200217 while (*ptr && (*ptr) != re) ptr = &(*ptr)->next;
2910*4b22b933Srs200217 if (!*ptr) { LogMsg("regrecord_callback - record not in list!"); return; }
2911*4b22b933Srs200217 *ptr = (*ptr)->next;
2912*4b22b933Srs200217 freeL("regrecord_callback", re->rr);
2913*4b22b933Srs200217 re->rr = rr = NULL;
2914*4b22b933Srs200217 freeL("regrecord_callback", re);
2915*4b22b933Srs200217 re = NULL;
2916*4b22b933Srs200217 }
2917*4b22b933Srs200217
2918*4b22b933Srs200217 ts = send_msg(reply);
2919*4b22b933Srs200217
2920*4b22b933Srs200217 if (ts == t_error || ts == t_terminated) { abort_request(rstate); unlink_request(rstate); }
2921*4b22b933Srs200217 else if (ts == t_complete) freeL("regrecord_callback", reply);
2922*4b22b933Srs200217 else if (ts == t_morecoming) append_reply(rstate, reply); // client is blocked, link reply into list
2923*4b22b933Srs200217 }
2924*4b22b933Srs200217
connected_registration_termination(void * context)2925*4b22b933Srs200217 mDNSlocal void connected_registration_termination(void *context)
2926*4b22b933Srs200217 {
2927*4b22b933Srs200217 int shared;
2928*4b22b933Srs200217 registered_record_entry *fptr, *ptr = ((request_state *)context)->reg_recs;
2929*4b22b933Srs200217 while(ptr)
2930*4b22b933Srs200217 {
2931*4b22b933Srs200217 fptr = ptr;
2932*4b22b933Srs200217 ptr = ptr->next;
2933*4b22b933Srs200217 shared = fptr->rr->resrec.RecordType == kDNSRecordTypeShared;
2934*4b22b933Srs200217 fptr->rr->RecordContext = NULL;
2935*4b22b933Srs200217 mDNS_Deregister(gmDNS, fptr->rr);
2936*4b22b933Srs200217 freeL("connected_registration_termination", fptr);
2937*4b22b933Srs200217 }
2938*4b22b933Srs200217 }
2939*4b22b933Srs200217
handle_removerecord_request(request_state * rstate)2940*4b22b933Srs200217 mDNSlocal mStatus handle_removerecord_request(request_state *rstate)
2941*4b22b933Srs200217 {
2942*4b22b933Srs200217 mStatus err = mStatus_BadReferenceErr;
2943*4b22b933Srs200217 char *ptr;
2944*4b22b933Srs200217 service_info *srvinfo = rstate->service_registration;
2945*4b22b933Srs200217
2946*4b22b933Srs200217 ptr = rstate->msgdata;
2947*4b22b933Srs200217 get_flags(&ptr); // flags unused
2948*4b22b933Srs200217
2949*4b22b933Srs200217 if (rstate->reg_recs) err = remove_record(rstate); // remove individually registered record
2950*4b22b933Srs200217 else if (!srvinfo) LogOperation("%3d: DNSServiceRemoveRecord (bad ref)", rstate->sd);
2951*4b22b933Srs200217 else
2952*4b22b933Srs200217 {
2953*4b22b933Srs200217 service_instance *i;
2954*4b22b933Srs200217 LogOperation("%3d: DNSServiceRemoveRecord(%##s)", rstate->sd,
2955*4b22b933Srs200217 (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL);
2956*4b22b933Srs200217 for (i = srvinfo->instances; i; i = i->next)
2957*4b22b933Srs200217 {
2958*4b22b933Srs200217 err = remove_extra(rstate, i);
2959*4b22b933Srs200217 if (err && i->default_local) break;
2960*4b22b933Srs200217 else err = mStatus_NoError; // suppress non-local default errors
2961*4b22b933Srs200217 }
2962*4b22b933Srs200217 }
2963*4b22b933Srs200217
2964*4b22b933Srs200217 return(err);
2965*4b22b933Srs200217 }
2966*4b22b933Srs200217
2967*4b22b933Srs200217 // remove a resource record registered via DNSServiceRegisterRecord()
remove_record(request_state * rstate)2968*4b22b933Srs200217 mDNSlocal mStatus remove_record(request_state *rstate)
2969*4b22b933Srs200217 {
2970*4b22b933Srs200217 int shared;
2971*4b22b933Srs200217 mStatus err = mStatus_UnknownErr;
2972*4b22b933Srs200217 registered_record_entry *e, **ptr = &rstate->reg_recs;
2973*4b22b933Srs200217
2974*4b22b933Srs200217 while(*ptr && (*ptr)->key != rstate->hdr.reg_index) ptr = &(*ptr)->next;
2975*4b22b933Srs200217 if (!*ptr) { LogMsg("DNSServiceRemoveRecord - bad reference"); return mStatus_BadReferenceErr; }
2976*4b22b933Srs200217 e = *ptr;
2977*4b22b933Srs200217 *ptr = e->next; // unlink
2978*4b22b933Srs200217
2979*4b22b933Srs200217 LogOperation("%3d: DNSServiceRemoveRecord(%#s)", rstate->sd, e->rr->resrec.name->c);
2980*4b22b933Srs200217 shared = e->rr->resrec.RecordType == kDNSRecordTypeShared;
2981*4b22b933Srs200217 e->rr->RecordContext = NULL;
2982*4b22b933Srs200217 err = mDNS_Deregister(gmDNS, e->rr);
2983*4b22b933Srs200217 if (err)
2984*4b22b933Srs200217 {
2985*4b22b933Srs200217 LogMsg("ERROR: remove_record, mDNS_Deregister: %ld", err);
2986*4b22b933Srs200217 freeL("remove_record", e->rr);
2987*4b22b933Srs200217 freeL("remove_record", e);
2988*4b22b933Srs200217 }
2989*4b22b933Srs200217 return err;
2990*4b22b933Srs200217 }
2991*4b22b933Srs200217
remove_extra(request_state * rstate,service_instance * serv)2992*4b22b933Srs200217 mDNSlocal mStatus remove_extra(request_state *rstate, service_instance *serv)
2993*4b22b933Srs200217 {
2994*4b22b933Srs200217 mStatus err = mStatus_BadReferenceErr;
2995*4b22b933Srs200217 ExtraResourceRecord *ptr;
2996*4b22b933Srs200217
2997*4b22b933Srs200217 for (ptr = serv->srs.Extras; ptr; ptr = ptr->next)
2998*4b22b933Srs200217 {
2999*4b22b933Srs200217 if (ptr->ClientID == rstate->hdr.reg_index) // found match
3000*4b22b933Srs200217 return mDNS_RemoveRecordFromService(gmDNS, &serv->srs, ptr, FreeExtraRR, ptr);
3001*4b22b933Srs200217 }
3002*4b22b933Srs200217 return err;
3003*4b22b933Srs200217 }
3004*4b22b933Srs200217
3005*4b22b933Srs200217 // domain enumeration
handle_enum_request(request_state * rstate)3006*4b22b933Srs200217 mDNSlocal void handle_enum_request(request_state *rstate)
3007*4b22b933Srs200217 {
3008*4b22b933Srs200217 DNSServiceFlags flags;
3009*4b22b933Srs200217 uint32_t ifi;
3010*4b22b933Srs200217 mDNSInterfaceID InterfaceID;
3011*4b22b933Srs200217 char *ptr = rstate->msgdata;
3012*4b22b933Srs200217 domain_enum_t *def, *all;
3013*4b22b933Srs200217 enum_termination_t *term;
3014*4b22b933Srs200217 mStatus err;
3015*4b22b933Srs200217 int result;
3016*4b22b933Srs200217
3017*4b22b933Srs200217 if (rstate->ts != t_complete)
3018*4b22b933Srs200217 {
3019*4b22b933Srs200217 LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
3020*4b22b933Srs200217 abort_request(rstate);
3021*4b22b933Srs200217 unlink_request(rstate);
3022*4b22b933Srs200217 return;
3023*4b22b933Srs200217 }
3024*4b22b933Srs200217
3025*4b22b933Srs200217 flags = get_flags(&ptr);
3026*4b22b933Srs200217 ifi = get_long(&ptr);
3027*4b22b933Srs200217 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
3028*4b22b933Srs200217 if (ifi && !InterfaceID)
3029*4b22b933Srs200217 {
3030*4b22b933Srs200217 deliver_error(rstate, mStatus_BadParamErr);
3031*4b22b933Srs200217 abort_request(rstate);
3032*4b22b933Srs200217 unlink_request(rstate);
3033*4b22b933Srs200217 return;
3034*4b22b933Srs200217 }
3035*4b22b933Srs200217
3036*4b22b933Srs200217 // allocate context structures
3037*4b22b933Srs200217 def = mallocL("handle_enum_request", sizeof(domain_enum_t));
3038*4b22b933Srs200217 all = mallocL("handle_enum_request", sizeof(domain_enum_t));
3039*4b22b933Srs200217 term = mallocL("handle_enum_request", sizeof(enum_termination_t));
3040*4b22b933Srs200217 if (!def || !all || !term) FatalError("ERROR: malloc");
3041*4b22b933Srs200217
3042*4b22b933Srs200217 #if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
3043*4b22b933Srs200217 dDNS_RegisterSearchDomains( gmDNS );
3044*4b22b933Srs200217 #endif
3045*4b22b933Srs200217
3046*4b22b933Srs200217 // enumeration requires multiple questions, so we must link all the context pointers so that
3047*4b22b933Srs200217 // necessary context can be reached from the callbacks
3048*4b22b933Srs200217 def->rstate = rstate;
3049*4b22b933Srs200217 all->rstate = rstate;
3050*4b22b933Srs200217 term->def = def;
3051*4b22b933Srs200217 term->all = all;
3052*4b22b933Srs200217 term->rstate = rstate;
3053*4b22b933Srs200217 rstate->termination_context = term;
3054*4b22b933Srs200217 rstate->terminate = enum_termination_callback;
3055*4b22b933Srs200217 def->question.QuestionContext = def;
3056*4b22b933Srs200217 def->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
3057*4b22b933Srs200217 mDNS_DomainTypeRegistrationDefault: mDNS_DomainTypeBrowseDefault;
3058*4b22b933Srs200217 all->question.QuestionContext = all;
3059*4b22b933Srs200217 all->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
3060*4b22b933Srs200217 mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
3061*4b22b933Srs200217
3062*4b22b933Srs200217 // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
3063*4b22b933Srs200217 if (!InterfaceID) InterfaceID = mDNSInterface_LocalOnly;
3064*4b22b933Srs200217
3065*4b22b933Srs200217 // make the calls
3066*4b22b933Srs200217 LogOperation("%3d: DNSServiceEnumerateDomains(%X=%s)", rstate->sd, flags,
3067*4b22b933Srs200217 (flags & kDNSServiceFlagsBrowseDomains ) ? "kDNSServiceFlagsBrowseDomains" :
3068*4b22b933Srs200217 (flags & kDNSServiceFlagsRegistrationDomains) ? "kDNSServiceFlagsRegistrationDomains" : "<<Unknown>>");
3069*4b22b933Srs200217 err = mDNS_GetDomains(gmDNS, &all->question, all->type, NULL, InterfaceID, enum_result_callback, all);
3070*4b22b933Srs200217 if (err == mStatus_NoError)
3071*4b22b933Srs200217 err = mDNS_GetDomains(gmDNS, &def->question, def->type, NULL, InterfaceID, enum_result_callback, def);
3072*4b22b933Srs200217 result = deliver_error(rstate, err); // send error *before* returning local domain
3073*4b22b933Srs200217
3074*4b22b933Srs200217 if (result < 0 || err)
3075*4b22b933Srs200217 {
3076*4b22b933Srs200217 abort_request(rstate);
3077*4b22b933Srs200217 unlink_request(rstate);
3078*4b22b933Srs200217 return;
3079*4b22b933Srs200217 }
3080*4b22b933Srs200217 }
3081*4b22b933Srs200217
enum_result_callback(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,mDNSBool AddRecord)3082*4b22b933Srs200217 mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
3083*4b22b933Srs200217 {
3084*4b22b933Srs200217 char domain[MAX_ESCAPED_DOMAIN_NAME];
3085*4b22b933Srs200217 domain_enum_t *de = question->QuestionContext;
3086*4b22b933Srs200217 DNSServiceFlags flags = 0;
3087*4b22b933Srs200217 reply_state *reply;
3088*4b22b933Srs200217 (void)m; // Unused
3089*4b22b933Srs200217
3090*4b22b933Srs200217 if (answer->rrtype != kDNSType_PTR) return;
3091*4b22b933Srs200217 if (!AddRecord && de->type != mDNS_DomainTypeBrowse) return;
3092*4b22b933Srs200217
3093*4b22b933Srs200217 if (AddRecord)
3094*4b22b933Srs200217 {
3095*4b22b933Srs200217 flags |= kDNSServiceFlagsAdd;
3096*4b22b933Srs200217 if (de->type == mDNS_DomainTypeRegistrationDefault || de->type == mDNS_DomainTypeBrowseDefault)
3097*4b22b933Srs200217 flags |= kDNSServiceFlagsDefault;
3098*4b22b933Srs200217 }
3099*4b22b933Srs200217 ConvertDomainNameToCString(&answer->rdata->u.name, domain);
3100*4b22b933Srs200217 // note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
3101*4b22b933Srs200217 // a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
3102*4b22b933Srs200217 // network, so we just pass kDNSServiceInterfaceIndexAny
3103*4b22b933Srs200217 reply = format_enumeration_reply(de->rstate, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError);
3104*4b22b933Srs200217 if (!reply)
3105*4b22b933Srs200217 {
3106*4b22b933Srs200217 LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
3107*4b22b933Srs200217 return;
3108*4b22b933Srs200217 }
3109*4b22b933Srs200217 reply->next = NULL;
3110*4b22b933Srs200217 append_reply(de->rstate, reply);
3111*4b22b933Srs200217 return;
3112*4b22b933Srs200217 }
3113*4b22b933Srs200217
format_enumeration_reply(request_state * rstate,const char * domain,DNSServiceFlags flags,uint32_t ifi,DNSServiceErrorType err)3114*4b22b933Srs200217 mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
3115*4b22b933Srs200217 {
3116*4b22b933Srs200217 size_t len;
3117*4b22b933Srs200217 reply_state *reply;
3118*4b22b933Srs200217 char *data;
3119*4b22b933Srs200217
3120*4b22b933Srs200217 len = sizeof(DNSServiceFlags);
3121*4b22b933Srs200217 len += sizeof(uint32_t);
3122*4b22b933Srs200217 len += sizeof(DNSServiceErrorType);
3123*4b22b933Srs200217 len += strlen(domain) + 1;
3124*4b22b933Srs200217
3125*4b22b933Srs200217 reply = create_reply(enumeration_reply_op, len, rstate);
3126*4b22b933Srs200217 reply->rhdr->flags = dnssd_htonl(flags);
3127*4b22b933Srs200217 reply->rhdr->ifi = dnssd_htonl(ifi);
3128*4b22b933Srs200217 reply->rhdr->error = dnssd_htonl(err);
3129*4b22b933Srs200217 data = reply->sdata;
3130*4b22b933Srs200217 put_string(domain, &data);
3131*4b22b933Srs200217 return reply;
3132*4b22b933Srs200217 }
3133*4b22b933Srs200217
enum_termination_callback(void * context)3134*4b22b933Srs200217 mDNSlocal void enum_termination_callback(void *context)
3135*4b22b933Srs200217 {
3136*4b22b933Srs200217 enum_termination_t *t = context;
3137*4b22b933Srs200217 mDNS *coredata = gmDNS;
3138*4b22b933Srs200217
3139*4b22b933Srs200217 mDNS_StopGetDomains(coredata, &t->all->question);
3140*4b22b933Srs200217 mDNS_StopGetDomains(coredata, &t->def->question);
3141*4b22b933Srs200217 freeL("enum_termination_callback", t->all);
3142*4b22b933Srs200217 freeL("enum_termination_callback", t->def);
3143*4b22b933Srs200217 t->rstate->termination_context = NULL;
3144*4b22b933Srs200217 freeL("enum_termination_callback", t);
3145*4b22b933Srs200217 }
3146*4b22b933Srs200217
handle_reconfirm_request(request_state * rstate)3147*4b22b933Srs200217 mDNSlocal void handle_reconfirm_request(request_state *rstate)
3148*4b22b933Srs200217 {
3149*4b22b933Srs200217 AuthRecord *rr = read_rr_from_ipc_msg(rstate->msgdata, 0, 0);
3150*4b22b933Srs200217 if (rr)
3151*4b22b933Srs200217 {
3152*4b22b933Srs200217 mStatus status = mDNS_ReconfirmByValue(gmDNS, &rr->resrec);
3153*4b22b933Srs200217 LogOperation(
3154*4b22b933Srs200217 (status == mStatus_NoError) ?
3155*4b22b933Srs200217 "%3d: DNSServiceReconfirmRecord(%s) interface %d initiated" :
3156*4b22b933Srs200217 "%3d: DNSServiceReconfirmRecord(%s) interface %d failed: %d",
3157*4b22b933Srs200217 rstate->sd, RRDisplayString(gmDNS, &rr->resrec),
3158*4b22b933Srs200217 mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID), status);
3159*4b22b933Srs200217 status = 0; // Adding this line eliminates a build failure when building mDNSPosix on Tiger
3160*4b22b933Srs200217 }
3161*4b22b933Srs200217 abort_request(rstate);
3162*4b22b933Srs200217 unlink_request(rstate);
3163*4b22b933Srs200217 freeL("handle_reconfirm_request", rr);
3164*4b22b933Srs200217 }
3165*4b22b933Srs200217
3166*4b22b933Srs200217 // setup rstate to accept new reg/dereg requests
reset_connected_rstate(request_state * rstate)3167*4b22b933Srs200217 mDNSlocal void reset_connected_rstate(request_state *rstate)
3168*4b22b933Srs200217 {
3169*4b22b933Srs200217 rstate->ts = t_morecoming;
3170*4b22b933Srs200217 rstate->hdr_bytes = 0;
3171*4b22b933Srs200217 rstate->data_bytes = 0;
3172*4b22b933Srs200217 if (rstate->msgbuf) freeL("reset_connected_rstate", rstate->msgbuf);
3173*4b22b933Srs200217 rstate->msgbuf = NULL;
3174*4b22b933Srs200217 rstate->bufsize = 0;
3175*4b22b933Srs200217 }
3176*4b22b933Srs200217
3177*4b22b933Srs200217 // returns a resource record (allocated w/ malloc) containing the data found in an IPC message
3178*4b22b933Srs200217 // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
3179*4b22b933Srs200217 // (ttl only extracted/set if ttl argument is non-zero). returns NULL for a bad-parameter error
read_rr_from_ipc_msg(char * msgbuf,int GetTTL,int validate_flags)3180*4b22b933Srs200217 mDNSlocal AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_flags)
3181*4b22b933Srs200217 {
3182*4b22b933Srs200217 char *rdata, name[256];
3183*4b22b933Srs200217 AuthRecord *rr;
3184*4b22b933Srs200217 DNSServiceFlags flags;
3185*4b22b933Srs200217 uint32_t interfaceIndex;
3186*4b22b933Srs200217 uint16_t type, class, rdlen;
3187*4b22b933Srs200217 int storage_size;
3188*4b22b933Srs200217
3189*4b22b933Srs200217 flags = get_flags(&msgbuf);
3190*4b22b933Srs200217 if (validate_flags &&
3191*4b22b933Srs200217 !((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
3192*4b22b933Srs200217 !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique))
3193*4b22b933Srs200217 {
3194*4b22b933Srs200217 LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
3195*4b22b933Srs200217 return NULL;
3196*4b22b933Srs200217 }
3197*4b22b933Srs200217
3198*4b22b933Srs200217 interfaceIndex = get_long(&msgbuf);
3199*4b22b933Srs200217 if (get_string(&msgbuf, name, 256) < 0)
3200*4b22b933Srs200217 {
3201*4b22b933Srs200217 LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
3202*4b22b933Srs200217 return NULL;
3203*4b22b933Srs200217 }
3204*4b22b933Srs200217 type = get_short(&msgbuf);
3205*4b22b933Srs200217 class = get_short(&msgbuf);
3206*4b22b933Srs200217 rdlen = get_short(&msgbuf);
3207*4b22b933Srs200217
3208*4b22b933Srs200217 if (rdlen > sizeof(RDataBody)) storage_size = rdlen;
3209*4b22b933Srs200217 else storage_size = sizeof(RDataBody);
3210*4b22b933Srs200217
3211*4b22b933Srs200217 rr = mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
3212*4b22b933Srs200217 if (!rr) FatalError("ERROR: malloc");
3213*4b22b933Srs200217 bzero(rr, sizeof(AuthRecord)); // ok if oversized rdata not zero'd
3214*4b22b933Srs200217
3215*4b22b933Srs200217 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex),
3216*4b22b933Srs200217 type, 0, (mDNSu8) ((flags & kDNSServiceFlagsShared) ? kDNSRecordTypeShared : kDNSRecordTypeUnique), mDNSNULL, mDNSNULL);
3217*4b22b933Srs200217
3218*4b22b933Srs200217 if (!MakeDomainNameFromDNSNameString(rr->resrec.name, name))
3219*4b22b933Srs200217 {
3220*4b22b933Srs200217 LogMsg("ERROR: bad name: %s", name);
3221*4b22b933Srs200217 freeL("read_rr_from_ipc_msg", rr);
3222*4b22b933Srs200217 return NULL;
3223*4b22b933Srs200217 }
3224*4b22b933Srs200217
3225*4b22b933Srs200217 if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery = mDNStrue;
3226*4b22b933Srs200217 rr->resrec.rrclass = class;
3227*4b22b933Srs200217 rr->resrec.rdlength = rdlen;
3228*4b22b933Srs200217 rr->resrec.rdata->MaxRDLength = rdlen;
3229*4b22b933Srs200217 rdata = get_rdata(&msgbuf, rdlen);
3230*4b22b933Srs200217 memcpy(rr->resrec.rdata->u.data, rdata, rdlen);
3231*4b22b933Srs200217 if (GetTTL) rr->resrec.rroriginalttl = get_long(&msgbuf);
3232*4b22b933Srs200217 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
3233*4b22b933Srs200217 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
3234*4b22b933Srs200217 return rr;
3235*4b22b933Srs200217 }
3236*4b22b933Srs200217
build_domainname_from_strings(domainname * srv,char * name,char * regtype,char * domain)3237*4b22b933Srs200217 mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
3238*4b22b933Srs200217 {
3239*4b22b933Srs200217 domainlabel n;
3240*4b22b933Srs200217 domainname d, t;
3241*4b22b933Srs200217
3242*4b22b933Srs200217 if (!MakeDomainLabelFromLiteralString(&n, name)) return -1;
3243*4b22b933Srs200217 if (!MakeDomainNameFromDNSNameString(&t, regtype)) return -1;
3244*4b22b933Srs200217 if (!MakeDomainNameFromDNSNameString(&d, domain)) return -1;
3245*4b22b933Srs200217 if (!ConstructServiceName(srv, &n, &t, &d)) return -1;
3246*4b22b933Srs200217 return 0;
3247*4b22b933Srs200217 }
3248*4b22b933Srs200217
3249*4b22b933Srs200217 // append a reply to the list in a request object
append_reply(request_state * req,reply_state * rep)3250*4b22b933Srs200217 mDNSlocal void append_reply(request_state *req, reply_state *rep)
3251*4b22b933Srs200217 {
3252*4b22b933Srs200217 reply_state *ptr;
3253*4b22b933Srs200217
3254*4b22b933Srs200217 if (!req->replies) req->replies = rep;
3255*4b22b933Srs200217 else
3256*4b22b933Srs200217 {
3257*4b22b933Srs200217 ptr = req->replies;
3258*4b22b933Srs200217 while (ptr->next) ptr = ptr->next;
3259*4b22b933Srs200217 ptr->next = rep;
3260*4b22b933Srs200217 }
3261*4b22b933Srs200217 rep->next = NULL;
3262*4b22b933Srs200217 }
3263*4b22b933Srs200217
3264*4b22b933Srs200217 // read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
3265*4b22b933Srs200217 // returns the current state of the request (morecoming, error, complete, terminated.)
3266*4b22b933Srs200217 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
read_msg(request_state * rs)3267*4b22b933Srs200217 mDNSlocal int read_msg(request_state *rs)
3268*4b22b933Srs200217 {
3269*4b22b933Srs200217 uint32_t nleft;
3270*4b22b933Srs200217 int nread;
3271*4b22b933Srs200217 char buf[4]; // dummy for death notification
3272*4b22b933Srs200217
3273*4b22b933Srs200217 if (rs->ts == t_terminated || rs->ts == t_error)
3274*4b22b933Srs200217 {
3275*4b22b933Srs200217 LogMsg("ERROR: read_msg called with transfer state terminated or error");
3276*4b22b933Srs200217 rs->ts = t_error;
3277*4b22b933Srs200217 return t_error;
3278*4b22b933Srs200217 }
3279*4b22b933Srs200217
3280*4b22b933Srs200217 if (rs->ts == t_complete)
3281*4b22b933Srs200217 { // this must be death or something is wrong
3282*4b22b933Srs200217 nread = recv(rs->sd, buf, 4, 0);
3283*4b22b933Srs200217 if (!nread) { rs->ts = t_terminated; return t_terminated; }
3284*4b22b933Srs200217 if (nread < 0) goto rerror;
3285*4b22b933Srs200217 LogMsg("ERROR: read data from a completed request.");
3286*4b22b933Srs200217 rs->ts = t_error;
3287*4b22b933Srs200217 return t_error;
3288*4b22b933Srs200217 }
3289*4b22b933Srs200217
3290*4b22b933Srs200217 if (rs->ts != t_morecoming)
3291*4b22b933Srs200217 {
3292*4b22b933Srs200217 LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs->ts);
3293*4b22b933Srs200217 rs->ts = t_error;
3294*4b22b933Srs200217 return t_error;
3295*4b22b933Srs200217 }
3296*4b22b933Srs200217
3297*4b22b933Srs200217 if (rs->hdr_bytes < sizeof(ipc_msg_hdr))
3298*4b22b933Srs200217 {
3299*4b22b933Srs200217 nleft = sizeof(ipc_msg_hdr) - rs->hdr_bytes;
3300*4b22b933Srs200217 nread = recv(rs->sd, (char *)&rs->hdr + rs->hdr_bytes, nleft, 0);
3301*4b22b933Srs200217 if (nread == 0) { rs->ts = t_terminated; return t_terminated; }
3302*4b22b933Srs200217 if (nread < 0) goto rerror;
3303*4b22b933Srs200217 rs->hdr_bytes += nread;
3304*4b22b933Srs200217 if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
3305*4b22b933Srs200217 {
3306*4b22b933Srs200217 ConvertHeaderBytes(&rs->hdr);
3307*4b22b933Srs200217 if (rs->hdr.version != VERSION)
3308*4b22b933Srs200217 {
3309*4b22b933Srs200217 LogMsg("ERROR: read_msg - client version 0x%08X does not match daemon version 0x%08X", rs->hdr.version, VERSION);
3310*4b22b933Srs200217 rs->ts = t_error;
3311*4b22b933Srs200217 return t_error;
3312*4b22b933Srs200217 }
3313*4b22b933Srs200217 }
3314*4b22b933Srs200217 if (rs->hdr_bytes > sizeof(ipc_msg_hdr))
3315*4b22b933Srs200217 {
3316*4b22b933Srs200217 LogMsg("ERROR: read_msg - read too many header bytes");
3317*4b22b933Srs200217 rs->ts = t_error;
3318*4b22b933Srs200217 return t_error;
3319*4b22b933Srs200217 }
3320*4b22b933Srs200217 }
3321*4b22b933Srs200217
3322*4b22b933Srs200217 // only read data if header is complete
3323*4b22b933Srs200217 if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
3324*4b22b933Srs200217 {
3325*4b22b933Srs200217 if (rs->hdr.datalen == 0) // ok in removerecord requests
3326*4b22b933Srs200217 {
3327*4b22b933Srs200217 rs->ts = t_complete;
3328*4b22b933Srs200217 rs->msgbuf = NULL;
3329*4b22b933Srs200217 return t_complete;
3330*4b22b933Srs200217 }
3331*4b22b933Srs200217
3332*4b22b933Srs200217 if (!rs->msgbuf) // allocate the buffer first time through
3333*4b22b933Srs200217 {
3334*4b22b933Srs200217 rs->msgbuf = mallocL("read_msg", rs->hdr.datalen + MSG_PAD_BYTES);
3335*4b22b933Srs200217 if (!rs->msgbuf)
3336*4b22b933Srs200217 {
3337*4b22b933Srs200217 my_perror("ERROR: malloc");
3338*4b22b933Srs200217 rs->ts = t_error;
3339*4b22b933Srs200217 return t_error;
3340*4b22b933Srs200217 }
3341*4b22b933Srs200217 rs->msgdata = rs->msgbuf;
3342*4b22b933Srs200217 bzero(rs->msgbuf, rs->hdr.datalen + MSG_PAD_BYTES);
3343*4b22b933Srs200217 }
3344*4b22b933Srs200217 nleft = rs->hdr.datalen - rs->data_bytes;
3345*4b22b933Srs200217 nread = recv(rs->sd, rs->msgbuf + rs->data_bytes, nleft, 0);
3346*4b22b933Srs200217 if (nread == 0) { rs->ts = t_terminated; return t_terminated; }
3347*4b22b933Srs200217 if (nread < 0) goto rerror;
3348*4b22b933Srs200217 rs->data_bytes += nread;
3349*4b22b933Srs200217 if (rs->data_bytes > rs->hdr.datalen)
3350*4b22b933Srs200217 {
3351*4b22b933Srs200217 LogMsg("ERROR: read_msg - read too many data bytes");
3352*4b22b933Srs200217 rs->ts = t_error;
3353*4b22b933Srs200217 return t_error;
3354*4b22b933Srs200217 }
3355*4b22b933Srs200217 }
3356*4b22b933Srs200217
3357*4b22b933Srs200217 if (rs->hdr_bytes == sizeof(ipc_msg_hdr) && rs->data_bytes == rs->hdr.datalen)
3358*4b22b933Srs200217 rs->ts = t_complete;
3359*4b22b933Srs200217 else rs->ts = t_morecoming;
3360*4b22b933Srs200217
3361*4b22b933Srs200217 return rs->ts;
3362*4b22b933Srs200217
3363*4b22b933Srs200217 rerror:
3364*4b22b933Srs200217 if (dnssd_errno() == dnssd_EWOULDBLOCK || dnssd_errno() == dnssd_EINTR) return t_morecoming;
3365*4b22b933Srs200217 my_perror("ERROR: read_msg");
3366*4b22b933Srs200217 rs->ts = t_error;
3367*4b22b933Srs200217 return t_error;
3368*4b22b933Srs200217 }
3369*4b22b933Srs200217
send_msg(reply_state * rs)3370*4b22b933Srs200217 mDNSlocal int send_msg(reply_state *rs)
3371*4b22b933Srs200217 {
3372*4b22b933Srs200217 ssize_t nwriten;
3373*4b22b933Srs200217
3374*4b22b933Srs200217 if (!rs->msgbuf)
3375*4b22b933Srs200217 {
3376*4b22b933Srs200217 LogMsg("ERROR: send_msg called with NULL message buffer");
3377*4b22b933Srs200217 return t_error;
3378*4b22b933Srs200217 }
3379*4b22b933Srs200217
3380*4b22b933Srs200217 if (rs->request->no_reply) //!!!KRS this behavior should be optimized if it becomes more common
3381*4b22b933Srs200217 {
3382*4b22b933Srs200217 rs->ts = t_complete;
3383*4b22b933Srs200217 freeL("send_msg", rs->msgbuf);
3384*4b22b933Srs200217 return t_complete;
3385*4b22b933Srs200217 }
3386*4b22b933Srs200217
3387*4b22b933Srs200217 ConvertHeaderBytes(rs->mhdr);
3388*4b22b933Srs200217 nwriten = send(rs->sd, rs->msgbuf + rs->nwriten, rs->len - rs->nwriten, 0);
3389*4b22b933Srs200217 ConvertHeaderBytes(rs->mhdr);
3390*4b22b933Srs200217 if (nwriten < 0)
3391*4b22b933Srs200217 {
3392*4b22b933Srs200217 if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK) nwriten = 0;
3393*4b22b933Srs200217 else
3394*4b22b933Srs200217 {
3395*4b22b933Srs200217 #if !defined(PLATFORM_NO_EPIPE)
3396*4b22b933Srs200217 if (dnssd_errno() == EPIPE)
3397*4b22b933Srs200217 {
3398*4b22b933Srs200217 debugf("%3d: broken pipe", rs->sd);
3399*4b22b933Srs200217 rs->ts = t_terminated;
3400*4b22b933Srs200217 rs->request->ts = t_terminated;
3401*4b22b933Srs200217 return t_terminated;
3402*4b22b933Srs200217 }
3403*4b22b933Srs200217 else
3404*4b22b933Srs200217 #endif
3405*4b22b933Srs200217 {
3406*4b22b933Srs200217 my_perror("ERROR: send\n");
3407*4b22b933Srs200217 rs->ts = t_error;
3408*4b22b933Srs200217 return t_error;
3409*4b22b933Srs200217 }
3410*4b22b933Srs200217 }
3411*4b22b933Srs200217 }
3412*4b22b933Srs200217 rs->nwriten += nwriten;
3413*4b22b933Srs200217
3414*4b22b933Srs200217 if (rs->nwriten == rs->len)
3415*4b22b933Srs200217 {
3416*4b22b933Srs200217 rs->ts = t_complete;
3417*4b22b933Srs200217 freeL("send_msg", rs->msgbuf);
3418*4b22b933Srs200217 }
3419*4b22b933Srs200217 return rs->ts;
3420*4b22b933Srs200217 }
3421*4b22b933Srs200217
create_reply(reply_op_t op,size_t datalen,request_state * request)3422*4b22b933Srs200217 mDNSlocal reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request)
3423*4b22b933Srs200217 {
3424*4b22b933Srs200217 reply_state *reply;
3425*4b22b933Srs200217 int totallen;
3426*4b22b933Srs200217
3427*4b22b933Srs200217 if ((unsigned)datalen < sizeof(reply_hdr))
3428*4b22b933Srs200217 {
3429*4b22b933Srs200217 LogMsg("ERROR: create_reply - data length less than lenght of required fields");
3430*4b22b933Srs200217 return NULL;
3431*4b22b933Srs200217 }
3432*4b22b933Srs200217
3433*4b22b933Srs200217 totallen = (int) (datalen + sizeof(ipc_msg_hdr));
3434*4b22b933Srs200217 reply = mallocL("create_reply", sizeof(reply_state));
3435*4b22b933Srs200217 if (!reply) FatalError("ERROR: malloc");
3436*4b22b933Srs200217 bzero(reply, sizeof(reply_state));
3437*4b22b933Srs200217 reply->ts = t_morecoming;
3438*4b22b933Srs200217 reply->sd = request->sd;
3439*4b22b933Srs200217 reply->request = request;
3440*4b22b933Srs200217 reply->len = totallen;
3441*4b22b933Srs200217 reply->msgbuf = mallocL("create_reply", totallen);
3442*4b22b933Srs200217 if (!reply->msgbuf) FatalError("ERROR: malloc");
3443*4b22b933Srs200217 bzero(reply->msgbuf, totallen);
3444*4b22b933Srs200217 reply->mhdr = (ipc_msg_hdr *)reply->msgbuf;
3445*4b22b933Srs200217 reply->rhdr = (reply_hdr *)(reply->msgbuf + sizeof(ipc_msg_hdr));
3446*4b22b933Srs200217 reply->sdata = reply->msgbuf + sizeof(ipc_msg_hdr) + sizeof(reply_hdr);
3447*4b22b933Srs200217 reply->mhdr->version = VERSION;
3448*4b22b933Srs200217 reply->mhdr->op = op;
3449*4b22b933Srs200217 reply->mhdr->datalen = totallen - sizeof(ipc_msg_hdr);
3450*4b22b933Srs200217 return reply;
3451*4b22b933Srs200217 }
3452*4b22b933Srs200217
deliver_error(request_state * rstate,mStatus err)3453*4b22b933Srs200217 mDNSlocal int deliver_error(request_state *rstate, mStatus err)
3454*4b22b933Srs200217 {
3455*4b22b933Srs200217 int nwritten = -1;
3456*4b22b933Srs200217 undelivered_error_t *undeliv;
3457*4b22b933Srs200217
3458*4b22b933Srs200217 err = dnssd_htonl(err);
3459*4b22b933Srs200217 nwritten = send(rstate->sd, (dnssd_sockbuf_t) &err, sizeof(mStatus), 0);
3460*4b22b933Srs200217 if (nwritten < (int)sizeof(mStatus))
3461*4b22b933Srs200217 {
3462*4b22b933Srs200217 if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
3463*4b22b933Srs200217 nwritten = 0;
3464*4b22b933Srs200217 if (nwritten < 0)
3465*4b22b933Srs200217 {
3466*4b22b933Srs200217 my_perror("ERROR: send - unable to deliver error to client");
3467*4b22b933Srs200217 return(-1);
3468*4b22b933Srs200217 }
3469*4b22b933Srs200217 else
3470*4b22b933Srs200217 {
3471*4b22b933Srs200217 //client blocked - store result and come backr
3472*4b22b933Srs200217 undeliv = mallocL("deliver_error", sizeof(undelivered_error_t));
3473*4b22b933Srs200217 if (!undeliv) FatalError("ERROR: malloc");
3474*4b22b933Srs200217 undeliv->err = err;
3475*4b22b933Srs200217 undeliv->nwritten = nwritten;
3476*4b22b933Srs200217 undeliv->sd = rstate->sd;
3477*4b22b933Srs200217 rstate->u_err = undeliv;
3478*4b22b933Srs200217 return 0;
3479*4b22b933Srs200217 }
3480*4b22b933Srs200217 }
3481*4b22b933Srs200217 return 0;
3482*4b22b933Srs200217 }
3483*4b22b933Srs200217
3484*4b22b933Srs200217 // returns 0 on success, -1 if send is incomplete, or on terminal failure (request is aborted)
send_undelivered_error(request_state * rs)3485*4b22b933Srs200217 mDNSlocal transfer_state send_undelivered_error(request_state *rs)
3486*4b22b933Srs200217 {
3487*4b22b933Srs200217 int nwritten;
3488*4b22b933Srs200217
3489*4b22b933Srs200217 nwritten = send(rs->u_err->sd, (char *)(&rs->u_err->err) + rs->u_err->nwritten, sizeof(mStatus) - rs->u_err->nwritten, 0);
3490*4b22b933Srs200217 if (nwritten < 0)
3491*4b22b933Srs200217 {
3492*4b22b933Srs200217 if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
3493*4b22b933Srs200217 nwritten = 0;
3494*4b22b933Srs200217 else
3495*4b22b933Srs200217 {
3496*4b22b933Srs200217 my_perror("ERROR: send - unable to deliver error to client\n");
3497*4b22b933Srs200217 return t_error;
3498*4b22b933Srs200217 }
3499*4b22b933Srs200217 }
3500*4b22b933Srs200217 if ((unsigned int)(nwritten + rs->u_err->nwritten) >= sizeof(mStatus))
3501*4b22b933Srs200217 {
3502*4b22b933Srs200217 freeL("send_undelivered_error", rs->u_err);
3503*4b22b933Srs200217 rs->u_err = NULL;
3504*4b22b933Srs200217 return t_complete;
3505*4b22b933Srs200217 }
3506*4b22b933Srs200217 rs->u_err->nwritten += nwritten;
3507*4b22b933Srs200217 return t_morecoming;
3508*4b22b933Srs200217 }
3509*4b22b933Srs200217
3510*4b22b933Srs200217 // send bogus data along with an error code to the app callback
3511*4b22b933Srs200217 // returns 0 on success (linking reply into list of not fully delivered),
3512*4b22b933Srs200217 // -1 on failure (request should be aborted)
deliver_async_error(request_state * rs,reply_op_t op,mStatus err)3513*4b22b933Srs200217 mDNSlocal int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
3514*4b22b933Srs200217 {
3515*4b22b933Srs200217 int len;
3516*4b22b933Srs200217 reply_state *reply;
3517*4b22b933Srs200217 transfer_state ts;
3518*4b22b933Srs200217
3519*4b22b933Srs200217 if (rs->no_reply) return 0;
3520*4b22b933Srs200217 len = 256; // long enough for any reply handler to read all args w/o buffer overrun
3521*4b22b933Srs200217 reply = create_reply(op, len, rs);
3522*4b22b933Srs200217 reply->rhdr->error = dnssd_htonl(err);
3523*4b22b933Srs200217 ts = send_msg(reply);
3524*4b22b933Srs200217 if (ts == t_error || ts == t_terminated)
3525*4b22b933Srs200217 {
3526*4b22b933Srs200217 freeL("deliver_async_error", reply);
3527*4b22b933Srs200217 return -1;
3528*4b22b933Srs200217 }
3529*4b22b933Srs200217 else if (ts == t_complete) freeL("deliver_async_error", reply);
3530*4b22b933Srs200217 else if (ts == t_morecoming) append_reply(rs, reply); // client is blocked, link reply into list
3531*4b22b933Srs200217 return 0;
3532*4b22b933Srs200217 }
3533*4b22b933Srs200217
abort_request(request_state * rs)3534*4b22b933Srs200217 mDNSlocal void abort_request(request_state *rs)
3535*4b22b933Srs200217 {
3536*4b22b933Srs200217 reply_state *rep, *ptr;
3537*4b22b933Srs200217
3538*4b22b933Srs200217 if (rs->terminate) rs->terminate(rs->termination_context); // terminate field may not be set yet
3539*4b22b933Srs200217 if (rs->msgbuf) freeL("abort_request", rs->msgbuf);
3540*4b22b933Srs200217 LogOperation("%3d: Removing FD", rs->sd);
3541*4b22b933Srs200217 udsSupportRemoveFDFromEventLoop(rs->sd); // Note: This also closes file descriptor rs->sd for us
3542*4b22b933Srs200217
3543*4b22b933Srs200217 // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MACOSX_MDNS_MALLOC_DEBUGGING uses
3544*4b22b933Srs200217 // for detecting when the memory for an object is inadvertently freed while the object is still on some list
3545*4b22b933Srs200217 rs->sd = -2;
3546*4b22b933Srs200217
3547*4b22b933Srs200217 // free pending replies
3548*4b22b933Srs200217 rep = rs->replies;
3549*4b22b933Srs200217 while(rep)
3550*4b22b933Srs200217 {
3551*4b22b933Srs200217 if (rep->msgbuf) freeL("abort_request", rep->msgbuf);
3552*4b22b933Srs200217 ptr = rep;
3553*4b22b933Srs200217 rep = rep->next;
3554*4b22b933Srs200217 freeL("abort_request", ptr);
3555*4b22b933Srs200217 }
3556*4b22b933Srs200217
3557*4b22b933Srs200217 if (rs->u_err)
3558*4b22b933Srs200217 {
3559*4b22b933Srs200217 freeL("abort_request", rs->u_err);
3560*4b22b933Srs200217 rs->u_err = NULL;
3561*4b22b933Srs200217 }
3562*4b22b933Srs200217 }
3563*4b22b933Srs200217
unlink_request(request_state * rs)3564*4b22b933Srs200217 mDNSlocal void unlink_request(request_state *rs)
3565*4b22b933Srs200217 {
3566*4b22b933Srs200217 request_state *ptr;
3567*4b22b933Srs200217
3568*4b22b933Srs200217 if (rs == all_requests)
3569*4b22b933Srs200217 {
3570*4b22b933Srs200217 all_requests = all_requests->next;
3571*4b22b933Srs200217 freeL("unlink_request", rs);
3572*4b22b933Srs200217 return;
3573*4b22b933Srs200217 }
3574*4b22b933Srs200217 for(ptr = all_requests; ptr->next; ptr = ptr->next)
3575*4b22b933Srs200217 if (ptr->next == rs)
3576*4b22b933Srs200217 {
3577*4b22b933Srs200217 ptr->next = rs->next;
3578*4b22b933Srs200217 freeL("unlink_request", rs);
3579*4b22b933Srs200217 return;
3580*4b22b933Srs200217 }
3581*4b22b933Srs200217 }
3582*4b22b933Srs200217
3583*4b22b933Srs200217 //hack to search-replace perror's to LogMsg's
my_perror(char * errmsg)3584*4b22b933Srs200217 mDNSlocal void my_perror(char *errmsg)
3585*4b22b933Srs200217 {
3586*4b22b933Srs200217 LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
3587*4b22b933Srs200217 }
3588*4b22b933Srs200217
3589*4b22b933Srs200217 // check that the message delivered by the client is sufficiently long to extract the required data from the buffer
3590*4b22b933Srs200217 // without overrunning it.
3591*4b22b933Srs200217 // returns 0 on success, -1 on error.
3592*4b22b933Srs200217
validate_message(request_state * rstate)3593*4b22b933Srs200217 mDNSlocal int validate_message(request_state *rstate)
3594*4b22b933Srs200217 {
3595*4b22b933Srs200217 uint32_t min_size;
3596*4b22b933Srs200217
3597*4b22b933Srs200217 switch(rstate->hdr.op)
3598*4b22b933Srs200217 {
3599*4b22b933Srs200217 case resolve_request: min_size = sizeof(DNSServiceFlags) + // flags
3600*4b22b933Srs200217 sizeof(uint32_t) + // interface
3601*4b22b933Srs200217 (3 * sizeof(char)); // name, regtype, domain
3602*4b22b933Srs200217 break;
3603*4b22b933Srs200217 case query_request: min_size = sizeof(DNSServiceFlags) + // flags
3604*4b22b933Srs200217 sizeof(uint32_t) + // interface
3605*4b22b933Srs200217 sizeof(char) + // fullname
3606*4b22b933Srs200217 (2 * sizeof(uint16_t)); // type, class
3607*4b22b933Srs200217 break;
3608*4b22b933Srs200217 case browse_request: min_size = sizeof(DNSServiceFlags) + // flags
3609*4b22b933Srs200217 sizeof(uint32_t) + // interface
3610*4b22b933Srs200217 (2 * sizeof(char)); // regtype, domain
3611*4b22b933Srs200217 break;
3612*4b22b933Srs200217 case reg_service_request: min_size = sizeof(DNSServiceFlags) + // flags
3613*4b22b933Srs200217 sizeof(uint32_t) + // interface
3614*4b22b933Srs200217 (4 * sizeof(char)) + // name, type, domain, host
3615*4b22b933Srs200217 (2 * sizeof(uint16_t)); // port, textlen
3616*4b22b933Srs200217 break;
3617*4b22b933Srs200217 case enumeration_request: min_size = sizeof(DNSServiceFlags) + // flags
3618*4b22b933Srs200217 sizeof(uint32_t); // interface
3619*4b22b933Srs200217 break;
3620*4b22b933Srs200217 case reg_record_request: min_size = sizeof(DNSServiceFlags) + // flags
3621*4b22b933Srs200217 sizeof(uint32_t) + // interface
3622*4b22b933Srs200217 sizeof(char) + // fullname
3623*4b22b933Srs200217 (3 * sizeof(uint16_t)) + // type, class, rdlen
3624*4b22b933Srs200217 sizeof(uint32_t); // ttl
3625*4b22b933Srs200217 break;
3626*4b22b933Srs200217 case add_record_request: min_size = sizeof(DNSServiceFlags) + // flags
3627*4b22b933Srs200217 (2 * sizeof(uint16_t)) + // type, rdlen
3628*4b22b933Srs200217 sizeof(uint32_t); // ttl
3629*4b22b933Srs200217 break;
3630*4b22b933Srs200217 case update_record_request: min_size = sizeof(DNSServiceFlags) + // flags
3631*4b22b933Srs200217 sizeof(uint16_t) + // rdlen
3632*4b22b933Srs200217 sizeof(uint32_t); // ttl
3633*4b22b933Srs200217 break;
3634*4b22b933Srs200217 case remove_record_request: min_size = sizeof(DNSServiceFlags); // flags
3635*4b22b933Srs200217 break;
3636*4b22b933Srs200217 case reconfirm_record_request: min_size=sizeof(DNSServiceFlags) + // flags
3637*4b22b933Srs200217 sizeof(uint32_t) + // interface
3638*4b22b933Srs200217 sizeof(char) + // fullname
3639*4b22b933Srs200217 (3 * sizeof(uint16_t)); // type, class, rdlen
3640*4b22b933Srs200217 break;
3641*4b22b933Srs200217 case setdomain_request: min_size = sizeof(DNSServiceFlags) + sizeof(char); // flags + domain
3642*4b22b933Srs200217 break;
3643*4b22b933Srs200217 default:
3644*4b22b933Srs200217 LogMsg("ERROR: validate_message - unsupported request type: %d", rstate->hdr.op);
3645*4b22b933Srs200217 return -1;
3646*4b22b933Srs200217 }
3647*4b22b933Srs200217
3648*4b22b933Srs200217 return (rstate->data_bytes >= min_size ? 0 : -1);
3649*4b22b933Srs200217
3650*4b22b933Srs200217 }
3651*4b22b933Srs200217
dnssd_htonl(uint32_t l)3652*4b22b933Srs200217 mDNSlocal uint32_t dnssd_htonl(uint32_t l)
3653*4b22b933Srs200217 {
3654*4b22b933Srs200217 uint32_t ret;
3655*4b22b933Srs200217 char * data;
3656*4b22b933Srs200217
3657*4b22b933Srs200217 data = (char*) &ret;
3658*4b22b933Srs200217
3659*4b22b933Srs200217 put_long(l, &data);
3660*4b22b933Srs200217
3661*4b22b933Srs200217 return ret;
3662*4b22b933Srs200217 }
3663*4b22b933Srs200217
3664*4b22b933Srs200217 #if defined(_WIN32)
3665*4b22b933Srs200217
win32_strerror(int inErrorCode)3666*4b22b933Srs200217 mDNSlocal char * win32_strerror(int inErrorCode)
3667*4b22b933Srs200217 {
3668*4b22b933Srs200217 static char buffer[1024];
3669*4b22b933Srs200217 DWORD n;
3670*4b22b933Srs200217
3671*4b22b933Srs200217 memset(buffer, 0, sizeof(buffer));
3672*4b22b933Srs200217
3673*4b22b933Srs200217 n = FormatMessageA(
3674*4b22b933Srs200217 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
3675*4b22b933Srs200217 NULL,
3676*4b22b933Srs200217 (DWORD) inErrorCode,
3677*4b22b933Srs200217 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
3678*4b22b933Srs200217 buffer,
3679*4b22b933Srs200217 sizeof( buffer ),
3680*4b22b933Srs200217 NULL );
3681*4b22b933Srs200217
3682*4b22b933Srs200217 if( n > 0 )
3683*4b22b933Srs200217 {
3684*4b22b933Srs200217 // Remove any trailing CR's or LF's since some messages have them.
3685*4b22b933Srs200217
3686*4b22b933Srs200217 while( ( n > 0 ) && isspace( ( (unsigned char *) buffer)[ n - 1 ] ) )
3687*4b22b933Srs200217 {
3688*4b22b933Srs200217 buffer[ --n ] = '\0';
3689*4b22b933Srs200217 }
3690*4b22b933Srs200217 }
3691*4b22b933Srs200217
3692*4b22b933Srs200217 return buffer;
3693*4b22b933Srs200217 }
3694*4b22b933Srs200217
3695*4b22b933Srs200217 #endif
3696