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