1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16
17 File: daemon.c
18
19 Contains: main & associated Application layer for mDNSResponder on Linux.
20
21 Change History (most recent first):
22
23 $Log: PosixDaemon.c,v $
24 Revision 1.29.2.1 2006/08/29 06:24:34 cheshire
25 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
26
27 Revision 1.29 2005/08/04 03:37:45 mkrochma
28 Temporary workaround to fix posix after mDNS_SetPrimaryInterfaceInfo changed
29
30 Revision 1.28 2005/07/19 11:21:09 cheshire
31 <rdar://problem/4170449> Unix Domain Socket leak in mdnsd
32
33 Revision 1.27 2005/02/04 00:39:59 cheshire
34 Move ParseDNSServers() from PosixDaemon.c to mDNSPosix.c so all Posix client layers can use it
35
36 Revision 1.26 2005/02/02 02:21:30 cheshire
37 Update references to "mDNSResponder" to say "mdnsd" instead
38
39 Revision 1.25 2005/01/27 20:01:50 cheshire
40 udsSupportRemoveFDFromEventLoop() needs to close the file descriptor as well
41
42 Revision 1.24 2005/01/19 19:20:49 ksekar
43 <rdar://problem/3960191> Need a way to turn off domain discovery
44
45 Revision 1.23 2004/12/16 20:17:11 cheshire
46 <rdar://problem/3324626> Cache memory management improvements
47
48 Revision 1.22 2004/12/10 13:12:08 cheshire
49 Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
50
51 Revision 1.21 2004/12/01 20:57:20 ksekar
52 <rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware
53
54 Revision 1.20 2004/12/01 04:28:43 cheshire
55 <rdar://problem/3872803> Darwin patches for Solaris and Suse
56 Use version of daemon() provided in mDNSUNP.c instead of local copy
57
58 Revision 1.19 2004/12/01 03:30:29 cheshire
59 <rdar://problem/3889346> Add Unicast DNS support to mDNSPosix
60
61 Revision 1.18 2004/11/30 22:45:59 cheshire
62 Minor code tidying
63
64 Revision 1.17 2004/11/30 22:18:59 cheshire
65 <rdar://problem/3889351> Posix needs to read the list of unicast DNS servers and set server list
66
67 Revision 1.16 2004/09/21 21:05:12 cheshire
68 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
69 into mDNSShared/uds_daemon.c
70
71 Revision 1.15 2004/09/17 01:08:53 cheshire
72 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
73 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
74 declared in that file are ONLY appropriate to single-address-space embedded applications.
75 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
76
77 Revision 1.14 2004/09/16 00:24:49 cheshire
78 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
79
80 Revision 1.13 2004/08/11 01:59:41 cheshire
81 Remove "mDNS *globalInstance" parameter from udsserver_init()
82
83 Revision 1.12 2004/06/28 23:19:19 cheshire
84 Fix "Daemon_Init declared but never defined" warning on Linux
85
86 Revision 1.11 2004/06/25 00:26:27 rpantos
87 Changes to fix the Posix build on Solaris.
88
89 Revision 1.10 2004/06/08 04:59:40 cheshire
90 Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it
91
92 Revision 1.9 2004/05/29 00:14:20 rpantos
93 <rdar://problem/3508093> Runtime check to disable prod mdnsd on OS X.
94
95 Revision 1.8 2004/04/07 01:19:04 cheshire
96 Hash slot value should be unsigned
97
98 Revision 1.7 2004/02/14 06:34:57 cheshire
99 Use LogMsg instead of fprintf( stderr
100
101 Revision 1.6 2004/02/14 01:10:42 rpantos
102 Allow daemon to run if 'nobody' is not defined, with a warning. (For Roku HD1000.)
103
104 Revision 1.5 2004/02/05 07:45:43 cheshire
105 Add Log header
106
107 Revision 1.4 2004/01/28 21:14:23 cheshire
108 Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
109
110 Revision 1.3 2004/01/19 19:51:46 cheshire
111 Fix compiler error (mixed declarations and code) on some versions of Linux
112
113 Revision 1.2 2003/12/11 03:03:51 rpantos
114 Clean up mDNSPosix so that it builds on OS X again.
115
116 Revision 1.1 2003/12/08 20:47:02 rpantos
117 Add support for mDNSResponder on Linux.
118 */
119
120 #pragma ident "%Z%%M% %I% %E% SMI"
121
122 #include <stdio.h>
123 #include <string.h>
124 #include <unistd.h>
125 #include <stdlib.h>
126 #include <signal.h>
127 #include <errno.h>
128 #include <fcntl.h>
129 #include <pwd.h>
130 #include <sys/types.h>
131
132 #include "mDNSEmbeddedAPI.h"
133 #include "mDNSDebug.h"
134 #include "mDNSPosix.h"
135 #include "uds_daemon.h"
136 #include "PlatformCommon.h"
137 #include "mDNSUNP.h"
138
139 #ifndef MDNSD_USER
140 #define MDNSD_USER "nobody"
141 #endif
142
143 #define CONFIG_FILE "/etc/mdnsd.conf"
144 static domainname DynDNSZone; // Default wide-area zone for service registration
145 static domainname DynDNSHostname;
146
147 #define RR_CACHE_SIZE 500
148 static CacheEntity gRRCache[RR_CACHE_SIZE];
149
150 extern const char mDNSResponderVersionString[];
151
Reconfigure(mDNS * m)152 static void Reconfigure(mDNS *m)
153 {
154 mDNSAddr DynDNSIP;
155 mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);
156 mDNS_DeleteDNSServers(m);
157 if (ParseDNSServers(m, uDNS_SERVERS_FILE) < 0)
158 LogMsgNoIdent("Unable to parse DNS server list. Unicast DNS-SD unavailable");
159 ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &DynDNSHostname, &DynDNSZone, NULL);
160 FindDefaultRouteIP(&DynDNSIP);
161 if (DynDNSHostname.c[0]) mDNS_AddDynDNSHostName(m, &DynDNSHostname, NULL, NULL);
162 if (DynDNSIP.type) mDNS_SetPrimaryInterfaceInfo(m, &DynDNSIP, NULL, NULL);
163 }
164
165 // Do appropriate things at startup with command line arguments. Calls exit() if unhappy.
ParseCmdLinArgs(int argc,char ** argv)166 static void ParseCmdLinArgs(int argc, char **argv)
167 {
168 if (argc > 1)
169 {
170 if (0 == strcmp(argv[1], "-debug")) mDNS_DebugMode = mDNStrue;
171 else printf("Usage: %s [-debug]\n", argv[0]);
172 }
173
174 if (!mDNS_DebugMode)
175 {
176 int result = daemon(0, 0);
177 if (result != 0) { LogMsg("Could not run as daemon - exiting"); exit(result); }
178 #if __APPLE__
179 LogMsg("The POSIX mdnsd should only be used on OS X for testing - exiting");
180 exit(-1);
181 #endif
182 }
183 }
184
DumpStateLog(mDNS * const m)185 static void DumpStateLog(mDNS *const m)
186 // Dump a little log of what we've been up to.
187 {
188 LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----");
189 udsserver_info(m);
190 LogMsgIdent(mDNSResponderVersionString, "---- END STATE LOG ----");
191 }
192
MainLoop(mDNS * m)193 static mStatus MainLoop(mDNS *m) // Loop until we quit.
194 {
195 sigset_t signals;
196 mDNSBool gotData = mDNSfalse;
197
198 mDNSPosixListenForSignalInEventLoop(SIGINT);
199 mDNSPosixListenForSignalInEventLoop(SIGTERM);
200 mDNSPosixListenForSignalInEventLoop(SIGUSR1);
201 mDNSPosixListenForSignalInEventLoop(SIGPIPE);
202 mDNSPosixListenForSignalInEventLoop(SIGHUP) ;
203
204 for (; ;)
205 {
206 // Work out how long we expect to sleep before the next scheduled task
207 struct timeval timeout;
208 mDNSs32 ticks;
209
210 // Only idle if we didn't find any data the last time around
211 if (!gotData)
212 {
213 mDNSs32 nextTimerEvent = mDNS_Execute(m);
214 nextTimerEvent = udsserver_idle(nextTimerEvent);
215 ticks = nextTimerEvent - mDNS_TimeNow(m);
216 if (ticks < 1) ticks = 1;
217 }
218 else // otherwise call EventLoop again with 0 timemout
219 ticks = 0;
220
221 timeout.tv_sec = ticks / mDNSPlatformOneSecond;
222 timeout.tv_usec = (ticks % mDNSPlatformOneSecond) * 1000000 / mDNSPlatformOneSecond;
223
224 (void) mDNSPosixRunEventLoopOnce(m, &timeout, &signals, &gotData);
225
226 if (sigismember(&signals, SIGHUP )) Reconfigure(m);
227 if (sigismember(&signals, SIGUSR1)) DumpStateLog(m);
228 // SIGPIPE happens when we try to write to a dead client; death should be detected soon in request_callback() and cleaned up.
229 if (sigismember(&signals, SIGPIPE)) LogMsg("Received SIGPIPE - ignoring");
230 if (sigismember(&signals, SIGINT) || sigismember(&signals, SIGTERM)) break;
231 }
232 return EINTR;
233 }
234
main(int argc,char ** argv)235 int main(int argc, char **argv)
236 {
237 #define mDNSRecord mDNSStorage
238 mDNS_PlatformSupport platformStorage;
239 mStatus err;
240
241 bzero(&mDNSRecord, sizeof mDNSRecord);
242 bzero(&platformStorage, sizeof platformStorage);
243
244 ParseCmdLinArgs(argc, argv);
245
246 LogMsgIdent(mDNSResponderVersionString, "starting");
247
248 err = mDNS_Init(&mDNSRecord, &platformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses,
249 mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
250
251 if (mStatus_NoError == err)
252 err = udsserver_init();
253
254 Reconfigure(&mDNSRecord);
255
256 // Now that we're finished with anything privileged, switch over to running as "nobody"
257 if (mStatus_NoError == err)
258 {
259 const struct passwd *pw = getpwnam(MDNSD_USER);
260 if (pw != NULL)
261 setuid(pw->pw_uid);
262 else
263 #ifdef MDNSD_NOROOT
264 {
265 LogMsg("WARNING: mdnsd exiting because user \""MDNSD_USER"\" does not exist");
266 err = mStatus_Invalid;
267 }
268 #else
269 LogMsg("WARNING: mdnsd continuing as root because user \""MDNSD_USER"\" does not exist");
270 #endif
271 }
272
273 if (mStatus_NoError == err)
274 err = MainLoop(&mDNSRecord);
275
276 LogMsgIdent(mDNSResponderVersionString, "stopping");
277
278 mDNS_Close(&mDNSRecord);
279
280 if (udsserver_exit() < 0)
281 LogMsg("ExitCallback: udsserver_exit failed");
282
283 #if MDNS_DEBUGMSGS > 0
284 printf("mDNSResponder exiting normally with %ld\n", err);
285 #endif
286
287 return err;
288 }
289
290 // uds_daemon support ////////////////////////////////////////////////////////////
291
292 #undef LogMalloc
293
294 #if MDNS_MALLOC_DEBUGGING >= 2
295 #define LogMalloc LogMsg
296 #else
297 #define LogMalloc(ARGS...) ((void)0)
298 #endif
299
udsSupportAddFDToEventLoop(int fd,udsEventCallback callback,void * context)300 mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context)
301 /* Support routine for uds_daemon.c */
302 {
303 // Depends on the fact that udsEventCallback == mDNSPosixEventCallback
304 return mDNSPosixAddFDToEventLoop(fd, callback, context);
305 }
306
udsSupportRemoveFDFromEventLoop(int fd)307 mStatus udsSupportRemoveFDFromEventLoop(int fd) // Note: This also CLOSES the file descriptor
308 {
309 mStatus err = mDNSPosixRemoveFDFromEventLoop(fd);
310 close(fd);
311 return err;
312 }
313
RecordUpdatedNiceLabel(mDNS * const m,mDNSs32 delay)314 mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
315 {
316 (void)m;
317 (void)delay;
318 // No-op, for now
319 }
320
321 #if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
322
mallocL(char * msg,unsigned int size)323 void *mallocL(char *msg, unsigned int size)
324 {
325 unsigned long *mem = malloc(size+8);
326 if (!mem)
327 {
328 LogMsg("malloc( %s : %d ) failed", msg, size);
329 return(NULL);
330 }
331 else
332 {
333 LogMalloc("malloc( %s : %lu ) = %p", msg, size, &mem[2]);
334 mem[0] = 0xDEAD1234;
335 mem[1] = size;
336 //bzero(&mem[2], size);
337 memset(&mem[2], 0xFF, size);
338 // validatelists(&mDNSStorage);
339 return(&mem[2]);
340 }
341 }
342
freeL(char * msg,void * x)343 void freeL(char *msg, void *x)
344 {
345 if (!x)
346 LogMsg("free( %s @ NULL )!", msg);
347 else
348 {
349 unsigned long *mem = ((unsigned long *)x) - 2;
350 if (mem[0] != 0xDEAD1234)
351 { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; }
352 if (mem[1] > 8000)
353 { LogMsg("free( %s : %ld @ %p) too big!", msg, mem[1], &mem[2]); return; }
354 LogMalloc("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
355 //bzero(mem, mem[1]+8);
356 memset(mem, 0xDD, mem[1]+8);
357 // validatelists(&mDNSStorage);
358 free(mem);
359 }
360 }
361
362 #endif // MACOSX_MDNS_MALLOC_DEBUGGING >= 1
363
364 // For convenience when using the "strings" command, this is the last thing in the file
365 #if mDNSResponderVersion > 1
366 mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder-" STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ") ";
367 #elif MDNS_VERSIONSTR_NODTS
368 mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder (Engineering Build) ";
369 #else
370 mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder (Engineering Build) (" __DATE__ " " __TIME__ ") ";
371 #endif
372