1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
26 Contains: main & associated Application layer for mDNSResponder on Linux.
28 Change History (most recent first):
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
34 Revision 1.24 2005/01/19 19:20:49 ksekar
35 <rdar://problem/3960191> Need a way to turn off domain discovery
37 Revision 1.23 2004/12/16 20:17:11 cheshire
38 <rdar://problem/3324626> Cache memory management improvements
40 Revision 1.22 2004/12/10 13:12:08 cheshire
41 Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
43 Revision 1.21 2004/12/01 20:57:20 ksekar
44 <rdar://problem/3873921> Wide Area Rendezvous must be split-DNS aware
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
50 Revision 1.19 2004/12/01 03:30:29 cheshire
51 <rdar://problem/3889346> Add Unicast DNS support to mDNSPosix
53 Revision 1.18 2004/11/30 22:45:59 cheshire
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
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
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.
69 Revision 1.14 2004/09/16 00:24:49 cheshire
70 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
72 Revision 1.13 2004/08/11 01:59:41 cheshire
73 Remove "mDNS *globalInstance" parameter from udsserver_init()
75 Revision 1.12 2004/06/28 23:19:19 cheshire
76 Fix "Daemon_Init declared but never defined" warning on Linux
78 Revision 1.11 2004/06/25 00:26:27 rpantos
79 Changes to fix the Posix build on Solaris.
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
84 Revision 1.9 2004/05/29 00:14:20 rpantos
85 <rdar://problem/3508093> Runtime check to disable prod mdnsd on OS X.
87 Revision 1.8 2004/04/07 01:19:04 cheshire
88 Hash slot value should be unsigned
90 Revision 1.7 2004/02/14 06:34:57 cheshire
91 Use LogMsg instead of fprintf( stderr
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.)
96 Revision 1.5 2004/02/05 07:45:43 cheshire
99 Revision 1.4 2004/01/28 21:14:23 cheshire
100 Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
102 Revision 1.3 2004/01/19 19:51:46 cheshire
103 Fix compiler error (mixed declarations and code) on some versions of Linux
105 Revision 1.2 2003/12/11 03:03:51 rpantos
106 Clean up mDNSPosix so that it builds on OS X again.
108 Revision 1.1 2003/12/08 20:47:02 rpantos
109 Add support for mDNSResponder on Linux.
120 #include <sys/types.h>
121 #include <netinet/in.h>
122 #include <arpa/inet.h>
124 #include "mDNSEmbeddedAPI.h"
125 #include "mDNSDebug.h"
126 #include "mDNSPosix.h"
127 #include "uds_daemon.h"
128 #include "PlatformCommon.h"
130 #define uDNS_SERVERS_FILE "/etc/resolv.conf"
132 #define CONFIG_FILE "/etc/mdnsd.conf"
133 static domainname DynDNSZone
; // Default wide-area zone for service registration
134 static domainname DynDNSHostname
;
136 #define RR_CACHE_SIZE 500
137 static CacheEntity gRRCache
[RR_CACHE_SIZE
];
139 extern const char mDNSResponderVersionString
[];
141 static int ParseDNSServers(mDNS
*m
, const char *filePath
)
146 int numOfServers
= 0;
147 FILE *fp
= fopen(filePath
, "r");
148 if (fp
== NULL
) return -1;
149 while (fgets(line
,sizeof(line
),fp
))
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)
158 DNSAddr
.type
= mDNSAddrType_IPv4
;
159 DNSAddr
.ip
.v4
.NotAnInteger
= ina
.s_addr
;
160 mDNS_AddDNSServer(m
, &DNSAddr
, NULL
);
164 return (numOfServers
> 0) ? 0 : -1;
167 static void Reconfigure(mDNS
*m
)
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
);
180 // Do appropriate things at startup with command line arguments. Calls exit() if unhappy.
181 static void ParseCmdLinArgs(int argc
, char **argv
)
185 if (0 == strcmp(argv
[1], "-debug")) mDNS_DebugMode
= mDNStrue
;
186 else printf("Usage: mDNSResponder [-debug]\n");
191 int result
= daemon(0, 0);
192 if (result
!= 0) { LogMsg("Could not run as daemon - exiting"); exit(result
); }
194 LogMsg("The POSIX mDNSResponder should only be used on OS X for testing - exiting");
200 static void DumpStateLog(mDNS
*const m
)
201 // Dump a little log of what we've been up to.
203 LogMsgIdent(mDNSResponderVersionString
, "---- BEGIN STATE LOG ----");
205 LogMsgIdent(mDNSResponderVersionString
, "---- END STATE LOG ----");
208 static mStatus
MainLoop(mDNS
*m
) // Loop until we quit.
211 mDNSBool gotData
= mDNSfalse
;
213 mDNSPosixListenForSignalInEventLoop(SIGINT
);
214 mDNSPosixListenForSignalInEventLoop(SIGTERM
);
215 mDNSPosixListenForSignalInEventLoop(SIGUSR1
);
216 mDNSPosixListenForSignalInEventLoop(SIGPIPE
);
217 mDNSPosixListenForSignalInEventLoop(SIGHUP
) ;
221 // Work out how long we expect to sleep before the next scheduled task
222 struct timeval timeout
;
225 // Only idle if we didn't find any data the last time around
228 mDNSs32 nextTimerEvent
= mDNS_Execute(m
);
229 nextTimerEvent
= udsserver_idle(nextTimerEvent
);
230 ticks
= nextTimerEvent
- mDNS_TimeNow(m
);
231 if (ticks
< 1) ticks
= 1;
233 else // otherwise call EventLoop again with 0 timemout
236 timeout
.tv_sec
= ticks
/ mDNSPlatformOneSecond
;
237 timeout
.tv_usec
= (ticks
% mDNSPlatformOneSecond
) * 1000000 / mDNSPlatformOneSecond
;
239 (void) mDNSPosixRunEventLoopOnce(m
, &timeout
, &signals
, &gotData
);
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;
250 int main(int argc
, char **argv
)
252 #define mDNSRecord mDNSStorage
253 mDNS_PlatformSupport platformStorage
;
256 bzero(&mDNSRecord
, sizeof mDNSRecord
);
257 bzero(&platformStorage
, sizeof platformStorage
);
259 ParseCmdLinArgs(argc
, argv
);
261 err
= mDNS_Init(&mDNSRecord
, &platformStorage
, gRRCache
, RR_CACHE_SIZE
, mDNS_Init_AdvertiseLocalAddresses
,
262 mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
264 if (mStatus_NoError
== err
)
265 err
= udsserver_init();
267 Reconfigure(&mDNSRecord
);
269 // Now that we're finished with anything privileged, switch over to running as "nobody"
270 if (mStatus_NoError
== err
)
272 const struct passwd
*pw
= getpwnam("nobody");
276 LogMsg("WARNING: mdnsd continuing as root because user \"nobody\" does not exist");
279 if (mStatus_NoError
== err
)
280 err
= MainLoop(&mDNSRecord
);
282 mDNS_Close(&mDNSRecord
);
284 if (udsserver_exit() < 0)
285 LogMsg("ExitCallback: udsserver_exit failed");
287 #if MDNS_DEBUGMSGS > 0
288 printf("mDNSResponder exiting normally with %ld\n", err
);
294 // uds_daemon support ////////////////////////////////////////////////////////////
296 #if MDNS_MALLOC_DEBUGGING >= 2
297 #define LogMalloc LogMsg
299 #define LogMalloc(ARGS...) ((void)0)
302 mStatus
udsSupportAddFDToEventLoop(int fd
, udsEventCallback callback
, void *context
)
303 /* Support routine for uds_daemon.c */
305 // Depends on the fact that udsEventCallback == mDNSPosixEventCallback
306 return mDNSPosixAddFDToEventLoop(fd
, callback
, context
);
309 mStatus
udsSupportRemoveFDFromEventLoop(int fd
) // Note: This also CLOSES the file descriptor
311 return mDNSPosixRemoveFDFromEventLoop(fd
);
315 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
322 #if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
324 void *mallocL(char *msg
, unsigned int size
)
326 unsigned long *mem
= malloc(size
+8);
329 LogMsg("malloc( %s : %d ) failed", msg
, size
);
334 LogMalloc("malloc( %s : %lu ) = %p", msg
, size
, &mem
[2]);
337 //bzero(&mem[2], size);
338 memset(&mem
[2], 0xFF, size
);
339 // validatelists(&mDNSStorage);
344 void freeL(char *msg
, void *x
)
347 LogMsg("free( %s @ NULL )!", msg
);
350 unsigned long *mem
= ((unsigned long *)x
) - 2;
351 if (mem
[0] != 0xDEAD1234)
352 { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg
, &mem
[2]); return; }
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);
363 #endif // MACOSX_MDNS_MALLOC_DEBUGGING >= 1
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__
") ";
369 mDNSexport
const char mDNSResponderVersionString
[] = "mDNSResponder (Engineering Build) (" __DATE__
" " __TIME__
") ";