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 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. 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 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 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 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 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 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 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 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 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