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