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.49 2009/04/30 20:07:51 mcguire 25 <rdar://problem/6822674> Support multiple UDSs from launchd 26 27 Revision 1.48 2009/04/11 01:43:28 jessic2 28 <rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically 29 30 Revision 1.47 2009/01/11 03:20:06 mkrochma 31 <rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris 32 33 Revision 1.46 2008/11/03 23:09:15 cheshire 34 Don't need to include mDNSDebug.h as well as mDNSEmbeddedAPI.h 35 36 Revision 1.45 2008/10/03 18:25:17 cheshire 37 Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);" 38 39 Revision 1.44 2008/09/15 23:52:30 cheshire 40 <rdar://problem/6218902> mDNSResponder-177 fails to compile on Linux with .desc pseudo-op 41 Made __crashreporter_info__ symbol conditional, so we only use it for OS X build 42 43 Revision 1.43 2007/10/22 20:05:34 cheshire 44 Use mDNSPlatformSourceAddrForDest instead of FindSourceAddrForIP 45 46 Revision 1.42 2007/09/18 19:09:02 cheshire 47 <rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings 48 49 Revision 1.41 2007/09/04 17:02:25 cheshire 50 <rdar://problem/5458929> False positives in changed files list in nightly builds 51 Added MDNS_VERSIONSTR_NODTS option at the reqest of Rishi Srivatsavai (Sun) 52 53 Revision 1.40 2007/07/31 23:08:34 mcguire 54 <rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming 55 56 Revision 1.39 2007/03/21 00:30:44 cheshire 57 Remove obsolete mDNS_DeleteDNSServers() call 58 59 Revision 1.38 2007/02/14 01:58:19 cheshire 60 <rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup 61 62 Revision 1.37 2007/02/07 19:32:00 cheshire 63 <rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format 64 65 Revision 1.36 2007/02/06 19:06:48 cheshire 66 <rdar://problem/3956518> Need to go native with launchd 67 68 Revision 1.35 2007/01/05 08:30:52 cheshire 69 Trim excessive "Log" checkin history from before 2006 70 (checkin history still available via "cvs log ..." of course) 71 72 Revision 1.34 2007/01/05 05:46:08 cheshire 73 Add mDNS *const m parameter to udsserver_handle_configchange() 74 75 Revision 1.33 2006/12/21 00:10:53 cheshire 76 Make mDNS_PlatformSupport PlatformStorage a static global instead of a stack variable 77 78 Revision 1.32 2006/11/03 22:28:50 cheshire 79 PosixDaemon needs to handle mStatus_ConfigChanged and mStatus_GrowCache messages 80 81 Revision 1.31 2006/08/14 23:24:46 cheshire 82 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 83 84 Revision 1.30 2006/07/07 01:09:12 cheshire 85 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd 86 Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd 87 88 */ 89 90 #include <stdio.h> 91 #include <string.h> 92 #include <unistd.h> 93 #include <stdlib.h> 94 #include <signal.h> 95 #include <errno.h> 96 #include <fcntl.h> 97 #include <pwd.h> 98 #include <sys/types.h> 99 100 #include "mDNSEmbeddedAPI.h" 101 #include "mDNSPosix.h" 102 #include "mDNSUNP.h" // For daemon() 103 #include "uds_daemon.h" 104 #include "DNSCommon.h" 105 #include "PlatformCommon.h" 106 107 #ifndef MDNSD_USER 108 #define MDNSD_USER "nobody" 109 #endif 110 111 #define CONFIG_FILE "/etc/mdnsd.conf" 112 static domainname DynDNSZone; // Default wide-area zone for service registration 113 static domainname DynDNSHostname; 114 115 #define RR_CACHE_SIZE 500 116 static CacheEntity gRRCache[RR_CACHE_SIZE]; 117 static mDNS_PlatformSupport PlatformStorage; 118 119 mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result) 120 { 121 (void)m; // Unused 122 if (result == mStatus_NoError) 123 { 124 // On successful registration of dot-local mDNS host name, daemon may want to check if 125 // any name conflict and automatic renaming took place, and if so, record the newly negotiated 126 // name in persistent storage for next time. It should also inform the user of the name change. 127 // On Mac OS X we store the current dot-local mDNS host name in the SCPreferences store, 128 // and notify the user with a CFUserNotification. 129 } 130 else if (result == mStatus_ConfigChanged) 131 { 132 udsserver_handle_configchange(m); 133 } 134 else if (result == mStatus_GrowCache) 135 { 136 // Allocate another chunk of cache storage 137 CacheEntity *storage = malloc(sizeof(CacheEntity) * RR_CACHE_SIZE); 138 if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE); 139 } 140 } 141 142 // %%% Reconfigure() probably belongs in the platform support layer (mDNSPosix.c), not the daemon cde 143 // -- all client layers running on top of mDNSPosix.c need to handle network configuration changes, 144 // not only the Unix Domain Socket Daemon 145 146 static void Reconfigure(mDNS *m) 147 { 148 mDNSAddr DynDNSIP; 149 const mDNSAddr dummy = { mDNSAddrType_IPv4, { { { 1, 1, 1, 1 } } } };; 150 mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL); 151 mDNS_Lock(m); 152 if (ParseDNSServers(m, uDNS_SERVERS_FILE) < 0) 153 LogMsg("Unable to parse DNS server list. Unicast DNS-SD unavailable"); 154 mDNS_Unlock(m); 155 ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &DynDNSHostname, &DynDNSZone, NULL); 156 mDNSPlatformSourceAddrForDest(&DynDNSIP, &dummy); 157 if (DynDNSHostname.c[0]) mDNS_AddDynDNSHostName(m, &DynDNSHostname, NULL, NULL); 158 if (DynDNSIP.type) mDNS_SetPrimaryInterfaceInfo(m, &DynDNSIP, NULL, NULL); 159 mDNS_ConfigChanged(m); 160 } 161 162 // Do appropriate things at startup with command line arguments. Calls exit() if unhappy. 163 mDNSlocal void ParseCmdLinArgs(int argc, char **argv) 164 { 165 if (argc > 1) 166 { 167 if (0 == strcmp(argv[1], "-debug")) mDNS_DebugMode = mDNStrue; 168 else printf("Usage: %s [-debug]\n", argv[0]); 169 } 170 171 if (!mDNS_DebugMode) 172 { 173 int result = daemon(0, 0); 174 if (result != 0) { LogMsg("Could not run as daemon - exiting"); exit(result); } 175 #if __APPLE__ 176 LogMsg("The POSIX mdnsd should only be used on OS X for testing - exiting"); 177 exit(-1); 178 #endif 179 } 180 } 181 182 mDNSlocal void DumpStateLog(mDNS *const m) 183 // Dump a little log of what we've been up to. 184 { 185 DNSServer *s; 186 PosixNetworkInterface *i; 187 188 LogMsg("---- BEGIN STATE LOG ----"); 189 udsserver_info(m); 190 191 LogMsgNoIdent("----- Network Interfaces -------"); 192 for (i = (PosixNetworkInterface*)(m->HostInterfaces); 193 i; i = (PosixNetworkInterface *)(i->coreIntf.next)) { 194 LogMsg("%p %p %d %s%s%s%s%s %-8s %#a", i, 195 (void *)(i->coreIntf.InterfaceID), i->index, 196 i->coreIntf.InterfaceActive ? "-" : "D", 197 i->coreIntf.IPv4Available ? "4" : "-", 198 i->coreIntf.IPv6Available ? "6" : "-", 199 i->coreIntf.Advertise ? "A" : "-", 200 i->coreIntf.McastTxRx ? "M" : "-", 201 i->intfName, &(i->coreIntf.ip)); 202 } 203 204 LogMsgNoIdent("--------- DNS Servers ----------"); 205 if (!mDNSStorage.DNSServers) LogMsgNoIdent("<None>"); 206 else 207 { 208 for (s = m->DNSServers; s; s = s->next) 209 { 210 LogMsgNoIdent("DNS Server %##s %#a:%d %s", 211 s->domain.c, &s->addr, mDNSVal16(s->port), 212 s->teststate == DNSServer_Untested ? "(Untested)" : 213 s->teststate == DNSServer_Passed ? "" : 214 s->teststate == DNSServer_Failed ? "(Failed)" : 215 s->teststate == DNSServer_Disabled ? "(Disabled)" : "(Unknown state)"); 216 } 217 } 218 219 LogMsg("---- END STATE LOG ----"); 220 } 221 222 mDNSlocal mStatus MainLoop(mDNS *m) // Loop until we quit. 223 { 224 sigset_t signals; 225 mDNSBool gotData = mDNSfalse; 226 227 mDNSPosixListenForSignalInEventLoop(SIGINT); 228 mDNSPosixListenForSignalInEventLoop(SIGTERM); 229 mDNSPosixListenForSignalInEventLoop(SIGUSR1); 230 #ifdef HAVE_SIGINFO 231 mDNSPosixListenForSignalInEventLoop(SIGUSR2); 232 mDNSPosixListenForSignalInEventLoop(SIGINFO); 233 #endif 234 mDNSPosixListenForSignalInEventLoop(SIGPIPE); 235 mDNSPosixListenForSignalInEventLoop(SIGHUP) ; 236 237 for (; ;) 238 { 239 // Work out how long we expect to sleep before the next scheduled task 240 struct timeval timeout; 241 mDNSs32 ticks; 242 243 // Only idle if we didn't find any data the last time around 244 if (!gotData) 245 { 246 mDNSs32 nextTimerEvent = mDNS_Execute(m); 247 nextTimerEvent = udsserver_idle(nextTimerEvent); 248 ticks = nextTimerEvent - mDNS_TimeNow(m); 249 if (ticks < 1) ticks = 1; 250 } 251 else // otherwise call EventLoop again with 0 timemout 252 ticks = 0; 253 254 timeout.tv_sec = ticks / mDNSPlatformOneSecond; 255 timeout.tv_usec = (ticks % mDNSPlatformOneSecond) * 1000000 / mDNSPlatformOneSecond; 256 257 (void) mDNSPosixRunEventLoopOnce(m, &timeout, &signals, &gotData); 258 259 if (sigismember(&signals, SIGHUP )) Reconfigure(m); 260 #ifdef HAVE_SIGINFO 261 /* use OSX-compatible signals since we can, and gain enhanced debugging */ 262 if (sigismember(&signals, SIGINFO)) DumpStateLog(m); 263 if (sigismember(&signals, SIGUSR1)) 264 { 265 mDNS_LoggingEnabled = mDNS_LoggingEnabled ? 0 : 1; 266 LogMsg("SIGUSR1: Logging %s", mDNS_LoggingEnabled ? "Enabled" : "Disabled"); 267 } 268 if (sigismember(&signals, SIGUSR2)) 269 { 270 mDNS_PacketLoggingEnabled = mDNS_PacketLoggingEnabled ? 0 : 1; 271 LogMsg("SIGUSR2: Packet Logging %s", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled"); 272 } 273 #else 274 if (sigismember(&signals, SIGUSR1)) DumpStateLog(m); 275 #endif 276 // SIGPIPE happens when we try to write to a dead client; death should be detected soon in request_callback() and cleaned up. 277 if (sigismember(&signals, SIGPIPE)) LogMsg("Received SIGPIPE - ignoring"); 278 if (sigismember(&signals, SIGINT) || sigismember(&signals, SIGTERM)) break; 279 } 280 return EINTR; 281 } 282 283 int main(int argc, char **argv) 284 { 285 mStatus err; 286 287 ParseCmdLinArgs(argc, argv); 288 289 LogMsg("%s starting", mDNSResponderVersionString); 290 291 err = mDNS_Init(&mDNSStorage, &PlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, 292 mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext); 293 294 if (mStatus_NoError == err) 295 err = udsserver_init(mDNSNULL, 0); 296 297 Reconfigure(&mDNSStorage); 298 299 // Now that we're finished with anything privileged, switch over to running as "nobody" 300 if (mStatus_NoError == err) 301 { 302 const struct passwd *pw = getpwnam(MDNSD_USER); 303 if (pw != NULL) 304 { 305 setgid(pw->pw_gid); 306 setuid(pw->pw_uid); 307 } 308 else 309 #ifdef MDNSD_NOROOT 310 { 311 LogMsg("WARNING: mdnsd exiting because user \""MDNSD_USER"\" does not exist"); 312 err = mStatus_Invalid; 313 } 314 #else 315 LogMsg("WARNING: mdnsd continuing as root because user \""MDNSD_USER"\" does not exist"); 316 #endif 317 } 318 319 if (mStatus_NoError == err) 320 err = MainLoop(&mDNSStorage); 321 322 LogMsg("%s stopping", mDNSResponderVersionString); 323 324 mDNS_Close(&mDNSStorage); 325 326 if (udsserver_exit() < 0) 327 LogMsg("ExitCallback: udsserver_exit failed"); 328 329 #if MDNS_DEBUGMSGS > 0 330 printf("mDNSResponder exiting normally with %ld\n", err); 331 #endif 332 333 return err; 334 } 335 336 // uds_daemon support //////////////////////////////////////////////////////////// 337 338 mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context) 339 /* Support routine for uds_daemon.c */ 340 { 341 // Depends on the fact that udsEventCallback == mDNSPosixEventCallback 342 return mDNSPosixAddFDToEventLoop(fd, callback, context); 343 } 344 345 mStatus udsSupportRemoveFDFromEventLoop(int fd) // Note: This also CLOSES the file descriptor 346 { 347 mStatus err = mDNSPosixRemoveFDFromEventLoop(fd); 348 close(fd); 349 return err; 350 } 351 352 mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay) 353 { 354 (void)m; 355 (void)delay; 356 // No-op, for now 357 } 358 359 #if _BUILDING_XCODE_PROJECT_ 360 // If the process crashes, then this string will be magically included in the automatically-generated crash log 361 const char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5; 362 asm(".desc ___crashreporter_info__, 0x10"); 363 #endif 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_SCCS[] = "@(#) mDNSResponder-" STRINGIFY(mDNSResponderVersion); 368 #elif MDNS_VERSIONSTR_NODTS 369 mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build)"; 370 #else 371 mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build)"; 372 #endif 373