uds_daemon.c revision 4b22b9337f359bfd063322244f5336cc7c6ffcfa
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2003-2006 Apple Computer, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
Change History (most recent first):
$Log: uds_daemon.c,v $
Revision 1.201.2.1 2006/08/29 06:24:36 cheshire
Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
Revision 1.201 2006/06/29 03:02:47 cheshire
<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
Revision 1.200 2006/06/28 08:56:26 cheshire
Added "_op" to the end of the operation code enum values,
to differentiate them from the routines with the same names
Revision 1.199 2006/06/28 08:53:39 cheshire
Added (commented out) debugging messages
Revision 1.198 2006/06/27 20:16:07 cheshire
Fix code layout
Revision 1.197 2006/05/18 01:32:35 cheshire
<rdar://problem/4472706> iChat: Lost connection with Bonjour
(mDNSResponder insufficiently defensive against malformed browsing PTR responses)
Revision 1.196 2006/05/05 07:07:13 cheshire
<rdar://problem/4538206> mDNSResponder fails when UDS reads deliver partial data
Revision 1.195 2006/04/25 20:56:28 mkrochma
Added comment about previous checkin
Revision 1.194 2006/04/25 18:29:36 mkrochma
Workaround for warning: unused variable 'status' when building mDNSPosix
Revision 1.193 2006/03/19 17:14:38 cheshire
<rdar://problem/4483117> Need faster purging of stale records
read_rr_from_ipc_msg was not setting namehash and rdatahash
Revision 1.192 2006/03/18 20:58:32 cheshire
Misplaced curly brace
Revision 1.191 2006/03/10 22:19:43 cheshire
Update debugging message in resolve_result_callback() to indicate whether event is ADD or RMV
Revision 1.190 2006/03/10 21:56:12 cheshire
<rdar://problem/4111464> After record update, old record sometimes remains in cache
When service TXT and SRV record both change, clients with active resolve calls get *two* callbacks, one
when the TXT data changes, and then immediately afterwards a second callback with the new port number
This change suppresses the first unneccessary (and confusing) callback
Revision 1.189 2006/01/06 00:56:31 cheshire
<rdar://problem/4400573> Should remove PID file on exit
Revision 1.188 2005/10/11 22:15:03 cheshire
<rdar://problem/4296042> Add memory corruption safeguards to uds_daemon.c
Only compile uds_validatelists() when building for Mac OS X
Revision 1.187 2005/10/11 20:30:27 cheshire
<rdar://problem/4296042> Add memory corruption safeguards to uds_daemon.c
Revision 1.186 2005/09/12 07:11:53 herscher
<rdar://problem/4248878> Lazily call RegisterSearchDomains to workaround crashes of several routers. This code is conditionally compiled, and currently is only enabled on Windows platforms.
Revision 1.185 2005/07/29 00:55:10 ksekar
Removed validation check in uds_validatelists which generated false alarms
Revision 1.184 2005/07/04 22:40:26 cheshire
Additional debugging code to help catch memory corruption
Revision 1.183 2005/06/13 22:39:11 cheshire
<rdar://problem/4144870> Missing return statement in handle_enum_request() error handling
Revision 1.182 2005/03/21 00:39:31 shersche
<rdar://problem/4021486> Fix build warnings on Win32 platform
Revision 1.181 2005/03/20 20:21:32 shersche
<rdar://problem/4056827> mDNSResponder crashes when incorrect interface index is passed to DNSServiceRegister()
Text record length and data parameters must be initialized to 0 and NULL to ensure that the service request
object is cleaned up correctly when encountering an interface index error.
Revision 1.180 2005/03/10 00:13:12 cheshire
<rdar://problem/4043098> DNSServiceBrowse no longer returning error codes for invalid types
In handle_browse_request(), mStatus err was being set correctly if an error occurred,
but the end of the function returned mStatus_NoError intead of err.
Revision 1.179 2005/03/04 02:47:26 ksekar
<rdar://problem/4026393> SCPreference domains disappear from enumeration when moving out from firewall
Revision 1.178 2005/02/25 19:35:38 ksekar
<rdar://problem/4023750> Non-local empty string registration failures should not return errors to caller
Revision 1.177 2005/02/25 03:05:41 cheshire
Change "broken pipe" message to debugf()
Revision 1.176 2005/02/24 18:44:45 ksekar
<rdar://problem/4018516> Printer Sharing does not get re-registered with wide-area
Revision 1.175 2005/02/21 21:31:25 ksekar
<rdar://problem/4015162> changed LogMsg to debugf
Revision 1.174 2005/02/20 01:41:17 cheshire
Revision 1.173 2005/02/18 01:26:42 cheshire
<rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
Log additional information about failed client
Revision 1.172 2005/02/18 00:58:35 cheshire
<rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
Revision 1.171 2005/02/18 00:43:12 cheshire
<rdar://problem/4010245> mDNSResponder should auto-truncate service names that are too long
Revision 1.170 2005/02/16 01:15:02 cheshire
Improve LogOperation() debugging messages for DNSServiceBrowse and DNSServiceRegister
Revision 1.169 2005/02/08 01:57:14 cheshire
More detailed error reporting in udsserver_init()
Revision 1.168 2005/02/03 00:44:37 cheshire
<rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
Revision 1.167 2005/02/02 02:19:32 cheshire
Add comment explaining why unlink(MDNS_UDS_SERVERPATH); fails
Revision 1.166 2005/02/01 19:58:52 ksekar
Shortened cryptic "broken pipe" syslog message
Revision 1.165 2005/02/01 19:56:47 ksekar
Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording
Revision 1.164 2005/01/28 06:07:55 cheshire
Don't use deliver_error() from within handle_regrecord_request()
Revision 1.163 2005/01/28 01:39:16 cheshire
Include file descriptor number in "broken pipe" message
Revision 1.162 2005/01/27 23:59:20 cheshire
Remove extraneous LogMsg
Revision 1.161 2005/01/27 22:57:56 cheshire
Fix compile errors on gcc4
Revision 1.160 2005/01/27 20:52:11 cheshire
Revision 1.159 2005/01/27 01:45:25 cheshire
<rdar://problem/3976147> mDNSResponder should never call exit(1);
Revision 1.158 2005/01/25 17:28:07 ksekar
<rdar://problem/3971467> Should not return "local" twice for domain enumeration
Revision 1.157 2005/01/21 02:20:39 cheshire
Fix mistake in LogOperation() format string
Revision 1.156 2005/01/19 19:15:36 ksekar
Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
Revision 1.155 2005/01/19 03:00:47 cheshire
Revision 1.154 2005/01/15 00:56:42 ksekar
<rdar://problem/3954575> Unicast services don't disappear when logging
out of VPN
Revision 1.153 2005/01/14 18:44:28 ksekar
<rdar://problem/3954609> mDNSResponder is crashing when changing domains
Revision 1.152 2005/01/13 17:16:38 ksekar
Back out checkin 1.150 - correct fix is on clientstub side
Revision 1.151 2005/01/11 21:06:29 ksekar
Changed now-benign LogMsg to debugf
Revision 1.150 2005/01/07 23:59:15 ksekar
<rdar://problem/3942900> dnd-sd shows the wrong port numbers
Revision 1.149 2004/12/20 23:20:35 cheshire
<rdar://problem/3928361> mDNSResponder crashes repeatedly when printer sharing is enabled
Make sure to call mDNS_SetupResourceRecord() for all newly created AuthRecords
Revision 1.148 2004/12/20 20:37:35 cheshire
AllowRemoteQuery not set for the extras in a ServiceRecordSet
Revision 1.147 2004/12/20 00:15:41 cheshire
Include client file descriptor numbers in udsserver_info() output
Revision 1.146 2004/12/17 05:25:47 cheshire
<rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
Revision 1.145 2004/12/16 21:39:46 cheshire
Include CacheGroup objects in CacheUsed count
Revision 1.144 2004/12/16 21:27:38 ksekar
Fixed build failures when compiled with verbose debugging messages
Revision 1.143 2004/12/16 20:13:02 cheshire
<rdar://problem/3324626> Cache memory management improvements
Revision 1.142 2004/12/16 08:07:33 shersche
Fix compiler error (mixed declarations and code) on Windows
Revision 1.141 2004/12/16 01:56:21 cheshire
Improve DNSServiceEnumerateDomains syslog message
Revision 1.140 2004/12/14 03:02:10 ksekar
<rdar://problem/3919016> Rare race condition can cause crash
Revision 1.139 2004/12/13 21:18:45 ksekar
Include uDNS registrations in CountPeerRegistrations
Revision 1.138 2004/12/13 18:23:18 ksekar
<rdar://problem/3915805> mDNSResponder error when quitting iChat -
don't close sockets delivering errors to blocked clients
Revision 1.137 2004/12/13 00:09:22 ksekar
<rdar://problem/3915805> mDNSResponder error when quitting iChat
Revision 1.136 2004/12/11 01:52:10 cheshire
<rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
Revision 1.135 2004/12/10 20:46:37 cheshire
Change LogOperation message to debugf
Revision 1.134 2004/12/10 13:19:37 cheshire
Add verbosedebugf() logging message in CountPeerRegistrations()
Revision 1.133 2004/12/10 05:27:26 cheshire
<rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
Revision 1.132 2004/12/10 04:28:28 cheshire
<rdar://problem/3914406> User not notified of name changes for services using new UDS API
Revision 1.131 2004/12/10 02:09:25 cheshire
<rdar://problem/3898376> Modify default TTLs
Revision 1.130 2004/12/10 00:55:24 cheshire
Add full name and type to LogOperation messages for DNSServiceAddRecord/UpdateRecord/RemoveRecord
Revision 1.129 2004/12/09 03:17:23 ksekar
<rdar://problem/3910435> DomainEnumeration interface index should be zero
Revision 1.128 2004/12/07 21:26:05 ksekar
<rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
Revision 1.127 2004/12/07 20:42:34 cheshire
Add explicit context parameter to mDNS_RemoveRecordFromService()
Revision 1.126 2004/12/07 17:23:55 ksekar
Fixed LogOperation
Revision 1.125 2004/12/06 21:15:23 ksekar
<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
Revision 1.124 2004/11/30 02:19:14 cheshire
<rdar://problem/3827971> Raise maxfds.rlim_cur for mDNSResponder
Revision 1.123 2004/11/29 23:50:57 cheshire
Checkin 1.122 not necessary
Revision 1.122 2004/11/24 17:55:01 ksekar
Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
Revision 1.121 2004/11/24 04:45:52 cheshire
Spelling mistake
Revision 1.120 2004/11/24 00:10:44 cheshire
<rdar://problem/3869241> For unicast operations, verify that service types are legal
Revision 1.119 2004/11/23 23:54:17 ksekar
<rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
can crash mDNSResponder
Revision 1.118 2004/11/23 22:33:01 cheshire
<rdar://problem/3654910> Remove temporary workaround code for iChat
Revision 1.117 2004/11/23 20:23:10 ksekar
Fixed LogOperation that causes crash on connected service deregistrations
Revision 1.116 2004/11/23 03:39:47 cheshire
Let interface name/index mapping capability live directly in JNISupport.c,
instead of having to call through to the daemon via IPC to get this information.
Revision 1.115 2004/11/13 00:12:53 ksekar
Fixed some LogOperation printf converstions for debug builds.
Revision 1.114 2004/11/12 18:25:45 shersche
Tidy up cross platform usleep code fragment.
Revision 1.113 2004/11/12 03:21:41 rpantos
rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
Revision 1.112 2004/11/11 16:58:32 ksekar
Removed unused code (previously wrapped in #if 0)
Revision 1.111 2004/11/05 22:47:37 shersche
Conditionally compile usleep(1000) to be Sleep(1) on Windows
Submitted by: Pavel Repin <prepin@gmail.com>
Revision 1.110 2004/11/05 19:56:56 ksekar
<rdar://problem/3862646> We no longer need to browse .Mac domains by
default - changed #if 0 to more descriptive #ifdef _HAVE_SETDOMAIN_SUPPORT_
Revision 1.109 2004/11/04 03:40:45 cheshire
More debugging messages
Revision 1.108 2004/11/03 02:25:51 cheshire
<rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
Revision 1.107 2004/11/02 19:39:23 ksekar
<rdar://problem/3862646> We no longer need to browse .Mac domains by default
Revision 1.106 2004/11/02 02:12:21 cheshire
<rdar://problem/3839111> Remove unnecessary memory allocations
Revision 1.105 2004/10/28 19:07:19 cheshire
Add some more debugging checks and improved LogOperation() messages
Revision 1.104 2004/10/26 18:53:15 cheshire
Avoid unused variable warning
Revision 1.103 2004/10/26 07:15:55 cheshire
Add file descriptor number to all LogOperation messages
Revision 1.102 2004/10/26 06:11:42 cheshire
Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
Revision 1.101 2004/10/26 04:31:44 cheshire
Rename CountSubTypes() as ChopSubTypes()
Revision 1.100 2004/10/26 01:17:48 cheshire
Use "#if 0" instead of commenting out code
Revision 1.99 2004/10/19 21:33:22 cheshire
<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
Revision 1.98 2004/10/14 01:59:33 cheshire
<rdar://problem/3839208> UDS resolves don't work for uDNS services
Revision 1.97 2004/10/13 00:58:35 cheshire
<rdar://problem/3832738> Registering a proxy doesn't work
Revision 1.96 2004/09/30 00:25:00 ksekar
<rdar://problem/3695802> Dynamically update default registration domains on config change
Revision 1.95 2004/09/26 23:20:36 ksekar
<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
Revision 1.94 2004/09/22 18:27:06 ksekar
<rdar://problem/3811427> allow DNSServiceAddRecord to pass zero to get
default record TTL
Revision 1.93 2004/09/22 02:39:44 cheshire
<rdar://problem/3810757> Allow DNSServiceRegisterRecord to pass zero to get default record TTL
Revision 1.92 2004/09/22 02:34:04 cheshire
Rename parameter "ttl" to "GetTTL" for clarity
Revision 1.91 2004/09/22 02:25:43 cheshire
Fix spelling errors
Revision 1.90 2004/09/21 23:40:12 ksekar
<rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
Revision 1.89 2004/09/21 23:29:51 cheshire
<rdar://problem/3680045> DNSServiceResolve should delay sending packets
Revision 1.88 2004/09/21 23:12:46 cheshire
Reorder initialization of question fields to match structure order
Revision 1.87 2004/09/21 22:18:33 cheshire
In SIGINFO output, display a '-' next to records that have the Unique bit set
Revision 1.86 2004/09/21 21:05:11 cheshire
Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
into mDNSShared/uds_daemon.c
Revision 1.85 2004/09/18 01:11:58 ksekar
<rdar://problem/3806734> Add a user's default domain to empty-string browse list
Revision 1.84 2004/09/17 01:08:55 cheshire
Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
declared in that file are ONLY appropriate to single-address-space embedded applications.
For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
Revision 1.83 2004/09/16 23:26:33 cheshire
Move version check inside preceeding "if" that checks we have a complete header
Revision 1.82 2004/09/16 23:14:25 cheshire
Changes for Windows compatibility
Revision 1.81 2004/09/16 21:46:38 ksekar
<rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area domain
Revision 1.80 2004/09/16 01:58:23 cheshire
Fix compiler warnings
Revision 1.79 2004/09/16 00:24:49 cheshire
<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
Revision 1.78 2004/09/15 21:44:20 cheshire
<rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
Show time value in log to help diagnose errors
Revision 1.77 2004/09/15 00:19:18 cheshire
<rdar://problem/3785823> read_rr_from_ipc_msg should use mDNS_SetupResourceRecord()
Revision 1.76 2004/09/02 06:39:52 cheshire
Minor textual cleanup for clarity
Revision 1.75 2004/09/02 03:48:47 cheshire
<rdar://problem/3709039> Disable targeted unicast query support by default
1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
2. New field AllowRemoteQuery in AuthRecord structure
3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
4. mDNS.c only answers remote queries if AllowRemoteQuery is set
Revision 1.74 2004/08/25 02:32:47 cheshire
Minor cleanup: replace "®type[0]" with "regtype"
Revision 1.73 2004/08/25 02:30:40 cheshire
<rdar://problem/3588761> Current method of doing subtypes causes name collisions
Revision 1.72 2004/08/14 03:22:42 cheshire
<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
Add GetUserSpecifiedDDNSName() routine
Convert ServiceRegDomain to domainname instead of C string
Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
Revision 1.71 2004/08/11 04:21:21 rpantos
Fix Windows build.
Revision 1.70 2004/08/11 02:07:00 cheshire
Remove "mDNS *globalInstance" parameter from udsserver_init()
Move CheckForDuplicateRegistrations from daemon.c
<rdar://problem/3501938> No warning when accidentally registering the same service multiple times using socket API
Revision 1.69 2004/08/10 16:14:48 cheshire
Fix debug builds (oops)
Revision 1.68 2004/08/10 06:24:56 cheshire
Use types with precisely defined sizes for 'op' and 'reg_index', for better
compatibility if the daemon and the client stub are built using different compilers
Revision 1.67 2004/07/27 07:14:16 shersche
make error socket non-blocking after call to connect()
Revision 1.66 2004/07/13 21:24:25 rpantos
Fix for <rdar://problem/3701120>.
Revision 1.65 2004/06/26 03:17:14 shersche
implement cross-platform strerror function
Submitted by: herscher
Revision 1.64 2004/06/25 00:26:27 rpantos
Changes to fix the Posix build on Solaris.
Revision 1.63 2004/06/24 03:43:44 rpantos
Fix previous checkin so it builds on Windows.
Revision 1.62 2004/06/24 00:57:08 ksekar
Replaced code acccidentally removed in checkin 1.59.
Revision 1.61 2004/06/19 00:09:39 cheshire
Remove unused strsep() implementation
Revision 1.60 2004/06/18 19:10:00 cheshire
<rdar://problem/3588761> Current method of doing subtypes causes name collisions
Revision 1.59 2004/06/18 05:10:31 rpantos
Changes to allow code to be used on Windows
Revision 1.58 2004/06/15 03:54:08 cheshire
Include mDNS_TimeNow(&mDNSStorage) in SIGINFO output
Revision 1.57 2004/06/12 01:47:27 ksekar
<rdar://problem/3690241>: BBEdit crashes when trying to check for newer version
udsserver_idle compared time in ticks to interval in seconds.
Revision 1.56 2004/06/12 01:35:47 cheshire
Changes for Windows compatibility
Revision 1.55 2004/06/05 00:04:27 cheshire
<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
Revision 1.54 2004/06/01 22:22:52 ksekar
<rdar://problem/3668635>: wide-area default registrations should be in
.local too
Revision 1.53 2004/05/28 23:42:37 ksekar
<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
Revision 1.52 2004/05/26 00:39:49 ksekar
<rdar://problem/3667105>: wide-area DNS-SD servers don't appear in
Finder
Use local-only InterfaceID for GetDomains calls for sockets-API
Revision 1.51 2004/05/18 23:51:27 cheshire
Revision 1.50 2004/05/14 16:39:47 ksekar
Browse for iChat locally for now.
Revision 1.49 2004/05/13 21:33:52 ksekar
Clean up non-local registration control via config file. Force iChat
registrations to be local for now.
Revision 1.48 2004/05/13 04:13:19 ksekar
Updated SIGINFO handler for multi-domain browses
Revision 1.47 2004/05/12 22:04:01 ksekar
Implemented multi-domain browsing by default for uds_daemon.
Revision 1.46 2004/05/06 18:42:58 ksekar
General dns_sd.h API cleanup, including the following radars:
<rdar://problem/3592068>: Remove flags with zero value
<rdar://problem/3479569>: Passing in NULL causes a crash.
Revision 1.45 2004/03/12 08:49:28 cheshire
Revision 1.44 2004/02/25 01:25:27 ksekar
<rdar://problem/3569212>: DNSServiceRegisterRecord flags not error-checked
Revision 1.43 2004/02/24 01:46:40 cheshire
Manually reinstate lost checkin 1.36
Revision 1.42 2004/02/05 19:39:29 cheshire
Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
so that all platforms get this functionality
Revision 1.41 2004/02/03 18:59:02 cheshire
Change "char *domain" parameter for format_enumeration_reply to "const char *domain"
Revision 1.40 2004/01/28 03:41:00 cheshire
<rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
Revision 1.39 2004/01/25 00:03:21 cheshire
Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
Revision 1.38 2004/01/19 19:51:46 cheshire
Fix compiler error (mixed declarations and code) on some versions of Linux
Revision 1.37 2003/12/08 21:11:42 rpantos
Changes necessary to support mDNSResponder on Linux.
Revision 1.36 2003/12/04 23:40:57 cheshire
<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
Fix some more code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
Revision 1.35 2003/12/03 19:10:22 ksekar
<rdar://problem/3498644>: malloc'd data not zero'd
Revision 1.34 2003/12/03 02:00:01 ksekar
<rdar://problem/3498644>: malloc'd data not zero'd
Revision 1.33 2003/11/22 01:18:46 ksekar
<rdar://problem/3486646>: config change handler not called for dns-sd services
Revision 1.32 2003/11/20 21:46:12 ksekar
<rdar://problem/3486635>: leak: DNSServiceRegisterRecord
Revision 1.31 2003/11/20 20:33:05 ksekar
<rdar://problem/3486635>: leak: DNSServiceRegisterRecord
Revision 1.30 2003/11/20 02:10:55 ksekar
<rdar://problem/3486643>: cleanup DNSServiceAdd/RemoveRecord
Revision 1.29 2003/11/14 21:18:32 cheshire
<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
Revision 1.28 2003/11/08 22:18:29 cheshire
<rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
Revision 1.27 2003/11/05 22:44:57 ksekar
<rdar://problem/3335230>: No bounds checking when reading data from client
Reviewed by: Stuart Cheshire
Revision 1.26 2003/10/23 17:51:04 ksekar
<rdar://problem/3335216>: handle blocked clients more efficiently
Changed gettimeofday() to mDNS_TimeNow(&mDNSStorage);
Revision 1.25 2003/10/22 23:37:49 ksekar
Revision 1.24 2003/10/21 20:59:40 ksekar
<rdar://problem/3335216>: handle blocked clients more efficiently
Revision 1.23 2003/09/23 02:12:43 cheshire
Also include port number in list of services registered via new UDS API
Revision 1.22 2003/08/19 16:03:55 ksekar
<rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
Check termination_context for NULL before dereferencing.
Revision 1.21 2003/08/19 05:39:43 cheshire
<rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
Revision 1.20 2003/08/16 03:39:01 cheshire
<rdar://problem/3338440> InterfaceID -1 indicates "local only"
Revision 1.19 2003/08/15 20:16:03 cheshire
<rdar://problem/3366590> mDNSResponder takes too much RPRVT
We want to avoid touching the rdata pages, so we don't page them in.
1. RDLength was stored with the rdata, which meant touching the page just to find the length.
Moved this from the RData to the ResourceRecord object.
2. To avoid unnecessarily touching the rdata just to compare it,
compute a hash of the rdata and store the hash in the ResourceRecord object.
Revision 1.18 2003/08/15 00:38:00 ksekar
<rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
Revision 1.17 2003/08/14 02:18:21 cheshire
<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
Revision 1.16 2003/08/13 23:58:52 ksekar
<rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
Revision 1.15 2003/08/13 17:30:33 ksekar
<rdar://problem/3374671>: DNSServiceAddRecord doesn't work
Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
Revision 1.14 2003/08/12 19:56:25 cheshire
Update to APSL 2.0
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#if defined(_WIN32)
#include <process.h>
#define dnssd_strerror(X) win32_strerror(X)
static char * win32_strerror(int inErrorCode);
#else
#include <fcntl.h>
#include <errno.h>
#include <sys/resource.h>
#define dnssd_strerror(X) strerror(X)
#endif
#include <stdlib.h>
#include <stdio.h>
#include "mDNSEmbeddedAPI.h"
#include "DNSCommon.h"
#include "uds_daemon.h"
#include "dns_sd.h"
#include "dnssd_ipc.h"
// Apple specific configuration functionality, not required for other platforms
#ifdef __MACOSX__
#ifndef LOCAL_PEERCRED
#endif // LOCAL_PEERCRED
#endif //__MACOSX__
#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
#endif
// Types and Data Structures
// ----------------------------------------------------------------------
typedef enum
{
typedef void (*req_termination_fn)(void *);
typedef struct registered_record_entry
{
AuthRecord *rr;
struct registered_record_entry *next;
struct request_state *rstate;
// A single registered service: ServiceRecordSet + bookkeeping
// Note that we duplicate some fields from parent service_info object
// to facilitate cleanup, when instances and parent may be deallocated at different times.
typedef struct service_instance
{
struct service_instance *next;
struct request_state *request;
// A client-created service. May reference several service_info objects if default
// settings cause registration in multiple domains.
typedef struct
{
void *txtdata;
int num_subtypes;
struct request_state *request;
} service_info;
// for multi-domain default browsing
typedef struct browser_t
{
DNSQuestion q;
} browser_t;
// parent struct for browser instances: list pointer plus metadata
typedef struct
{
struct request_state *rstate;
typedef struct
{
int nwritten;
typedef struct request_state
{
// connection structures
// state of read (in case message is read over several recv() calls)
char *msgbuf; // pointer to data storage to pass to free()
char *msgdata; // pointer to data to be read from (may be modified)
int bufsize; // size of data storage
// reply, termination, error, and client context info
int no_reply; // don't send asynchronous replies to client
int time_blocked; // record time of a blocked client
void *client_context; // don't touch this - pointer only valid in client's addr space
void *termination_context;
//!!!KRS toss these pointers in a union
// registration context associated with this request (null if not applicable)
struct request_state *next;
// struct physically sits between ipc message header and call-specific fields in the message buffer
typedef struct
{
} reply_hdr;
typedef struct reply_state
{
// state of the transmission
// context of the reply
// pointer into message buffer - allows fields to be changed after message is formatted
char *sdata; // pointer to start of call-specific data
// pointer to malloc'd buffer
char *msgbuf;
} reply_state;
// domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
// structures to handle callbacks
typedef struct
{
typedef struct
{
typedef struct
{
// const ResourceRecord *txt;
// const ResourceRecord *srv;
#ifdef _HAVE_SETDOMAIN_SUPPORT_
typedef struct default_browse_list_t
{
struct default_browse_list_t *next;
#endif // _HAVE_SETDOMAIN_SUPPORT_
// globals
#define gmDNS (&mDNSStorage)
#define MAX_TIME_BLOCKED 60 * mDNSPlatformOneSecond // try to send data to a blocked client for 60 seconds before
// terminating connection
// n get_string() calls w/o buffer overrun
// private function prototypes
mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain);
mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
// If a platform specifies its own PID file name, we use that
#ifndef PID_FILE
#define PID_FILE "/var/run/mDNSResponder.pid"
#endif
{
void *t = req->termination_context;
if (t)
{
{
LogMsgNoIdent("%3d: DNSServiceRegister %##s %u", req->sd, ptr->srs.RR_SRV.resrec.name->c, SRS_PORT(&ptr->srs));
}
{
}
LogMsgNoIdent("%3d: DNSServiceEnumerateDomains %##s", req->sd, ((enum_termination_t *) t)->all->question.qname.c);
}
}
{
*(long*)0 = 0; // On OS X abort() doesn't generate a crash log, but writing to zero does
abort(); // On platforms where writing to zero doesn't generate an exception, abort instead
}
int udsserver_init(void)
{
int ret;
#if defined(_WIN32)
#endif
// If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
if (PID_FILE[0])
{
{
}
}
{
my_perror("ERROR: socket(AF_DNSSD, SOCK_STREAM, 0); failed");
goto error;
}
#if defined(USE_TCP_LOOPBACK)
{
if (ret < 0)
{
my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
goto error;
}
}
#else
{
#ifndef NOT_HAVE_SA_LEN
// According to Stevens (section 3.2), there is no portable way to
// determine whether sa_len is defined on a particular platform.
#endif
if (ret < 0)
{
my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
goto error;
}
}
#endif
#if defined(_WIN32)
//
// SEH: do we even need to do this on windows? this socket
// will be given to WSAEventSelect which will automatically
// set it to non-blocking
//
#else
#endif
{
my_perror("ERROR: could not set listen socket to non-blocking mode");
goto error;
}
{
my_perror("ERROR: could not listen on listen socket");
goto error;
}
{
my_perror("ERROR: could not add listen socket to event loop");
goto error;
}
#if !defined(PLATFORM_NO_RLIMIT)
{
// Set maximum number of open file descriptors
#define MIN_OPENFILES 10240
// Due to bugs in OS X (<rdar://problem/2941095>, <rdar://problem/3342704>, <rdar://problem/3839173>)
// you have to get and set rlimits once before getrlimit will return sensible values
if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
if (setrlimit(RLIMIT_NOFILE, &maxfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
if (setrlimit(RLIMIT_NOFILE, &newfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
}
#endif
return 0;
my_perror("ERROR: udsserver_init");
return -1;
}
int udsserver_exit(void)
{
#if !defined(USE_TCP_LOOPBACK)
// to give up unnecessary privilege, but we need to be root to remove this Unix Domain Socket.
// It would be nice if we could find a solution to this problem
if (unlink(MDNS_UDS_SERVERPATH))
#endif
return 0;
}
{
while(req)
{
{
{
if (result == t_complete)
{
}
{
break;
}
}
}
if (result == t_morecoming)
{
debugf("udsserver_idle: client has been blocked for %ld seconds", (now - req->time_blocked) / mDNSPlatformOneSecond);
{
LogMsg("Could not write data to client %d after %ld seconds - aborting connection", req->sd, MAX_TIME_BLOCKED / mDNSPlatformOneSecond);
}
else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond; // try again in a second
}
//since we're already doing a list traversal, we unlink the request manually instead of calling unlink_request()
{
}
else
{
}
}
return nextevent;
}
{
CacheGroup *cg;
LogMsgNoIdent("Slt Q TTL U Type if len rdata");
{
CacheUsed++; // Count one cache entity for the CacheGroup object
{
CacheUsed++;
LogMsgNoIdent("%3d %s%6ld %s %-6s%-6s%s",
slot,
CRDisplayString(m, rr));
}
}
if (m->rrcache_totalused != CacheUsed)
LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
if (m->rrcache_active != CacheActive)
LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
LogMsgNoIdent("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed, CacheActive);
now = mDNS_TimeNow(m);
}
mDNSexport void uds_validatelists(void)
{
}
#endif
{
{
if (mDNS_DeregisterService(gmDNS, &srv->srs)) // If service deregistered already, we can re-register immediately
}
}
mDNSexport void udsserver_handle_configchange(void)
{
{
if (req->service_registration)
{
}
}
}
{
unsigned long optval;
(void)info; // Unused
if (sd == dnssd_InvalidSocket)
{
if (dnssd_errno() == dnssd_EWOULDBLOCK) return;
my_perror("ERROR: accept");
return;
}
optval = 1;
#ifdef SO_NOSIGPIPE
// Some environments (e.g. OS X) support turning off SIGPIPE for a socket
{
my_perror("ERROR: setsockopt - SO_NOSIGPIPE - aborting client");
return;
}
#endif
#if defined(_WIN32)
#else
#endif
{
my_perror("ERROR: fcntl(sd, F_SETFL, O_NONBLOCK) - aborting client");
return;
}
// allocate a request_state struct that will live with the socket
return;
}
// handler
{
#if defined(_WIN32)
#endif
if (result == t_morecoming)
{
return;
}
if (result == t_terminated)
{
return;
}
{
return;
}
{
LogMsg("ERROR: client incompatible with daemon (client version = %d, "
return;
}
if (validate_message(rstate) < 0)
{
// note that we cannot deliver an error message if validation fails, since the path to the error socket
// may be contained in the (invalid) message body for some message types
LogMsg("Invalid message sent by client - may indicate a malicious program running on this machine!");
return;
}
// check if client wants silent operation
dedicated_error_socket = (rstate->hdr.op == reg_record_request || rstate->hdr.op == add_record_request ||
LogMsg("WARNING: client request %d with incorrect flags setting 0x%X", rstate->hdr.op, rstate->hdr.flags);
// check if primary socket is to be used for synchronous errors, else open new socket
{
int nwritten;
if (errfd == dnssd_InvalidSocket)
{
my_perror("ERROR: socket");
return;
}
//LogOperation("request_callback: Opened dedicated errfd %d", errfd);
#if defined(USE_TCP_LOOPBACK)
{
}
#else
{
char ctrl_path[MAX_CTLPATH];
}
#endif
//LogOperation("request_callback: Connecting to “%s”", cliaddr.sun_path);
{
//LogOperation("request_callback: Couldn't connect to “%s”", cliaddr.sun_path);
my_perror("ERROR: connect");
return;
}
#if defined(_WIN32)
#else
#endif
{
my_perror("ERROR: could not set control socket to non-blocking mode");
return;
}
{
default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
}
//LogOperation("request_callback: Returning error code %d on socket %d", err, errfd);
// On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a four-byte write for us.
// If not, we don't attempt to handle this failure, but we do log it.
LogMsg("ERROR: failed to write error response back to caller: %d %d %s",
//else LogOperation("request_callback: Returned error code %d on socket %d", err, errfd);
//LogOperation("request_callback: Closed errfd %d", errfd);
}
else
{
{
default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
}
}
}
// mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
// the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
// to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
// the mDNSCore operation if the client dies or closes its socket.
// query and resolve calls have separate request handlers that parse the arguments from the client and
// massage the name parameters appropriately, but the rest of the operations (making the query call,
// delivering the result to the client, and termination) are identical.
{
char name[256];
char *ptr;
DNSQuestion *q;
{
LogMsg("ERROR: handle_query_request - transfer state != t_complete");
goto error;
}
if (!ptr)
{
LogMsg("ERROR: handle_query_request - NULL msgdata");
goto error;
}
if (!q) FatalError("ERROR: handle_query - malloc");
bzero(q, sizeof(DNSQuestion));
q->InterfaceID = InterfaceID;
q->ExpectUnique = mDNSfalse;
q->QuestionContext = rstate;
rstate->termination_context = q;
LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) START", rstate->sd, q->qname.c, DNSTypeName(q->qtype));
return;
return;
}
{
char *ptr; // message data pointer
{
LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
return;
}
// extract the data from the message
if (!ptr)
{
LogMsg("ERROR: handle_resolve_request - NULL msgdata");
return;
}
if (interfaceIndex && !InterfaceID)
{ LogMsg("ERROR: handle_resolve_request - Couldn't find InterfaceID for interfaceIndex %d", interfaceIndex); goto bad_param; }
// free memory in rstate since we don't need it anymore
{ LogMsg("ERROR: handle_resolve_request - Couldn't build_domainname_from_strings “%s” “%s” “%s”", name, regtype, domain); goto bad_param; }
// set up termination info
// format questions
// ask the questions
if (err)
{
}
{
}
return;
}
{
if (!term)
{
LogMsg("ERROR: resolve_termination_callback: double termination");
return;
}
}
mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
{
char *data;
(void)m; // Unused
LogOperation("%3d: DNSServiceResolve(%##s, %s) %s %s",
rs->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
// This code used to do this trick of just keeping a copy of the pointer to
// the answer record in the cache, but the unicast query code doesn't currently
// put its answer records in the cache, so for now we can't do this.
if (!AddRecord)
{
// After unicast query code is updated to store its records in the common cache, use this...
// if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
// if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
// intead of this...
if (answer->rrtype == kDNSType_SRV && res->srv && SameRDataBody(answer, (RDataBody *)&res->srvdata))
if (answer->rrtype == kDNSType_TXT && res->txt && answer->rdlength == res->txtlen && SameRDataBody(answer, (RDataBody *)&res->txtdata))
return;
}
// After unicast query code is updated to store its records in the common cache, use this...
// if (answer->rrtype == kDNSType_SRV) res->srv = answer;
// if (answer->rrtype == kDNSType_TXT) res->txt = answer;
// intead of this...
{
}
{
}
// calculate reply length
len += sizeof(DNSServiceFlags);
len += sizeof(DNSServiceErrorType);
rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
// write reply data to message
{
}
}
// what gets called when a resolve is completed and we need to send the data back to the client
mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
{
char *data;
char name[MAX_ESCAPED_DOMAIN_NAME];
(void)m; // Unused
LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) RESULT %s", req->sd, question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer));
//mDNS_StopQuery(m, question);
{
return;
}
// calculate reply data length
len = sizeof(DNSServiceFlags);
len += sizeof(DNSServiceErrorType);
rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
return;
}
{
DNSQuestion *q = context;
LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP", ((request_state *)q->QuestionContext)->sd, q->qname.c, DNSTypeName(q->qtype));
freeL("question_termination_callback", q);
}
// If there's a comma followed by another character,
// FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
// Otherwise, it returns a pointer to the final nul at the end of the string
mDNSlocal char *FindFirstSubType(char *p)
{
while (*p)
{
if (p[0] == '\\' && p[1]) p += 2;
else if (p[0] == ',' && p[1]) { *p++ = 0; return(p); }
else p++;
}
return(p);
}
// If there's a comma followed by another character,
// FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
// If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
// Otherwise, it returns a pointer to the final nul at the end of the string
mDNSlocal char *FindNextSubType(char *p)
{
while (*p)
{
if (p[0] == '\\' && p[1]) // If escape character
p += 2; // ignore following character
else if (p[0] == ',') // If we found a comma
{
if (p[1]) *p++ = 0;
return(p);
}
else if (p[0] == '.')
return(mDNSNULL);
else p++;
}
return(p);
}
// Returns -1 if illegal subtype found
{
mDNSs32 NumSubTypes = 0;
{
NumSubTypes++;
}
if (!stp) return(-1);
return(NumSubTypes);
}
{
if (NumSubTypes)
{
mDNSs32 i;
for (i = 0; i < NumSubTypes; i++)
{
mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
while (*p) p++;
p++;
}
}
return(st);
}
#ifdef _HAVE_SETDOMAIN_SUPPORT_
{
(void)m; // unused
}
#endif
{
char *ptr;
char domainstr[MAX_ESCAPED_DOMAIN_NAME];
#ifdef _HAVE_SETDOMAIN_SUPPORT_
#endif
{
LogMsg("ERROR: handle_setdomain_request - transfer state != t_complete");
return;
}
#ifdef _HAVE_SETDOMAIN_SUPPORT_
// this functionality currently only used for Apple-specific configuration, so we don't burned other platforms by mandating
// the existence of this socket option
if (xuc.cr_version != XUCRED_VERSION) { LogMsg("getsockopt, LOCAL_PEERCRED - bad version"); err = mStatus_UnknownErr; goto end; }
LogMsg("Default domain %s %s for UID %d", domainstr, flags & kDNSServiceFlagsAdd ? "set" : "removed", xuc.cr_uid);
if (flags & kDNSServiceFlagsAdd)
{
// register a local-only PRT record
mDNS_SetupResourceRecord(&newelem->ptr_rec, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, free_defdomain, newelem);
MakeDomainNameFromDNSNameString(&newelem->ptr_rec.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault]);
else
{
// link into list
}
}
else
{
// remove - find in list, deregister
while (ptr)
{
{
break;
}
}
if (!ptr) { LogMsg("Attempt to remove nonexistent domain %s for UID %d", domainstr, xuc.cr_uid); err = mStatus_Invalid; }
}
#else
#endif // _HAVE_SETDOMAIN_SUPPORT_
end:
}
// Generates a response message giving name, type, domain, plus interface index,
// suitable for a browse result or service registration result.
// On successful completion rep is set to point to a malloc'd reply_state struct
mDNSlocal mStatus GenerateNTDResponse(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep)
{
return kDNSServiceErr_Invalid;
else
{
char typestr[MAX_ESCAPED_DOMAIN_NAME];
char domstr [MAX_ESCAPED_DOMAIN_NAME];
int len;
char *data;
// Calculate reply data length
len = sizeof(DNSServiceFlags);
len += sizeof(DNSServiceErrorType);
// Build reply header
// Build reply body
return mStatus_NoError;
}
}
mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
{
(void)m; // Unused
{ LogMsg("%3d: FoundInstance: Should not be called with rrtype %d (not a PTR record)", req->sd, answer->rrtype); return; }
{
LogMsg("%3d: FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
return;
}
LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
}
{
browser_t *b, *p;
{
if (SameDomainName(&p->domain, d))
{ debugf("add_domain_to_browser - attempt to add domain %##d already in list", d->c); return mStatus_AlreadyRegistered; }
}
b = mallocL("browser_t", sizeof(*b));
if (!b) return mStatus_NoMemoryErr;
AssignDomainName(&b->domain, d);
err = mDNS_StartBrowse(gmDNS, &b->q, &info->regtype, d, info->interface_id, info->ForceMCast, FoundInstance, info->rstate);
if (err)
{
freeL("browser_t", b);
}
else
{
}
return err;
}
{
char *ptr;
{
LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
return;
}
// extract data from message
#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
{
}
#endif
typedn.c[0] = 0;
if (!regtype[0] || !AppendDNSNameString(&typedn, regtype)) { err = mStatus_BadParamErr; goto error; }
if (temp.c[0] > 15 && domain[0] == 0) strcpy(domain, "local."); // For over-long service types, we only allow domain "local"
// allocate and set up browser info
// setup termination context
LogOperation("%3d: DNSServiceBrowse(\"%##s\", \"%s\") START", request->sd, info->regtype.c, domain);
if (domain[0])
{
}
else
{
{
if (err)
{
}
}
}
return;
}
{
if (!info) return;
{
}
}
{
request_state *r;
for (r = all_requests; r; r = r->next)
{
else
{
while (*ptr)
{
{
{
// Give goodbyes for known answers.
// Note that this a special case where we know that the QuestionCallback function is our own
// code (it's FoundInstance), and that callback routine doesn't ever cancel its operation, so we
// don't need to guard against the question being cancelled mid-loop the way the mDNSCore routines do.
while (ka) { remove->q.QuestionCallback(gmDNS, &remove->q, &ka->resrec, mDNSfalse); ka = ka->next; }
}
return;
}
}
}
}
}
// Count how many other service records we have locally with the same name, but different rdata.
// For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
// the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
{
int count = 0;
AuthRecord *rr;
ServiceRecordSet *s;
if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
count++;
if (rr->uDNS_info.state != regState_Unregistered && rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
count++;
if (s->uDNS_info.state != regState_Unregistered && SameDomainName(s->RR_SRV.resrec.name, r->name) && !SameRData(&s->RR_SRV.resrec, r))
count++;
return(count);
}
{
int count = 0;
AuthRecord *rr;
count++;
return(count);
}
{
int instance_size;
{
{ LogMsg("register_service_instance: domain %##s already registered", domain->c); return mStatus_AlreadyRegistered; }
}
instance_size = sizeof(*instance);
instance->rename_on_memfree = 0;
result = mDNS_RegisterService(gmDNS, &instance->srs, &instance->name, &info->type, domain, info->host.c[0] ? &info->host : NULL, info->port,
info->txtdata, info->txtlen, instance->subtypes, info->num_subtypes, info->InterfaceID, regservice_callback, instance);
else
{
}
return result;
}
{
{
if (!info) { LogMsg("udsserver_default_reg_domain_changed - NULL service info"); continue; } // this should never happen
if (!info->default_domain) continue;
// valid default registration
else
{
// find the instance to remove
while (si)
{
{
if (err)
{
}
break;
}
}
if (!si) debugf("udsserver_default_reg_domain_changed - domain %##s not registered", d->c); // normal if registration failed
}
}
}
// service registration
{
char name[1024]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
char *ptr;
domainname d, srv;
{
LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
return;
}
// extract data from message
{ LogMsg("ERROR: handle_regservice_request - Couldn't find InterfaceID for interfaceIndex %d", ifi); goto bad_param; }
{
}
// Check for sub-types after the service type
service->num_subtypes = ChopSubTypes(service->type_as_string); // Note: Modifies regtype string to remove trailing subtypes
if (service->num_subtypes < 0)
{ LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", service->type_as_string); goto bad_param; }
// Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
if (!*service->type_as_string || !MakeDomainNameFromDNSNameString(&service->type, service->type_as_string))
{ LogMsg("ERROR: handle_regservice_request - service->type_as_string bad %s", service->type_as_string); goto bad_param; }
if (!name[0])
{
}
else
{
// If the client is allowing AutoRename, then truncate name to legal length before converting it to a DomainLabel
if ((flags & kDNSServiceFlagsNoAutoRename) == 0)
{
}
}
if (*domain)
{
if (!MakeDomainNameFromDNSNameString(&d, domain))
}
else
{
MakeDomainNameFromDNSNameString(&d, "local.");
}
{ LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”", service->name.c, service->type.c, d.c); goto bad_param; }
// Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
// a port number of zero. When two instances of the protected client are allowed to run on one
// machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
{
if (count)
LogMsg("Client application registered %d identical instances of service %##s port %u.",
}
LogOperation("%3d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", \"%s\", %u) START",
{
// note that we don't report errors for non-local, non-explicit domains
}
if (result != mStatus_NoError)
{
}
else
return;
//if (service) freeL("service_info", service); Don't think we should do this -- abort_request will free it a second time and crash
}
// service registration callback performs three duties - frees memory for deregistered services,
// handles name conflicts, and delivers completed registration information to the client (via
// process_service_registraion())
{
(void)m; // Unused
{
// don't send errors up to client for wide-area, empty-string registrations
}
if (result == mStatus_NoError)
LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED ", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
else if (result == mStatus_MemFree)
LogOperation("%3d: DNSServiceRegister(%##s, %u) DEREGISTERED", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
else if (result == mStatus_NameConflict)
LogOperation("%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
else
LogOperation("%3d: DNSServiceRegister(%##s, %u) CALLBACK %d", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), result);
if (result == mStatus_NoError)
{
if (instance->allowremotequery)
{
}
else
{
if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep) != mStatus_NoError)
LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", req->sd, srs->RR_SRV.resrec.name->c);
else
{
}
}
RecordUpdatedNiceLabel(m, 0); // Successfully got new name, tell user immediately
return;
}
else if (result == mStatus_MemFree)
{
if (instance->rename_on_memfree)
{
instance->rename_on_memfree = 0;
// error should never happen - safest to log and continue
}
else
{
return;
}
}
else if (result == mStatus_NameConflict)
{
{
// On conflict for an autoname service, rename and reregister *all* autoname services
m->MainCallback(m, mStatus_ConfigChanged);
}
{
return;
}
else
{
if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
{
}
return;
}
}
else
{
if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
if (result != mStatus_NATTraversal) LogMsg("ERROR: unknown result in regservice_callback: %ld", result);
{
}
return;
}
}
{
(void)m; //unused
if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; }
}
mDNSlocal mStatus add_record_to_service(request_state *rstate, service_instance *instance, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl)
{
int size;
if (!extra)
{
my_perror("ERROR: malloc");
return mStatus_NoMemoryErr;
}
return result;
}
{
service_instance *i;
{
if (result && i->default_local) break;
}
return(result);
}
{
int rdsize;
// BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
// since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
// Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
return result;
}
{
service_instance *i;
// get the message data
{
// update an individually registered record
{
{
goto end;
}
}
goto end;
}
// update a record from a service record set
{
else
{
}
}
end:
return(result);
}
{
(void)m; // Unused
}
{
// clear pointers from parent struct
if (rstate)
{
while (ptr)
{
{
break;
}
}
}
while(e)
{
e->r.RecordContext = e;
tmp = e;
e = e->next;
}
}
{
service_instance *i, *p;
while (i)
{
p = i;
i = i->next;
// only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP", info->request->sd, p->srs.RR_SRV.resrec.name->c, mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port));
}
}
{
AuthRecord *rr;
{
LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
return(-1);
}
if (!rr) return(mStatus_BadParamErr);
// allocate registration entry, link into list
{
}
return(result);
}
{
int len;
(void)m; // Unused
if (!re)
{
// parent struct alreadt freed by termination callback
else
{
if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
}
return;
}
// format result, add to the list for the request, including the client context in the header
len = sizeof(DNSServiceFlags);
len += sizeof(DNSServiceErrorType);
reply->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID));
if (result)
{
// unlink from list, free memory
}
else if (ts == t_morecoming) append_reply(rstate, reply); // client is blocked, link reply into list
}
{
int shared;
while(ptr)
{
}
}
{
char *ptr;
else
{
service_instance *i;
{
if (err && i->default_local) break;
}
}
return(err);
}
// remove a resource record registered via DNSServiceRegisterRecord()
{
int shared;
e = *ptr;
if (err)
{
freeL("remove_record", e);
}
return err;
}
{
{
}
return err;
}
// domain enumeration
{
int result;
{
LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
return;
}
if (ifi && !InterfaceID)
{
return;
}
// allocate context structures
#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
#endif
// enumeration requires multiple questions, so we must link all the context pointers so that
// necessary context can be reached from the callbacks
// if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
// make the calls
(flags & kDNSServiceFlagsRegistrationDomains) ? "kDNSServiceFlagsRegistrationDomains" : "<<Unknown>>");
err = mDNS_GetDomains(gmDNS, &all->question, all->type, NULL, InterfaceID, enum_result_callback, all);
if (err == mStatus_NoError)
err = mDNS_GetDomains(gmDNS, &def->question, def->type, NULL, InterfaceID, enum_result_callback, def);
{
return;
}
}
mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
{
char domain[MAX_ESCAPED_DOMAIN_NAME];
DNSServiceFlags flags = 0;
(void)m; // Unused
if (AddRecord)
{
}
// note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
// a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
// network, so we just pass kDNSServiceInterfaceIndexAny
reply = format_enumeration_reply(de->rstate, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError);
if (!reply)
{
LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
return;
}
return;
}
mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
{
char *data;
len = sizeof(DNSServiceFlags);
len += sizeof(DNSServiceErrorType);
return reply;
}
{
enum_termination_t *t = context;
freeL("enum_termination_callback", t);
}
{
if (rr)
{
(status == mStatus_NoError) ?
"%3d: DNSServiceReconfirmRecord(%s) interface %d initiated" :
"%3d: DNSServiceReconfirmRecord(%s) interface %d failed: %d",
status = 0; // Adding this line eliminates a build failure when building mDNSPosix on Tiger
}
}
{
rstate->data_bytes = 0;
}
// returns a resource record (allocated w/ malloc) containing the data found in an IPC message
// data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
{
AuthRecord *rr;
int storage_size;
if (validate_flags &&
{
LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
return NULL;
}
{
LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
return NULL;
}
else storage_size = sizeof(RDataBody);
mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex),
type, 0, (mDNSu8) ((flags & kDNSServiceFlagsShared) ? kDNSRecordTypeShared : kDNSRecordTypeUnique), mDNSNULL, mDNSNULL);
{
return NULL;
}
return rr;
}
mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
{
domainlabel n;
domainname d, t;
return 0;
}
// append a reply to the list in a request object
{
else
{
}
}
// read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
// returns the current state of the request (morecoming, error, complete, terminated.)
// if there is no data on the socket, the socket will be closed and t_terminated will be returned
{
int nread;
{
LogMsg("ERROR: read_msg called with transfer state terminated or error");
return t_error;
}
{ // this must be death or something is wrong
LogMsg("ERROR: read data from a completed request.");
return t_error;
}
{
return t_error;
}
{
{
{
LogMsg("ERROR: read_msg - client version 0x%08X does not match daemon version 0x%08X", rs->hdr.version, VERSION);
return t_error;
}
}
{
LogMsg("ERROR: read_msg - read too many header bytes");
return t_error;
}
}
// only read data if header is complete
{
{
return t_complete;
}
{
{
my_perror("ERROR: malloc");
return t_error;
}
}
{
LogMsg("ERROR: read_msg - read too many data bytes");
return t_error;
}
}
my_perror("ERROR: read_msg");
return t_error;
}
{
{
LogMsg("ERROR: send_msg called with NULL message buffer");
return t_error;
}
{
return t_complete;
}
if (nwriten < 0)
{
else
{
#if !defined(PLATFORM_NO_EPIPE)
if (dnssd_errno() == EPIPE)
{
return t_terminated;
}
else
#endif
{
my_perror("ERROR: send\n");
return t_error;
}
}
}
{
}
}
{
int totallen;
{
LogMsg("ERROR: create_reply - data length less than lenght of required fields");
return NULL;
}
return reply;
}
{
int nwritten = -1;
{
nwritten = 0;
if (nwritten < 0)
{
my_perror("ERROR: send - unable to deliver error to client");
return(-1);
}
else
{
//client blocked - store result and come backr
return 0;
}
}
return 0;
}
// returns 0 on success, -1 if send is incomplete, or on terminal failure (request is aborted)
{
int nwritten;
nwritten = send(rs->u_err->sd, (char *)(&rs->u_err->err) + rs->u_err->nwritten, sizeof(mStatus) - rs->u_err->nwritten, 0);
if (nwritten < 0)
{
nwritten = 0;
else
{
my_perror("ERROR: send - unable to deliver error to client\n");
return t_error;
}
}
{
return t_complete;
}
return t_morecoming;
}
// send bogus data along with an error code to the app callback
// returns 0 on success (linking reply into list of not fully delivered),
// -1 on failure (request should be aborted)
{
int len;
{
return -1;
}
return 0;
}
{
// Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MACOSX_MDNS_MALLOC_DEBUGGING uses
// for detecting when the memory for an object is inadvertently freed while the object is still on some list
// free pending replies
while(rep)
{
}
{
}
}
{
if (rs == all_requests)
{
return;
}
{
return;
}
}
//hack to search-replace perror's to LogMsg's
{
}
// check that the message delivered by the client is sufficiently long to extract the required data from the buffer
// without overrunning it.
// returns 0 on success, -1 on error.
{
{
sizeof(uint32_t) + // interface
(3 * sizeof(char)); // name, regtype, domain
break;
sizeof(uint32_t) + // interface
sizeof(char) + // fullname
break;
sizeof(uint32_t) + // interface
(2 * sizeof(char)); // regtype, domain
break;
sizeof(uint32_t) + // interface
(4 * sizeof(char)) + // name, type, domain, host
break;
sizeof(uint32_t); // interface
break;
sizeof(uint32_t) + // interface
sizeof(char) + // fullname
sizeof(uint32_t); // ttl
break;
sizeof(uint32_t); // ttl
break;
sizeof(uint16_t) + // rdlen
sizeof(uint32_t); // ttl
break;
break;
sizeof(uint32_t) + // interface
sizeof(char) + // fullname
break;
break;
default:
return -1;
}
}
{
char * data;
return ret;
}
#if defined(_WIN32)
{
static char buffer[1024];
DWORD n;
n = FormatMessageA(
NULL,
(DWORD) inErrorCode,
sizeof( buffer ),
NULL );
if( n > 0 )
{
// Remove any trailing CR's or LF's since some messages have them.
{
buffer[ --n ] = '\0';
}
}
return buffer;
}
#endif