Home | History | Annotate | Line # | Download | only in mDNSPosix
PosixDaemon.c revision 1.1.1.3
      1      1.1  tsarna /* -*- Mode: C; tab-width: 4 -*-
      2      1.1  tsarna  *
      3      1.1  tsarna  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
      4      1.1  tsarna  *
      5      1.1  tsarna  * Licensed under the Apache License, Version 2.0 (the "License");
      6      1.1  tsarna  * you may not use this file except in compliance with the License.
      7      1.1  tsarna  * You may obtain a copy of the License at
      8      1.1  tsarna  *
      9      1.1  tsarna  *     http://www.apache.org/licenses/LICENSE-2.0
     10      1.1  tsarna  *
     11      1.1  tsarna  * Unless required by applicable law or agreed to in writing, software
     12      1.1  tsarna  * distributed under the License is distributed on an "AS IS" BASIS,
     13      1.1  tsarna  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14      1.1  tsarna  * See the License for the specific language governing permissions and
     15      1.1  tsarna  * limitations under the License.
     16      1.1  tsarna 
     17      1.1  tsarna 	File:		daemon.c
     18      1.1  tsarna 
     19      1.1  tsarna 	Contains:	main & associated Application layer for mDNSResponder on Linux.
     20      1.1  tsarna 
     21  1.1.1.2  pettai  */
     22      1.1  tsarna 
     23  1.1.1.2  pettai #if __APPLE__
     24  1.1.1.2  pettai // In Mac OS X 10.5 and later trying to use the daemon function gives a daemon is deprecated
     25  1.1.1.2  pettai // error, which prevents compilation because we build with "-Werror".
     26  1.1.1.2  pettai // Since this is supposed to be portable cross-platform code, we don't care that daemon is
     27  1.1.1.2  pettai // deprecated on Mac OS X 10.5, so we use this preprocessor trick to eliminate the error message.
     28  1.1.1.2  pettai #define daemon yes_we_know_that_daemon_is_deprecated_in_os_x_10_5_thankyou
     29  1.1.1.2  pettai #endif
     30      1.1  tsarna 
     31      1.1  tsarna #include <stdio.h>
     32      1.1  tsarna #include <string.h>
     33      1.1  tsarna #include <unistd.h>
     34      1.1  tsarna #include <stdlib.h>
     35      1.1  tsarna #include <signal.h>
     36      1.1  tsarna #include <errno.h>
     37      1.1  tsarna #include <fcntl.h>
     38      1.1  tsarna #include <pwd.h>
     39      1.1  tsarna #include <sys/types.h>
     40      1.1  tsarna 
     41  1.1.1.2  pettai #if __APPLE__
     42  1.1.1.2  pettai #undef daemon
     43  1.1.1.2  pettai extern int daemon(int, int);
     44  1.1.1.2  pettai #endif
     45  1.1.1.2  pettai 
     46      1.1  tsarna #include "mDNSEmbeddedAPI.h"
     47      1.1  tsarna #include "mDNSPosix.h"
     48      1.1  tsarna #include "mDNSUNP.h"		// For daemon()
     49      1.1  tsarna #include "uds_daemon.h"
     50  1.1.1.3  pettai #include "DNSCommon.h"
     51      1.1  tsarna #include "PlatformCommon.h"
     52      1.1  tsarna 
     53  1.1.1.3  pettai #ifndef MDNSD_USER
     54  1.1.1.3  pettai #define MDNSD_USER "nobody"
     55  1.1.1.3  pettai #endif
     56  1.1.1.3  pettai 
     57      1.1  tsarna #define CONFIG_FILE "/etc/mdnsd.conf"
     58      1.1  tsarna static domainname DynDNSZone;                // Default wide-area zone for service registration
     59      1.1  tsarna static domainname DynDNSHostname;
     60      1.1  tsarna 
     61      1.1  tsarna #define RR_CACHE_SIZE 500
     62      1.1  tsarna static CacheEntity gRRCache[RR_CACHE_SIZE];
     63      1.1  tsarna static mDNS_PlatformSupport PlatformStorage;
     64      1.1  tsarna 
     65      1.1  tsarna mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
     66      1.1  tsarna 	{
     67      1.1  tsarna 	(void)m; // Unused
     68      1.1  tsarna 	if (result == mStatus_NoError)
     69      1.1  tsarna 		{
     70      1.1  tsarna 		// On successful registration of dot-local mDNS host name, daemon may want to check if
     71      1.1  tsarna 		// any name conflict and automatic renaming took place, and if so, record the newly negotiated
     72      1.1  tsarna 		// name in persistent storage for next time. It should also inform the user of the name change.
     73      1.1  tsarna 		// On Mac OS X we store the current dot-local mDNS host name in the SCPreferences store,
     74      1.1  tsarna 		// and notify the user with a CFUserNotification.
     75      1.1  tsarna 		}
     76      1.1  tsarna 	else if (result == mStatus_ConfigChanged)
     77      1.1  tsarna 		{
     78      1.1  tsarna 		udsserver_handle_configchange(m);
     79      1.1  tsarna 		}
     80      1.1  tsarna 	else if (result == mStatus_GrowCache)
     81      1.1  tsarna 		{
     82      1.1  tsarna 		// Allocate another chunk of cache storage
     83      1.1  tsarna 		CacheEntity *storage = malloc(sizeof(CacheEntity) * RR_CACHE_SIZE);
     84      1.1  tsarna 		if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE);
     85      1.1  tsarna 		}
     86      1.1  tsarna 	}
     87      1.1  tsarna 
     88      1.1  tsarna // %%% Reconfigure() probably belongs in the platform support layer (mDNSPosix.c), not the daemon cde
     89      1.1  tsarna // -- all client layers running on top of mDNSPosix.c need to handle network configuration changes,
     90      1.1  tsarna // not only the Unix Domain Socket Daemon
     91      1.1  tsarna 
     92      1.1  tsarna static void Reconfigure(mDNS *m)
     93      1.1  tsarna 	{
     94      1.1  tsarna 	mDNSAddr DynDNSIP;
     95      1.1  tsarna 	const mDNSAddr dummy = { mDNSAddrType_IPv4, { { { 1, 1, 1, 1 } } } };;
     96      1.1  tsarna 	mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);
     97  1.1.1.3  pettai         mDNS_Lock(m);
     98      1.1  tsarna 	if (ParseDNSServers(m, uDNS_SERVERS_FILE) < 0)
     99      1.1  tsarna 		LogMsg("Unable to parse DNS server list. Unicast DNS-SD unavailable");
    100  1.1.1.3  pettai         mDNS_Unlock(m);
    101      1.1  tsarna 	ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &DynDNSHostname, &DynDNSZone, NULL);
    102      1.1  tsarna 	mDNSPlatformSourceAddrForDest(&DynDNSIP, &dummy);
    103      1.1  tsarna 	if (DynDNSHostname.c[0]) mDNS_AddDynDNSHostName(m, &DynDNSHostname, NULL, NULL);
    104      1.1  tsarna 	if (DynDNSIP.type)       mDNS_SetPrimaryInterfaceInfo(m, &DynDNSIP, NULL, NULL);
    105      1.1  tsarna 	mDNS_ConfigChanged(m);
    106      1.1  tsarna 	}
    107      1.1  tsarna 
    108      1.1  tsarna // Do appropriate things at startup with command line arguments. Calls exit() if unhappy.
    109      1.1  tsarna mDNSlocal void ParseCmdLinArgs(int argc, char **argv)
    110      1.1  tsarna 	{
    111      1.1  tsarna 	if (argc > 1)
    112      1.1  tsarna 		{
    113      1.1  tsarna 		if (0 == strcmp(argv[1], "-debug")) mDNS_DebugMode = mDNStrue;
    114      1.1  tsarna 		else printf("Usage: %s [-debug]\n", argv[0]);
    115      1.1  tsarna 		}
    116      1.1  tsarna 
    117      1.1  tsarna 	if (!mDNS_DebugMode)
    118      1.1  tsarna 		{
    119      1.1  tsarna 		int result = daemon(0, 0);
    120      1.1  tsarna 		if (result != 0) { LogMsg("Could not run as daemon - exiting"); exit(result); }
    121      1.1  tsarna #if __APPLE__
    122      1.1  tsarna 		LogMsg("The POSIX mdnsd should only be used on OS X for testing - exiting");
    123      1.1  tsarna 		exit(-1);
    124      1.1  tsarna #endif
    125      1.1  tsarna 		}
    126      1.1  tsarna 	}
    127      1.1  tsarna 
    128      1.1  tsarna mDNSlocal void DumpStateLog(mDNS *const m)
    129      1.1  tsarna // Dump a little log of what we've been up to.
    130      1.1  tsarna 	{
    131  1.1.1.3  pettai 	DNSServer *s;
    132  1.1.1.3  pettai         PosixNetworkInterface *i;
    133  1.1.1.3  pettai 
    134      1.1  tsarna 	LogMsg("---- BEGIN STATE LOG ----");
    135      1.1  tsarna 	udsserver_info(m);
    136  1.1.1.3  pettai 
    137  1.1.1.3  pettai         LogMsgNoIdent("----- Network Interfaces -------");
    138  1.1.1.3  pettai         for (i = (PosixNetworkInterface*)(m->HostInterfaces);
    139  1.1.1.3  pettai         i; i = (PosixNetworkInterface *)(i->coreIntf.next)) {
    140  1.1.1.3  pettai             LogMsg("%p %p %d %s%s%s%s%s %-8s %#a", i,
    141  1.1.1.3  pettai             (void *)(i->coreIntf.InterfaceID), i->index,
    142  1.1.1.3  pettai             i->coreIntf.InterfaceActive ? "-" : "D",
    143  1.1.1.3  pettai             i->coreIntf.IPv4Available ? "4" : "-",
    144  1.1.1.3  pettai             i->coreIntf.IPv6Available ? "6" : "-",
    145  1.1.1.3  pettai             i->coreIntf.Advertise ? "A" : "-",
    146  1.1.1.3  pettai             i->coreIntf.McastTxRx ? "M" : "-",
    147  1.1.1.3  pettai             i->intfName, &(i->coreIntf.ip));
    148  1.1.1.3  pettai         }
    149  1.1.1.3  pettai 
    150  1.1.1.3  pettai         LogMsgNoIdent("--------- DNS Servers ----------");
    151  1.1.1.3  pettai         if (!mDNSStorage.DNSServers) LogMsgNoIdent("<None>");
    152  1.1.1.3  pettai         else
    153  1.1.1.3  pettai                 {
    154  1.1.1.3  pettai                 for (s = m->DNSServers; s; s = s->next)
    155  1.1.1.3  pettai                         {
    156  1.1.1.3  pettai                         LogMsgNoIdent("DNS Server %##s %#a:%d %s",
    157  1.1.1.3  pettai                                 s->domain.c, &s->addr, mDNSVal16(s->port),
    158  1.1.1.3  pettai                                 s->teststate == DNSServer_Untested ? "(Untested)" :
    159  1.1.1.3  pettai                                 s->teststate == DNSServer_Passed   ? ""           :
    160  1.1.1.3  pettai                                 s->teststate == DNSServer_Failed   ? "(Failed)"   :
    161  1.1.1.3  pettai                                 s->teststate == DNSServer_Disabled ? "(Disabled)" : "(Unknown state)");
    162  1.1.1.3  pettai                         }
    163  1.1.1.3  pettai                 }
    164  1.1.1.3  pettai 
    165      1.1  tsarna 	LogMsg("----  END STATE LOG  ----");
    166      1.1  tsarna 	}
    167      1.1  tsarna 
    168      1.1  tsarna mDNSlocal mStatus MainLoop(mDNS *m) // Loop until we quit.
    169      1.1  tsarna 	{
    170      1.1  tsarna 	sigset_t	signals;
    171      1.1  tsarna 	mDNSBool	gotData = mDNSfalse;
    172      1.1  tsarna 
    173      1.1  tsarna 	mDNSPosixListenForSignalInEventLoop(SIGINT);
    174      1.1  tsarna 	mDNSPosixListenForSignalInEventLoop(SIGTERM);
    175      1.1  tsarna 	mDNSPosixListenForSignalInEventLoop(SIGUSR1);
    176  1.1.1.3  pettai #ifdef HAVE_SIGINFO
    177  1.1.1.3  pettai 	mDNSPosixListenForSignalInEventLoop(SIGUSR2);
    178  1.1.1.3  pettai 	mDNSPosixListenForSignalInEventLoop(SIGINFO);
    179  1.1.1.3  pettai #endif
    180      1.1  tsarna 	mDNSPosixListenForSignalInEventLoop(SIGPIPE);
    181      1.1  tsarna 	mDNSPosixListenForSignalInEventLoop(SIGHUP) ;
    182      1.1  tsarna 
    183      1.1  tsarna 	for (; ;)
    184      1.1  tsarna 		{
    185      1.1  tsarna 		// Work out how long we expect to sleep before the next scheduled task
    186      1.1  tsarna 		struct timeval	timeout;
    187      1.1  tsarna 		mDNSs32			ticks;
    188      1.1  tsarna 
    189      1.1  tsarna 		// Only idle if we didn't find any data the last time around
    190      1.1  tsarna 		if (!gotData)
    191      1.1  tsarna 			{
    192      1.1  tsarna 			mDNSs32			nextTimerEvent = mDNS_Execute(m);
    193      1.1  tsarna 			nextTimerEvent = udsserver_idle(nextTimerEvent);
    194      1.1  tsarna 			ticks = nextTimerEvent - mDNS_TimeNow(m);
    195      1.1  tsarna 			if (ticks < 1) ticks = 1;
    196      1.1  tsarna 			}
    197      1.1  tsarna 		else	// otherwise call EventLoop again with 0 timemout
    198      1.1  tsarna 			ticks = 0;
    199      1.1  tsarna 
    200      1.1  tsarna 		timeout.tv_sec = ticks / mDNSPlatformOneSecond;
    201      1.1  tsarna 		timeout.tv_usec = (ticks % mDNSPlatformOneSecond) * 1000000 / mDNSPlatformOneSecond;
    202      1.1  tsarna 
    203      1.1  tsarna 		(void) mDNSPosixRunEventLoopOnce(m, &timeout, &signals, &gotData);
    204      1.1  tsarna 
    205      1.1  tsarna 		if (sigismember(&signals, SIGHUP )) Reconfigure(m);
    206  1.1.1.3  pettai #ifdef HAVE_SIGINFO
    207  1.1.1.3  pettai                 /* use OSX-compatible signals since we can, and gain enhanced debugging */
    208  1.1.1.3  pettai 		if (sigismember(&signals, SIGINFO)) DumpStateLog(m);
    209  1.1.1.3  pettai 		if (sigismember(&signals, SIGUSR1))
    210  1.1.1.3  pettai 			{
    211  1.1.1.3  pettai 		        mDNS_LoggingEnabled = mDNS_LoggingEnabled ? 0 : 1;
    212  1.1.1.3  pettai 		        LogMsg("SIGUSR1: Logging %s", mDNS_LoggingEnabled ? "Enabled" : "Disabled");
    213  1.1.1.3  pettai 			}
    214  1.1.1.3  pettai 		if (sigismember(&signals, SIGUSR2))
    215  1.1.1.3  pettai 			{
    216  1.1.1.3  pettai 			mDNS_PacketLoggingEnabled = mDNS_PacketLoggingEnabled ? 0 : 1;
    217  1.1.1.3  pettai 			LogMsg("SIGUSR2: Packet Logging %s", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled");
    218  1.1.1.3  pettai 			}
    219  1.1.1.3  pettai #else
    220      1.1  tsarna 		if (sigismember(&signals, SIGUSR1)) DumpStateLog(m);
    221  1.1.1.3  pettai #endif
    222      1.1  tsarna 		// SIGPIPE happens when we try to write to a dead client; death should be detected soon in request_callback() and cleaned up.
    223      1.1  tsarna 		if (sigismember(&signals, SIGPIPE)) LogMsg("Received SIGPIPE - ignoring");
    224      1.1  tsarna 		if (sigismember(&signals, SIGINT) || sigismember(&signals, SIGTERM)) break;
    225      1.1  tsarna 		}
    226      1.1  tsarna 	return EINTR;
    227      1.1  tsarna 	}
    228      1.1  tsarna 
    229      1.1  tsarna int main(int argc, char **argv)
    230      1.1  tsarna 	{
    231      1.1  tsarna 	mStatus					err;
    232      1.1  tsarna 
    233      1.1  tsarna 	ParseCmdLinArgs(argc, argv);
    234      1.1  tsarna 
    235      1.1  tsarna 	LogMsg("%s starting", mDNSResponderVersionString);
    236      1.1  tsarna 
    237      1.1  tsarna 	err = mDNS_Init(&mDNSStorage, &PlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses,
    238      1.1  tsarna 					mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext);
    239      1.1  tsarna 
    240      1.1  tsarna 	if (mStatus_NoError == err)
    241      1.1  tsarna 		err = udsserver_init(mDNSNULL, 0);
    242      1.1  tsarna 
    243      1.1  tsarna 	Reconfigure(&mDNSStorage);
    244      1.1  tsarna 
    245      1.1  tsarna 	// Now that we're finished with anything privileged, switch over to running as "nobody"
    246      1.1  tsarna 	if (mStatus_NoError == err)
    247      1.1  tsarna 		{
    248  1.1.1.3  pettai 		const struct passwd *pw = getpwnam(MDNSD_USER);
    249      1.1  tsarna 		if (pw != NULL)
    250  1.1.1.3  pettai 		        {
    251  1.1.1.3  pettai 			setgid(pw->pw_gid);
    252      1.1  tsarna 			setuid(pw->pw_uid);
    253  1.1.1.3  pettai 		        }
    254      1.1  tsarna 		else
    255  1.1.1.3  pettai #ifdef MDNSD_NOROOT
    256  1.1.1.3  pettai                         {
    257  1.1.1.3  pettai     			LogMsg("WARNING: mdnsd exiting because user \""MDNSD_USER"\" does not exist");
    258  1.1.1.3  pettai                         err = mStatus_Invalid;
    259  1.1.1.3  pettai                         }
    260  1.1.1.3  pettai #else
    261  1.1.1.3  pettai     			LogMsg("WARNING: mdnsd continuing as root because user \""MDNSD_USER"\" does not exist");
    262  1.1.1.3  pettai #endif
    263      1.1  tsarna 		}
    264      1.1  tsarna 
    265      1.1  tsarna 	if (mStatus_NoError == err)
    266      1.1  tsarna 		err = MainLoop(&mDNSStorage);
    267      1.1  tsarna 
    268      1.1  tsarna 	LogMsg("%s stopping", mDNSResponderVersionString);
    269      1.1  tsarna 
    270      1.1  tsarna 	mDNS_Close(&mDNSStorage);
    271      1.1  tsarna 
    272      1.1  tsarna 	if (udsserver_exit() < 0)
    273      1.1  tsarna 		LogMsg("ExitCallback: udsserver_exit failed");
    274      1.1  tsarna 
    275      1.1  tsarna  #if MDNS_DEBUGMSGS > 0
    276      1.1  tsarna 	printf("mDNSResponder exiting normally with %ld\n", err);
    277      1.1  tsarna  #endif
    278      1.1  tsarna 
    279      1.1  tsarna 	return err;
    280      1.1  tsarna 	}
    281      1.1  tsarna 
    282      1.1  tsarna //		uds_daemon support		////////////////////////////////////////////////////////////
    283      1.1  tsarna 
    284  1.1.1.2  pettai mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context, void **platform_data)
    285      1.1  tsarna /* Support routine for uds_daemon.c */
    286      1.1  tsarna 	{
    287      1.1  tsarna 	// Depends on the fact that udsEventCallback == mDNSPosixEventCallback
    288  1.1.1.2  pettai 	(void) platform_data;
    289      1.1  tsarna 	return mDNSPosixAddFDToEventLoop(fd, callback, context);
    290      1.1  tsarna 	}
    291      1.1  tsarna 
    292  1.1.1.2  pettai int udsSupportReadFD(dnssd_sock_t fd, char *buf, int len, int flags, void *platform_data)
    293  1.1.1.2  pettai 	{
    294  1.1.1.2  pettai 	(void) platform_data;
    295  1.1.1.2  pettai 	return recv(fd, buf, len, flags);
    296  1.1.1.2  pettai 	}
    297  1.1.1.2  pettai 
    298  1.1.1.2  pettai mStatus udsSupportRemoveFDFromEventLoop(int fd, void *platform_data)		// Note: This also CLOSES the file descriptor
    299      1.1  tsarna 	{
    300      1.1  tsarna 	mStatus err = mDNSPosixRemoveFDFromEventLoop(fd);
    301  1.1.1.2  pettai 	(void) platform_data;
    302      1.1  tsarna 	close(fd);
    303      1.1  tsarna 	return err;
    304      1.1  tsarna 	}
    305      1.1  tsarna 
    306      1.1  tsarna mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
    307      1.1  tsarna 	{
    308      1.1  tsarna 	(void)m;
    309      1.1  tsarna 	(void)delay;
    310      1.1  tsarna 	// No-op, for now
    311      1.1  tsarna 	}
    312      1.1  tsarna 
    313      1.1  tsarna #if _BUILDING_XCODE_PROJECT_
    314      1.1  tsarna // If the process crashes, then this string will be magically included in the automatically-generated crash log
    315      1.1  tsarna const char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5;
    316      1.1  tsarna asm(".desc ___crashreporter_info__, 0x10");
    317      1.1  tsarna #endif
    318      1.1  tsarna 
    319      1.1  tsarna // For convenience when using the "strings" command, this is the last thing in the file
    320      1.1  tsarna #if mDNSResponderVersion > 1
    321  1.1.1.3  pettai mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder-" STRINGIFY(mDNSResponderVersion);
    322      1.1  tsarna #elif MDNS_VERSIONSTR_NODTS
    323      1.1  tsarna mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build)";
    324      1.1  tsarna #else
    325  1.1.1.3  pettai mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build)";
    326      1.1  tsarna #endif
    327