summaryrefslogtreecommitdiff
path: root/external/apache2
diff options
context:
space:
mode:
authorpettai <pettai@NetBSD.org>2014-03-24 00:31:13 +0000
committerpettai <pettai@NetBSD.org>2014-03-24 00:31:13 +0000
commitee6991e1b7cc8d076911533626a48497011b4ebe (patch)
treeab13b4baf49c2ca4837848adf0298165992cd523 /external/apache2
parent09fa7e98e105d1936a7dab2aa5f48698d0f027ff (diff)
Import mDNSResponder-258.14, merge, fix conflicts
Diffstat (limited to 'external/apache2')
-rw-r--r--external/apache2/mDNSResponder/dist/Clients/dns-sd.c158
-rw-r--r--external/apache2/mDNSResponder/dist/mDNSCore/DNSCommon.c974
-rw-r--r--external/apache2/mDNSResponder/dist/mDNSCore/DNSDigest.c99
-rwxr-xr-xexternal/apache2/mDNSResponder/dist/mDNSCore/mDNS.c5831
-rwxr-xr-xexternal/apache2/mDNSResponder/dist/mDNSCore/mDNSEmbeddedAPI.h1552
-rw-r--r--external/apache2/mDNSResponder/dist/mDNSPosix/PosixDaemon.c92
-rwxr-xr-xexternal/apache2/mDNSResponder/dist/mDNSPosix/mDNSPosix.c162
-rwxr-xr-xexternal/apache2/mDNSResponder/dist/mDNSPosix/mDNSUNP.c145
-rw-r--r--external/apache2/mDNSResponder/dist/mDNSShared/dns-sd.121
-rw-r--r--external/apache2/mDNSResponder/dist/mDNSShared/dns_sd.h293
-rw-r--r--external/apache2/mDNSResponder/dist/mDNSShared/dnssd_clientlib.c73
-rw-r--r--external/apache2/mDNSResponder/dist/mDNSShared/dnssd_clientstub.c693
-rw-r--r--external/apache2/mDNSResponder/dist/mDNSShared/dnssd_ipc.h138
-rw-r--r--external/apache2/mDNSResponder/dist/mDNSShared/uds_daemon.c1699
14 files changed, 5195 insertions, 6735 deletions
diff --git a/external/apache2/mDNSResponder/dist/Clients/dns-sd.c b/external/apache2/mDNSResponder/dist/Clients/dns-sd.c
index 8ce9089560d..9dc5388bb29 100644
--- a/external/apache2/mDNSResponder/dist/Clients/dns-sd.c
+++ b/external/apache2/mDNSResponder/dist/Clients/dns-sd.c
@@ -70,6 +70,14 @@ cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT ws2_32.lib ..\mDNSWindows\DLL\Rele
// aren't in the system's /usr/lib/libSystem.dylib.
//#define TEST_NEW_CLIENTSTUB 1
+// When building mDNSResponder for Mac OS X 10.4 and earlier, /usr/lib/libSystem.dylib is built using its own private
+// copy of dnssd_clientstub.c, which is old and doesn't have all the entry points defined in the latest version, so
+// when we're building dns-sd.c on Mac OS X 10.4 or earlier, we automatically set TEST_NEW_CLIENTSTUB so that we'll
+// embed a copy of the latest dnssd_clientstub.c instead of trying to link to the incomplete version in libSystem.dylib
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ <= 1040
+#define TEST_NEW_CLIENTSTUB 1
+#endif
+
#include <ctype.h>
#include <stdio.h> // For stdout, stderr
#include <stdlib.h> // For exit()
@@ -144,6 +152,15 @@ cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT ws2_32.lib ..\mDNSWindows\DLL\Rele
return name;
}
+ static size_t _sa_len(const struct sockaddr *addr)
+ {
+ if (addr->sa_family == AF_INET) return (sizeof(struct sockaddr_in));
+ else if (addr->sa_family == AF_INET6) return (sizeof(struct sockaddr_in6));
+ else return (sizeof(struct sockaddr));
+ }
+
+# define SA_LEN(addr) (_sa_len(addr))
+
#else
#include <unistd.h> // For getopt() and optind
#include <netdb.h> // For getaddrinfo()
@@ -153,14 +170,18 @@ cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT ws2_32.lib ..\mDNSWindows\DLL\Rele
#include <arpa/inet.h> // For inet_addr()
#include <net/if.h> // For if_nametoindex()
static const char kFilePathSep = '/';
+ #define SA_LEN(addr) ((addr)->sa_len)
#endif
#if (TEST_NEW_CLIENTSTUB && !defined(__APPLE_API_PRIVATE))
#define __APPLE_API_PRIVATE 1
#endif
+// DNSServiceSetDispatchQueue is not supported on 10.6 & prior
+#if ! TEST_NEW_CLIENTSTUB && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ - (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ % 10) <= 1060)
+#undef _DNS_SD_LIBDISPATCH
+#endif
#include "dns_sd.h"
-
#include "ClientCommon.h"
#if TEST_NEW_CLIENTSTUB
@@ -196,12 +217,24 @@ static char myhinfoX[ 9] = "\003Mac\004OS X";
static char updatetest[3] = "\002AA";
static char bigNULL[8192]; // 8K is maximum rdata we support
+#if _DNS_SD_LIBDISPATCH
+dispatch_queue_t main_queue;
+dispatch_source_t timer_source;
+#endif
+
// Note: the select() implementation on Windows (Winsock2) fails with any timeout much larger than this
#define LONG_TIME 100000000
static volatile int stopNow = 0;
static volatile int timeOut = LONG_TIME;
+#if _DNS_SD_LIBDISPATCH
+#define EXIT_IF_LIBDISPATCH_FATAL_ERROR(E) \
+ if (main_queue && (E) == kDNSServiceErr_ServiceNotRunning) { fprintf(stderr, "Error code %d\n", (E)); exit(0); }
+#else
+#define EXIT_IF_LIBDISPATCH_FATAL_ERROR(E)
+#endif
+
//*************************************************************************************************************
// Supporting Utility Functions
@@ -311,6 +344,7 @@ static void DNSSD_API enum_reply(DNSServiceRef sdref, const DNSServiceFlags flag
(void)sdref; // Unused
(void)ifIndex; // Unused
(void)context; // Unused
+ EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
// 1. Print the header
if (num_printed++ == 0) printf("Timestamp Recommended %s domain\n", operation == 'E' ? "Registration" : "Browsing");
@@ -443,6 +477,7 @@ static void DNSSD_API zonedata_browse(DNSServiceRef sdref, const DNSServiceFlags
(void)sdref; // Unused
(void)context; // Unused
+ EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
if (!(flags & kDNSServiceFlagsAdd)) return;
if (errorCode) { printf("Error code %d\n", errorCode); return; }
@@ -458,6 +493,8 @@ static void DNSSD_API browse_reply(DNSServiceRef sdref, const DNSServiceFlags fl
char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
(void)sdref; // Unused
(void)context; // Unused
+ EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
+
if (num_printed++ == 0) printf("Timestamp A/R Flags if %-25s %-25s %s\n", "Domain", "Service Type", "Instance Name");
printtimestamp();
if (errorCode) printf("Error code %d\n", errorCode);
@@ -512,11 +549,13 @@ static void DNSSD_API resolve_reply(DNSServiceRef sdref, const DNSServiceFlags f
(void)sdref; // Unused
(void)ifIndex; // Unused
(void)context; // Unused
+ EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
- printtimestamp();
- if (errorCode) printf("Error code %d\n", errorCode);
+ if (errorCode)
+ printf("Error code %d\n", errorCode);
else
{
+ printtimestamp();
printf("%s can be reached at %s:%u (interface %d)", fullname, hosttarget, PortAsNumber, ifIndex);
if (flags) printf(" Flags: %X", flags);
// Don't show degenerate TXT records containing nothing but a single empty string
@@ -571,6 +610,11 @@ static void myTimerCallBack(void)
err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_NULL, sizeof(bigNULL), &bigNULL[0], 0);
if (err) printf("Failed: %d\n", err); else printf("Succeeded\n");
timeOut = LONG_TIME;
+#if _DNS_SD_LIBDISPATCH
+ if (timer_source)
+ dispatch_source_set_timer(timer_source, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)timeOut * NSEC_PER_SEC),
+ (uint64_t)timeOut * NSEC_PER_SEC, 0);
+#endif
}
break;
}
@@ -588,6 +632,7 @@ static void DNSSD_API reg_reply(DNSServiceRef sdref, const DNSServiceFlags flags
(void)sdref; // Unused
(void)flags; // Unused
(void)context; // Unused
+ EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
printtimestamp();
printf("Got a reply for service %s.%s%s: ", name, regtype, domain);
@@ -596,7 +641,15 @@ static void DNSSD_API reg_reply(DNSServiceRef sdref, const DNSServiceFlags flags
{
if (flags & kDNSServiceFlagsAdd) printf("Name now registered and active\n");
else printf("Name registration removed\n");
- if (operation == 'A' || operation == 'U' || operation == 'N') timeOut = 5;
+ if (operation == 'A' || operation == 'U' || operation == 'N')
+ {
+ timeOut = 5;
+#if _DNS_SD_LIBDISPATCH
+ if (timer_source)
+ dispatch_source_set_timer(timer_source, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)timeOut * NSEC_PER_SEC),
+ (uint64_t)timeOut * NSEC_PER_SEC, 0);
+#endif
+ }
}
else if (errorCode == kDNSServiceErr_NameConflict)
{
@@ -633,6 +686,7 @@ static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags,
(void)ifIndex; // Unused
(void)ttl; // Unused
(void)context; // Unused
+ EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
if (num_printed++ == 0) printf("Timestamp A/R Flags if %-30s%4s%4s Rdata\n", "Name", "T", "C");
printtimestamp();
@@ -697,9 +751,10 @@ static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags,
static void DNSSD_API port_mapping_create_reply(DNSServiceRef sdref, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, uint32_t publicAddress, uint32_t protocol, uint16_t privatePort, uint16_t publicPort, uint32_t ttl, void *context)
{
(void)sdref; // Unused
- (void)context; // Unused
(void)flags; // Unused
-
+ (void)context; // Unused
+ EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
+
if (num_printed++ == 0) printf("Timestamp if %-20s %-15s %-15s %-15s %-6s\n", "External Address", "Protocol", "Internal Port", "External Port", "TTL");
printtimestamp();
if (errorCode && errorCode != kDNSServiceErr_DoubleNAT) printf("Error code %d\n", errorCode);
@@ -711,7 +766,8 @@ static void DNSSD_API port_mapping_create_reply(DNSServiceRef sdref, DNSServiceF
snprintf(addr, sizeof(addr), "%d.%d.%d.%d", digits[0], digits[1], digits[2], digits[3]);
printf("%-4d %-20s %-15d %-15d %-15d %-6d%s\n", ifIndex, addr, protocol, ntohs(privatePort), ntohs(publicPort), ttl, errorCode == kDNSServiceErr_DoubleNAT ? " Double NAT" : "");
}
- fflush(stdout);
+
+ if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
}
#endif
@@ -722,7 +778,8 @@ static void DNSSD_API addrinfo_reply(DNSServiceRef sdref, DNSServiceFlags flags,
char addr[256] = "";
(void) sdref;
(void) context;
-
+ EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
+
if (num_printed++ == 0) printf("Timestamp A/R Flags if %-25s %-44s %s\n", "Hostname", "Address", "TTL");
printtimestamp();
@@ -759,6 +816,26 @@ static void DNSSD_API addrinfo_reply(DNSServiceRef sdref, DNSServiceFlags flags,
// The main test function
static void HandleEvents(void)
+#if _DNS_SD_LIBDISPATCH
+ {
+ main_queue = dispatch_get_main_queue();
+ if (client) DNSServiceSetDispatchQueue(client, main_queue);
+ if (client_pa) DNSServiceSetDispatchQueue(client_pa, main_queue);
+ if (operation == 'A' || operation == 'U' || operation == 'N')
+ {
+ timer_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, main_queue);
+ if (timer_source)
+ {
+ // Start the timer "timeout" seconds into the future and repeat it every "timeout" seconds
+ dispatch_source_set_timer(timer_source, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)timeOut * NSEC_PER_SEC),
+ (uint64_t)timeOut * NSEC_PER_SEC, 0);
+ dispatch_source_set_event_handler(timer_source, ^{myTimerCallBack();});
+ dispatch_resume(timer_source);
+ }
+ }
+ dispatch_main();
+ }
+#else
{
int dns_sd_fd = client ? DNSServiceRefSockFD(client ) : -1;
int dns_sd_fd2 = client_pa ? DNSServiceRefSockFD(client_pa) : -1;
@@ -801,6 +878,7 @@ static void HandleEvents(void)
}
}
}
+#endif
static int getfirstoption(int argc, char **argv, const char *optstr, int *pOptInd)
// Return the recognized option in optstr and the option index of the next arg.
@@ -832,9 +910,10 @@ static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordR
char *name = (char *)context;
(void)service; // Unused
- (void)rec; // Unused
+ (void)rec; // Unused
(void)flags; // Unused
-
+ EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
+
printtimestamp();
printf("Got a reply for record %s: ", name);
@@ -846,28 +925,26 @@ static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordR
}
if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
// DNSServiceRemoveRecord(service, rec, 0); to test record removal
- }
-static unsigned long getip(const char *const name)
- {
- unsigned long ip = 0;
- struct addrinfo hints;
- struct addrinfo *addrs = NULL;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_INET;
-
- if (getaddrinfo(name, NULL, &hints, &addrs) == 0)
+#if 0 // To test updating of individual records registered via DNSServiceRegisterRecord
+ if (!errorCode)
{
- ip = ((struct sockaddr_in*) addrs->ai_addr)->sin_addr.s_addr;
+ int x = 0x11111111;
+ printf("Updating\n");
+ DNSServiceUpdateRecord(service, rec, 0, sizeof(x), &x, 0);
}
+#endif
- if (addrs)
- {
- freeaddrinfo(addrs);
- }
+ if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
+ }
- return(ip);
+static void getip(const char *const name, struct sockaddr_storage *result)
+ {
+ struct addrinfo *addrs = NULL;
+ int err = getaddrinfo(name, NULL, NULL, &addrs);
+ if (err) fprintf(stderr, "getaddrinfo error %d for %s", err, name);
+ else memcpy(result, addrs->ai_addr, SA_LEN(addrs->ai_addr));
+ if (addrs) freeaddrinfo(addrs);
}
static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef sdref, const char *host, const char *ip)
@@ -876,10 +953,15 @@ static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef sdref, const
// On the Win32 platform, WinSock must be initialized for getip() to succeed.
// Any DNSService* call will initialize WinSock for us, so we make sure
// DNSServiceCreateConnection() is called before getip() is.
- unsigned long addr = getip(ip);
- return(DNSServiceRegisterRecord(sdref, &record, kDNSServiceFlagsUnique, opinterface, host,
- kDNSServiceType_A, kDNSServiceClass_IN, sizeof(addr), &addr, 240, MyRegisterRecordCallback, (void*)host));
- // Note, should probably add support for creating proxy AAAA records too, one day
+ struct sockaddr_storage hostaddr;
+ getip(ip, &hostaddr);
+ if (hostaddr.ss_family == AF_INET)
+ return(DNSServiceRegisterRecord(sdref, &record, kDNSServiceFlagsUnique, opinterface, host,
+ kDNSServiceType_A, kDNSServiceClass_IN, 4, &((struct sockaddr_in *)&hostaddr)->sin_addr, 240, MyRegisterRecordCallback, (void*)host));
+ else if (hostaddr.ss_family == AF_INET6)
+ return(DNSServiceRegisterRecord(sdref, &record, kDNSServiceFlagsUnique, opinterface, host,
+ kDNSServiceType_AAAA, kDNSServiceClass_IN, 16, &((struct sockaddr_in6*)&hostaddr)->sin6_addr, 240, MyRegisterRecordCallback, (void*)host));
+ else return(kDNSServiceErr_BadParam);
}
#define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0' ) : \
@@ -973,6 +1055,14 @@ int main(int argc, char **argv)
printf("Using LocalOnly\n");
}
+ if (argc > 1 && (!strcmp(argv[1], "-p2p") || !strcmp(argv[1], "-P2P")))
+ {
+ argc--;
+ argv++;
+ opinterface = kDNSServiceInterfaceIndexP2P;
+ printf("Using P2P\n");
+ }
+
if (argc > 2 && !strcmp(argv[1], "-i"))
{
opinterface = if_nametoindex(argv[2]);
@@ -983,7 +1073,7 @@ int main(int argc, char **argv)
}
if (argc < 2) goto Fail; // Minimum command line is the command name and one argument
- operation = getfirstoption(argc, argv, "EFBZLRPQCAUNTMISV"
+ operation = getfirstoption(argc, argv, "EFBZLRPQqCAUNTMISV"
#if HAS_NAT_PMP_API
"X"
#endif
@@ -1055,10 +1145,12 @@ int main(int argc, char **argv)
//DNSServiceRemoveRecord(client_pa, record, 0);
break;
+ case 'q':
case 'Q':
case 'C': {
uint16_t rrtype, rrclass;
DNSServiceFlags flags = kDNSServiceFlagsReturnIntermediates;
+ if (operation == 'q') flags |= kDNSServiceFlagsSuppressUnusable;
if (argc < opi+1) goto Fail;
rrtype = (argc <= opi+1) ? kDNSServiceType_A : GetRRType(argv[opi+1]);
rrclass = (argc <= opi+2) ? kDNSServiceClass_IN : atoi(argv[opi+2]);
@@ -1137,7 +1229,7 @@ int main(int argc, char **argv)
#endif
case 'S': {
- Opaque16 registerPort = { { 0x23, 0x45 } };
+ Opaque16 registerPort = { { 0x23, 0x45 } }; // 9029 decimal
unsigned char txtrec[16] = "\xF" "/path=test.html";
DNSRecordRef rec;
unsigned char nulrec[4] = "1234";
diff --git a/external/apache2/mDNSResponder/dist/mDNSCore/DNSCommon.c b/external/apache2/mDNSResponder/dist/mDNSCore/DNSCommon.c
index 4fab9dd2052..f08d9c3d07b 100644
--- a/external/apache2/mDNSResponder/dist/mDNSCore/DNSCommon.c
+++ b/external/apache2/mDNSResponder/dist/mDNSCore/DNSCommon.c
@@ -13,552 +13,7 @@
* 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: DNSCommon.c,v $
-Revision 1.252 2009/06/27 00:27:03 cheshire
-<rdar://problem/6959273> mDNSResponder taking up 13% CPU with 400 KBps incoming bonjour requests
-Removed overly-complicate and ineffective multi-packet known-answer snooping code
-(Bracketed it with "#if ENABLE_MULTI_PACKET_QUERY_SNOOPING" for now; will delete actual code later)
-
-Revision 1.251 2009/05/19 23:40:37 cheshire
-<rdar://problem/6903507> Sleep Proxy: Retransmission logic not working reliably on quiet networks
-Added m->NextScheduledSPRetry timer for scheduling Sleep Proxy registration retries
-
-Revision 1.250 2009/05/01 21:28:33 cheshire
-<rdar://problem/6721680> AppleConnectAgent's reachability checks delay sleep by 30 seconds
-No longer suspend network operations after we've acknowledged that the machine is going to sleep,
-because other software may not have yet acknowledged the sleep event, and may be still trying
-to do unicast DNS queries or other Bonjour operations.
-
-Revision 1.249 2009/04/24 00:29:20 cheshire
-<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
-Added support for generating/parsing/displaying NSEC records
-
-Revision 1.248 2009/04/23 22:11:16 cheshire
-Minor cleanup in debugging checks in GetLargeResourceRecord
-
-Revision 1.247 2009/04/21 23:36:25 cheshire
-<rdar://problem/6814427> Remove unused kDNSType_MAC
-
-Revision 1.246 2009/04/21 01:00:19 cheshire
-Fixed typo in previous checkin
-
-Revision 1.245 2009/04/21 00:57:23 cheshire
-<rdar://problem/6810410> Off-by-one error in putDomainNameAsLabels()
-If just writing one-byte root label, make sure we have space for that
-
-Revision 1.244 2009/04/11 00:19:30 jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.243 2009/04/01 17:50:10 mcguire
-cleanup mDNSRandom
-
-Revision 1.242 2009/03/26 04:01:55 jessic2
-<rdar://problem/6613786> MessageTracer: Log service types longer than 14 characters and service types with underscores
-
-Revision 1.241 2009/03/18 20:50:08 cheshire
-<rdar://problem/6650064> uDNS: Reverse lookup of own IP address takes way too long, sometimes forever
-
-Revision 1.240 2009/03/18 20:41:04 cheshire
-Added definition of the all-ones mDNSOpaque16 ID
-
-Revision 1.239 2009/03/06 23:51:50 mcguire
-Fix broken build by defining DiscardPort
-
-Revision 1.238 2009/03/04 00:40:13 cheshire
-Updated DNS server error codes to be more consistent with definitions at
-<http://www.iana.org/assignments/dns-parameters>
-
-Revision 1.237 2009/03/03 23:04:43 cheshire
-For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC)
-
-Revision 1.236 2009/03/03 22:51:53 cheshire
-<rdar://problem/6504236> Sleep Proxy: Waking on same network but different interface will cause conflicts
-
-Revision 1.235 2009/02/07 05:55:44 cheshire
-Only pay attention to m->DelaySleep when it's nonzero
-
-Revision 1.234 2009/02/07 02:52:52 cheshire
-<rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
-Pay attention to m->DelaySleep when computing next task time
-
-Revision 1.233 2009/01/30 23:50:31 cheshire
-Added LastLabel() routine to get the last label of a domainname
-
-Revision 1.232 2009/01/15 00:22:48 mcguire
-<rdar://problem/6437092> NAT-PMP: mDNSResponder needs to listen on 224.0.0.1:5350/UDP with REUSEPORT
-
-Revision 1.231 2008/12/12 01:24:06 cheshire
-Updated GetNextScheduledEvent() to pay attention to m->SPSProxyListChanged
-
-Revision 1.230 2008/12/10 01:55:54 cheshire
-Renamed "Max" macro to avoid conflict with another "Max" macro on ARMv5
-
-Revision 1.229 2008/11/27 01:28:45 cheshire
-For display purposes, show sleep sequence number as unsigned
-
-Revision 1.228 2008/11/26 20:57:37 cheshire
-For consistency with other similar macros, renamed mdnsIsDigit/mdnsIsLetter/mdnsValidHostChar
-to mDNSIsDigit/mDNSIsLetter/mDNSValidHostChar
-
-Revision 1.227 2008/11/26 20:28:05 cheshire
-Added new SSHPort constant
-
-Revision 1.226 2008/11/16 16:55:51 cheshire
-Updated debugging messages
-
-Revision 1.225 2008/11/14 21:56:31 cheshire
-Moved debugging routine ShowTaskSchedulingError() from daemon.c into DNSCommon.c
-
-Revision 1.224 2008/11/14 02:20:03 cheshire
-Include m->NextScheduledSPS in task scheduling calculations
-
-Revision 1.223 2008/11/14 01:19:03 cheshire
-Initialize TimeRcvd and TimeExpire fields in AuthRecord_struct
-
-Revision 1.222 2008/11/14 00:00:53 cheshire
-After client machine wakes up, Sleep Proxy machine need to remove any records
-it was temporarily holding as proxy for that client
-
-Revision 1.221 2008/11/13 19:06:02 cheshire
-Added code to put, get, and display rdataOPT properly
-
-Revision 1.220 2008/11/06 01:08:11 mcguire
-Fix compiler warning about discarding const
-
-Revision 1.219 2008/11/04 23:06:50 cheshire
-Split RDataBody union definition into RDataBody and RDataBody2, and removed
-SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord
-
-Revision 1.218 2008/11/04 22:21:44 cheshire
-Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord
-
-Revision 1.217 2008/11/04 22:13:43 cheshire
-Made RDataBody parameter to GetRRDisplayString_rdb "const"
-
-Revision 1.216 2008/11/04 20:06:19 cheshire
-<rdar://problem/6186231> Change MAX_DOMAIN_NAME to 256
-
-Revision 1.215 2008/10/23 23:54:35 cheshire
-Added missing "const" in declaration
-
-Revision 1.214 2008/10/23 22:25:55 cheshire
-Renamed field "id" to more descriptive "updateid"
-
-Revision 1.213 2008/10/22 01:01:52 cheshire
-Added onesEthAddr constant, used for sending ARP broadcasts
-
-Revision 1.212 2008/10/14 21:52:18 cheshire
-Added support for putting/getting/printing kDNSType_MAC
-
-Revision 1.211 2008/10/09 22:36:08 cheshire
-Now that we have Sleep Proxy Server, can't suppress normal scheduling logic while going to sleep
-
-Revision 1.210 2008/10/08 01:03:52 cheshire
-Change GetFirstActiveInterface() so the NetworkInterfaceInfo it returns is not "const"
-Added mDNS_SetupQuestion() convenience function
-
-Revision 1.209 2008/09/23 04:13:30 cheshire
-<rdar://problem/6238774> Remove "local" from the end of _services._dns-sd._udp PTR records
-Removed old special-case Bonjour Browser hack that is no longer needed
-
-Revision 1.208 2008/09/23 02:33:56 cheshire
-<rdar://problem/4738033> uDNS: Should not compress SRV rdata in uDNS packets
-
-Revision 1.207 2008/09/23 02:30:07 cheshire
-Get rid of PutResourceRecordCappedTTL()
-
-Revision 1.206 2008/09/23 02:26:09 cheshire
-Don't need to export putEmptyResourceRecord (it's only used from DNSCommon.c)
-
-Revision 1.205 2008/09/23 02:21:00 cheshire
-Don't need to force setting of rrclass in PutResourceRecordTTLWithLimit() now that putLLQ() sets it correctly
-
-Revision 1.204 2008/08/29 19:03:05 cheshire
-<rdar://problem/6185645> Off-by-one error in putDomainNameAsLabels()
-
-Revision 1.203 2008/08/13 00:47:53 mcguire
-Handle failures when packet logging
-
-Revision 1.202 2008/08/13 00:32:48 mcguire
-refactor to use SwapDNSHeaderBytes instead of swapping manually
-
-Revision 1.201 2008/07/24 20:23:03 cheshire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-
-Revision 1.200 2008/07/18 00:07:50 cheshire
-<rdar://problem/5904999> Log a message for applications that register service types longer than 14 characters
-
-Revision 1.199 2008/03/14 19:58:38 mcguire
-<rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
-Make sure we add the record when sending LLQ refreshes
-
-Revision 1.198 2008/03/07 23:29:24 cheshire
-Fixed cosmetic byte order display issue in DumpPacket output
-
-Revision 1.197 2008/03/05 22:51:29 mcguire
-<rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
-Even further refinements
-
-Revision 1.196 2008/03/05 22:01:53 cheshire
-<rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
-Now that we optionally add the HINFO record, when rewriting the header fields into network byte
-order, we need to use our updated msg->h.numAdditionals, not the stack variable numAdditionals
-
-Revision 1.195 2008/03/05 19:06:30 mcguire
-<rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
-further refinements
-
-Revision 1.194 2008/03/05 00:26:06 cheshire
-<rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
-
-Revision 1.193 2007/12/17 23:42:36 cheshire
-Added comments about DNSDigest_SignMessage()
-
-Revision 1.192 2007/12/17 21:24:09 cheshire
-<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
-We suspend sending of mDNS queries responses when going to sleep, so calculate GetNextScheduledEvent() time accordingly
-
-Revision 1.191 2007/12/14 00:59:36 cheshire
-<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
-While going to sleep, don't block event scheduling
-
-Revision 1.190 2007/12/13 20:20:17 cheshire
-Minor efficiency tweaks -- converted IdenticalResourceRecord, IdenticalSameNameRecord, and
-SameRData from functions to macros, which allows the code to be inlined (the compiler can't
-inline a function defined in a different compilation unit) and therefore optimized better.
-
-Revision 1.189 2007/12/13 00:17:32 cheshire
-RDataHashValue was not calculating hash value reliably for RDATA types that have 'holes' in the
-in-memory representation (particularly SOA was affected by this, resulting in multiple duplicate
-cache entities for the same SOA record, because they had erroneously different rdatahash values).
-
-Revision 1.188 2007/12/13 00:13:03 cheshire
-Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody
-
-Revision 1.187 2007/12/08 00:35:20 cheshire
-<rdar://problem/5636422> Updating TXT records is too slow
-m->SuppressSending should not suppress all activity, just mDNS Query/Probe/Response
-
-Revision 1.186 2007/11/15 22:52:29 cheshire
-<rdar://problem/5589039> ERROR: mDNSPlatformWriteTCP - send Broken pipe
-
-Revision 1.185 2007/10/10 20:22:03 cheshire
-Added sanity checks in mDNSSendDNSMessage -- we've seen crashes in DNSDigest_SignMessage
-apparently caused by trying to sign zero-length messages
-
-Revision 1.184 2007/10/05 17:56:07 cheshire
-Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
-
-Revision 1.183 2007/10/02 18:33:46 cheshire
-Improved GetRRDisplayString to show all constituent strings within a text record
-(up to the usual MaxMsg 120-character limit)
-
-Revision 1.182 2007/10/01 19:45:01 cheshire
-<rdar://problem/5514859> BTMM: Sometimes Back to My Mac autotunnel registrations are malformed
-
-Revision 1.181 2007/10/01 18:36:53 cheshire
-Yet another fix to finally get the DumpPacket RCODE display right
-
-Revision 1.180 2007/09/29 21:30:38 cheshire
-In DumpPacket/DumpRecords, show an error line if we run out of packet data
-
-Revision 1.179 2007/09/29 20:44:56 cheshire
-Fix error in DumpPacket where it was not displaying the RCODE field properly
-
-Revision 1.178 2007/09/27 21:11:44 cheshire
-Fixed spelling mistake: ROCDE -> RCODE
-
-Revision 1.177 2007/09/27 18:51:26 cheshire
-Improved DumpPacket to use "Zone/Prerequisites/Updates" nomenclature when displaying a DNS Update packet
-
-Revision 1.176 2007/09/27 17:53:37 cheshire
-Add display of RCODE and flags in DumpPacket output
-
-Revision 1.175 2007/09/26 22:26:40 cheshire
-Also show DNS query/response ID in DumpPacket output
-
-Revision 1.174 2007/09/26 16:36:02 cheshire
-In DumpPacket output, begin header line with "-- " to make it visually stand out better
-
-Revision 1.173 2007/09/26 00:49:46 cheshire
-Improve packet logging to show sent and received packets,
-transport protocol (UDP/TCP/TLS) and source/destination address:port
-
-Revision 1.172 2007/09/21 23:14:39 cheshire
-<rdar://problem/5498009> BTMM: Need to log updates and query packet contents in verbose debug mode
-Changed DumpRecords to use LargeCacheRecord on the stack instead of the shared m->rec storage,
-to eliminate "GetLargeResourceRecord: m->rec appears to be already in use" warnings
-
-Revision 1.171 2007/09/21 21:12:36 cheshire
-<rdar://problem/5498009> BTMM: Need to log updates and query packet contents
-
-Revision 1.170 2007/09/07 21:16:58 cheshire
-Add new symbol "NATPMPAnnouncementPort" (5350)
-
-Revision 1.169 2007/08/30 00:31:20 cheshire
-Improve "locking failure" debugging messages to show function name using __func__ macro
-
-Revision 1.168 2007/08/28 23:58:42 cheshire
-Rename HostTarget -> AutoTarget
-
-Revision 1.167 2007/08/10 23:10:05 vazquez
-<rdar://problem/5389850> mDNS: Reverse lookups of IPv6 link-local addresses always fail
-
-Revision 1.166 2007/08/01 16:09:13 cheshire
-Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
-
-Revision 1.165 2007/08/01 00:04:13 cheshire
-<rdar://problem/5261696> Crash in tcpKQSocketCallback
-Half-open TCP connections were not being cancelled properly
-
-Revision 1.164 2007/07/27 20:48:43 cheshire
-In DumpRecords(), include record TTL in output
-
-Revision 1.163 2007/07/16 20:10:11 vazquez
-<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
-Added SSDP port number
-
-Revision 1.162 2007/07/10 01:59:33 cheshire
-<rdar://problem/3557903> Performance: Core code will not work on platforms with small stacks
-Fixed GetPktLease to use shared m->rec instead of putting LargeCacheRecord on the stack
-
-Revision 1.161 2007/07/06 18:56:26 cheshire
-Check m->NextScheduledNATOp in GetNextScheduledEvent()
-
-Revision 1.160 2007/06/29 00:06:42 vazquez
-<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-
-Revision 1.159 2007/06/28 21:17:17 cheshire
-Rename "m->nextevent" as more informative "m->NextuDNSEvent"
-
-Revision 1.158 2007/05/25 00:25:43 cheshire
-<rdar://problem/5227737> Need to enhance putRData to output all current known types
-
-Revision 1.157 2007/05/23 00:32:15 cheshire
-Don't treat uDNS responses as an entire RRSet (kDNSRecordTypePacketUniqueMask)
-when received in a truncated UDP response
-
-Revision 1.156 2007/05/15 00:29:00 cheshire
-Print «ZERO ADDRESS» for %#a with a zero mDNSAddr
-
-Revision 1.155 2007/05/07 22:07:47 cheshire
-<rdar://problem/4738025> Enhance GetLargeResourceRecord to decompress more record types
-
-Revision 1.154 2007/05/04 20:19:53 cheshire
-Improve DumpPacket() output
-
-Revision 1.153 2007/05/01 21:46:31 cheshire
-Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them
-
-Revision 1.152 2007/04/27 19:28:01 cheshire
-Any code that calls StartGetZoneData needs to keep a handle to the structure, so
-it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
--- it would start a query and then quickly cancel it, and then when
-StartGetZoneData completed, it had a dangling pointer and crashed.)
-
-Revision 1.151 2007/04/26 13:35:25 cheshire
-Add kDNSType_SOA case in SameRDataBody, and a comment in GetLargeResourceRecord about why this is important
-
-Revision 1.150 2007/04/24 00:17:33 cheshire
-Made LocateLLQOptData guard against packets with bogus numAdditionals value
-
-Revision 1.149 2007/04/23 21:43:00 cheshire
-Remove debugging check
-
-Revision 1.148 2007/04/23 04:55:29 cheshire
-Add some defensive null pointer checks
-
-Revision 1.147 2007/04/22 20:18:10 cheshire
-Add comment about mDNSRandom()
-
-Revision 1.146 2007/04/22 06:02:02 cheshire
-<rdar://problem/4615977> Query should immediately return failure when no server
-
-Revision 1.145 2007/04/20 21:17:24 cheshire
-For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
-
-Revision 1.144 2007/04/19 18:02:43 cheshire
-<rdar://problem/5140504> Unicast DNS response records should tagged with kDNSRecordTypePacketUnique bit
-
-Revision 1.143 2007/04/16 21:53:49 cheshire
-Improve display of negative cache entries
-
-Revision 1.142 2007/04/05 22:55:35 cheshire
-<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
-
-Revision 1.141 2007/04/04 01:33:11 cheshire
-<rdar://problem/5075200> DNSServiceAddRecord is failing to advertise NULL record
-Overly defensive code was zeroing too much of the AuthRecord structure
-
-Revision 1.140 2007/04/03 19:37:58 cheshire
-Rename mDNSAddrIsv4Private() to more precise mDNSAddrIsRFC1918()
-
-Revision 1.139 2007/04/03 19:18:39 cheshire
-Use mDNSSameIPv4Address (and similar) instead of accessing internal fields directly
-
-Revision 1.138 2007/03/28 21:14:08 cheshire
-The rrclass field of an OPT pseudo-RR holds the sender's UDP payload size
-
-Revision 1.137 2007/03/28 20:59:26 cheshire
-<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
-
-Revision 1.136 2007/03/28 15:56:37 cheshire
-<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
-
-Revision 1.135 2007/03/28 01:20:05 cheshire
-<rdar://problem/4883206> Improve/create logging for secure browse
-
-Revision 1.134 2007/03/27 23:25:35 cheshire
-Fix error caching SOA records
-(cache entry was size of wire-format packed data, not size of in-memory structure)
-
-Revision 1.133 2007/03/26 22:55:45 cheshire
-Add OPT and TSIG to list of types DNSTypeName() knows about
-
-Revision 1.132 2007/03/22 18:31:48 cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.131 2007/03/21 21:55:20 cheshire
-<rdar://problem/5069688> Hostname gets ; or : which are illegal characters
-Error in AppendLabelSuffix() for numbers close to the 32-bit limit
-
-Revision 1.130 2007/03/21 19:23:37 cheshire
-<rdar://problem/5076826> jmDNS advertised garbage that shows up weird in Safari
-Make check less strict so we don't break Bonjour Browser
-
-Revision 1.129 2007/03/21 01:00:45 cheshire
-<rdar://problem/5076826> jmDNS advertised garbage that shows up weird in Safari
-DeconstructServiceName() needs to be more defensive about what it considers legal
-
-Revision 1.128 2007/03/21 00:30:02 cheshire
-<rdar://problem/4789455> Multiple errors in DNameList-related code
-
-Revision 1.127 2007/03/20 17:07:15 cheshire
-Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-
-Revision 1.126 2007/03/10 03:26:44 cheshire
-<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
-
-Revision 1.125 2007/03/07 00:08:58 cheshire
-<rdar://problem/4347550> Don't allow hyphens at start of service type
-
-Revision 1.124 2007/01/19 18:04:05 cheshire
-For naming consistency, use capital letters for RR types: rdataOpt should be rdataOPT
-
-Revision 1.123 2007/01/10 22:45:51 cheshire
-Cast static strings to "(const domainname*)", not "(domainname*)"
-
-Revision 1.122 2007/01/06 00:47:35 cheshire
-Improve GetRRDisplayString to indicate when record has zero-length rdata
-
-Revision 1.121 2007/01/05 08:30:39 cheshire
-Trim excessive "Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.120 2007/01/05 05:23:00 cheshire
-Zero DNSQuestion structure in getQuestion (specifically, need TargetQID to be zero'd)
-
-Revision 1.119 2007/01/05 04:30:16 cheshire
-Change a couple of "(domainname *)" casts to "(const domainname *)"
-
-Revision 1.118 2007/01/04 20:21:59 cheshire
-<rdar://problem/4720673> uDNS: Need to start caching unicast records
-Don't return multicast answers in response to unicast questions
-
-Revision 1.117 2006/12/22 20:59:49 cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.116 2006/12/21 00:04:07 cheshire
-To be defensive, put a mDNSPlatformMemZero() at the start of mDNS_SetupResourceRecord()
-
-Revision 1.115 2006/12/20 04:07:34 cheshire
-Remove uDNS_info substructure from AuthRecord_struct
-
-Revision 1.114 2006/12/19 22:40:04 cheshire
-Fix compiler warnings
-
-Revision 1.113 2006/12/19 02:21:08 cheshire
-Delete spurious spaces
-
-Revision 1.112 2006/12/15 20:42:10 cheshire
-<rdar://problem/4769083> ValidateRData() should be stricter about malformed MX and SRV records
-Additional defensive coding in GetLargeResourceRecord() to reject apparently-valid
-rdata that actually runs past the end of the received packet data.
-
-Revision 1.111 2006/12/15 19:09:57 cheshire
-<rdar://problem/4769083> ValidateRData() should be stricter about malformed MX and SRV records
-Made DomainNameLength() more defensive by adding a limit parameter, so it can be
-safely used to inspect potentially malformed data received from external sources.
-Without this, a domain name that starts off apparently valid, but extends beyond the end of
-the received packet data, could have appeared valid if the random bytes are already in memory
-beyond the end of the packet just happened to have reasonable values (e.g. all zeroes).
-
-Revision 1.110 2006/11/18 05:01:30 cheshire
-Preliminary support for unifying the uDNS and mDNS code,
-including caching of uDNS answers
-
-Revision 1.109 2006/11/10 00:54:14 cheshire
-<rdar://problem/4816598> Changing case of Computer Name doesn't work
-
-Revision 1.108 2006/10/05 23:11:18 cheshire
-<rdar://problem/4769083> ValidateRData() should be stricter about malformed MX and SRV records
-
-Revision 1.107 2006/09/15 21:20:14 cheshire
-Remove uDNS_info substructure from mDNS_struct
-
-Revision 1.106 2006/08/14 23:24:22 cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.105 2006/07/15 02:01:28 cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Fix broken "empty string" browsing
-
-Revision 1.104 2006/07/05 23:09:13 cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
-
-Revision 1.103 2006/06/29 07:42:14 cheshire
-<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
-
-Revision 1.102 2006/06/22 19:49:11 cheshire
-Added (commented out) definitions for the LLMNR UDP port and multicast addresses
-
-Revision 1.101 2006/06/15 21:35:15 cheshire
-Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants
-from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code
-
-Revision 1.100 2006/06/08 22:58:46 cheshire
-<rdar://problem/4335605> IPv6 link-local address prefix is FE80::/10, not FE80::/16
-
-Revision 1.99 2006/05/18 01:32:33 cheshire
-<rdar://problem/4472706> iChat: Lost connection with Bonjour
-(mDNSResponder insufficiently defensive against malformed browsing PTR responses)
-
-Revision 1.98 2006/03/19 17:00:58 cheshire
-Define symbol MaxMsg instead of using hard-coded constant value '80'
-
-Revision 1.97 2006/03/18 21:47:56 cheshire
-<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-
-Revision 1.96 2006/03/10 21:51:42 cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-Split out SameRDataBody() into a separate routine so it can be called from other code
-
-Revision 1.95 2006/03/08 22:43:11 cheshire
-Use "localdomain" symbol instead of literal string
-
-Revision 1.94 2006/03/02 21:59:55 cheshire
-<rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
-Improve sanity checks & debugging support in GetLargeResourceRecord()
-
-Revision 1.93 2006/03/02 20:30:47 cheshire
-Improved GetRRDisplayString to also show priority, weight, and port for SRV records
-
-*/
+ */
// Set mDNS_InstantiateInlines to tell mDNSEmbeddedAPI.h to instantiate inline functions, if necessary
#define mDNS_InstantiateInlines 1
@@ -580,20 +35,11 @@ Improved GetRRDisplayString to also show priority, weight, and port for SRV reco
#pragma mark - Program Constants
#endif
-mDNSexport const mDNSIPPort zeroIPPort = { { 0 } };
-mDNSexport const mDNSv4Addr zerov4Addr = { { 0 } };
-mDNSexport const mDNSv6Addr zerov6Addr = { { 0 } };
-mDNSexport const mDNSEthAddr zeroEthAddr = { { 0 } };
-mDNSexport const mDNSv4Addr onesIPv4Addr = { { 255, 255, 255, 255 } };
-mDNSexport const mDNSv6Addr onesIPv6Addr = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } };
-mDNSexport const mDNSAddr zeroAddr = { mDNSAddrType_None, {{{ 0 }}} };
-mDNSexport const mDNSEthAddr onesEthAddr = { { 255, 255, 255, 255, 255, 255 } };
-
-mDNSexport const OwnerOptData zeroOwner = { 0, 0, { { 0 } }, { { 0 } }, { { 0 } } };
-
mDNSexport const mDNSInterfaceID mDNSInterface_Any = 0;
-mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)1;
-mDNSexport const mDNSInterfaceID mDNSInterface_Unicast = (mDNSInterfaceID)2;
+mDNSexport const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)-1;
+mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)-2;
+mDNSexport const mDNSInterfaceID mDNSInterface_Unicast = (mDNSInterfaceID)-3;
+mDNSexport const mDNSInterfaceID mDNSInterface_P2P = (mDNSInterfaceID)-4;
// Note: Microsoft's proposed "Link Local Multicast Name Resolution Protocol" (LLMNR) is essentially a limited version of
// Multicast DNS, using the same packet formats, naming syntax, and record types as Multicast DNS, but on a different UDP
@@ -606,6 +52,7 @@ mDNSexport const mDNSInterfaceID mDNSInterface_Unicast = (mDNSInterfaceID)2;
#define SSHPortAsNumber 22
#define UnicastDNSPortAsNumber 53
#define SSDPPortAsNumber 1900
+#define IPSECPortAsNumber 4500
#define NSIPCPortAsNumber 5030 // Port used for dnsextd to talk to local nameserver bound to loopback
#define NATPMPAnnouncementPortAsNumber 5350
#define NATPMPPortAsNumber 5351
@@ -619,6 +66,7 @@ mDNSexport const mDNSIPPort DiscardPort = { { DiscardPortAsNumber
mDNSexport const mDNSIPPort SSHPort = { { SSHPortAsNumber >> 8, SSHPortAsNumber & 0xFF } };
mDNSexport const mDNSIPPort UnicastDNSPort = { { UnicastDNSPortAsNumber >> 8, UnicastDNSPortAsNumber & 0xFF } };
mDNSexport const mDNSIPPort SSDPPort = { { SSDPPortAsNumber >> 8, SSDPPortAsNumber & 0xFF } };
+mDNSexport const mDNSIPPort IPSECPort = { { IPSECPortAsNumber >> 8, IPSECPortAsNumber & 0xFF } };
mDNSexport const mDNSIPPort NSIPCPort = { { NSIPCPortAsNumber >> 8, NSIPCPortAsNumber & 0xFF } };
mDNSexport const mDNSIPPort NATPMPAnnouncementPort = { { NATPMPAnnouncementPortAsNumber >> 8, NATPMPAnnouncementPortAsNumber & 0xFF } };
mDNSexport const mDNSIPPort NATPMPPort = { { NATPMPPortAsNumber >> 8, NATPMPPortAsNumber & 0xFF } };
@@ -627,12 +75,26 @@ mDNSexport const mDNSIPPort MulticastDNSPort = { { MulticastDNSPortAsNumbe
mDNSexport const mDNSIPPort LoopbackIPCPort = { { LoopbackIPCPortAsNumber >> 8, LoopbackIPCPortAsNumber & 0xFF } };
mDNSexport const mDNSIPPort PrivateDNSPort = { { PrivateDNSPortAsNumber >> 8, PrivateDNSPortAsNumber & 0xFF } };
-mDNSexport const mDNSv4Addr AllDNSAdminGroup = { { 239, 255, 255, 251 } };
-mDNSexport const mDNSv4Addr AllSystemsMcast = { { 224, 0, 0, 1 } }; // For NAT-PMP Annoucements
-mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 251 } } } };
-//mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 252 } } } }; // LLMNR
-mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } };
-//mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x01,0x00,0x03 } } } }; // LLMNR
+mDNSexport const OwnerOptData zeroOwner = { 0, 0, { { 0 } }, { { 0 } }, { { 0 } } };
+
+mDNSexport const mDNSIPPort zeroIPPort = { { 0 } };
+mDNSexport const mDNSv4Addr zerov4Addr = { { 0 } };
+mDNSexport const mDNSv6Addr zerov6Addr = { { 0 } };
+mDNSexport const mDNSEthAddr zeroEthAddr = { { 0 } };
+mDNSexport const mDNSv4Addr onesIPv4Addr = { { 255, 255, 255, 255 } };
+mDNSexport const mDNSv6Addr onesIPv6Addr = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } };
+mDNSexport const mDNSEthAddr onesEthAddr = { { 255, 255, 255, 255, 255, 255 } };
+mDNSexport const mDNSAddr zeroAddr = { mDNSAddrType_None, {{{ 0 }}} };
+
+mDNSexport const mDNSv4Addr AllDNSAdminGroup = { { 239, 255, 255, 251 } };
+mDNSexport const mDNSv4Addr AllHosts_v4 = { { 224, 0, 0, 1 } }; // For NAT-PMP Annoucements
+mDNSexport const mDNSv6Addr AllHosts_v6 = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01 } };
+mDNSexport const mDNSv6Addr NDP_prefix = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01, 0xFF,0x00,0x00,0xFB } }; // FF02:0:0:0:0:1:FF00::/104
+mDNSexport const mDNSEthAddr AllHosts_v6_Eth = { { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 } };
+mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 251 } } } };
+//mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 252 } } } }; // LLMNR
+mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } };
+//mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x01,0x00,0x03 } } } }; // LLMNR
mDNSexport const mDNSOpaque16 zeroID = { { 0, 0 } };
mDNSexport const mDNSOpaque16 onesID = { { 255, 255 } };
@@ -783,7 +245,7 @@ mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RD
break;
case kDNSType_NSEC: {
- int i;
+ mDNSu16 i;
for (i=0; i<255; i++)
if (rd->nsec.bitmap[i>>3] & (128 >> (i&7)))
length += mDNS_snprintf(buffer+length, RemSpc, "%s ", DNSTypeName(i));
@@ -1274,16 +736,16 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
src = type->c; // Put the service type into the domain name
len = *src;
- if (len < 2 || len > 15)
+ if (len < 2 || len > 16)
{
- LogMsg("Bad service type in %#s.%##s%##s Application protocol name must be underscore plus 1-14 characters. "
+ LogMsg("Bad service type in %#s.%##s%##s Application protocol name must be underscore plus 1-15 characters. "
"See <http://www.dns-sd.org/ServiceTypes.html>", name->c, type->c, domain->c);
#if APPLE_OSX_mDNSResponder
ConvertDomainNameToCString(type, typeBuf);
mDNSASLLog(mDNSNULL, "serviceType.nameTooLong", "noop", typeBuf, "");
#endif
}
- if (len < 2 || len >= 0x40 || (len > 15 && !SameDomainName(domain, &localdomain))) return(mDNSNULL);
+ if (len < 2 || len >= 0x40 || (len > 16 && !SameDomainName(domain, &localdomain))) return(mDNSNULL);
if (src[1] != '_') { errormsg = "Application protocol name must begin with underscore"; goto fail; }
for (i=2; i<=len; i++)
{
@@ -1542,6 +1004,7 @@ mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mD
rr->resrec.rrtype = rrtype;
rr->resrec.rrclass = kDNSClass_IN;
rr->resrec.rroriginalttl = ttl;
+ rr->resrec.rDNSServer = mDNSNULL;
// rr->resrec.rdlength = MUST set by client and/or in mDNS_Register_internal
// rr->resrec.rdestimate = set in mDNS_Register_internal
// rr->resrec.rdata = MUST be set by client
@@ -1583,8 +1046,6 @@ mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mD
rr->Private = 0;
rr->updateid = zeroID;
rr->zone = rr->resrec.name;
- rr->UpdateServer = zeroAddr;
- rr->UpdatePort = zeroIPPort;
rr->nta = mDNSNULL;
rr->tcp = mDNSNULL;
rr->OrigRData = 0;
@@ -1593,6 +1054,9 @@ mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mD
rr->InFlightRDLen = 0;
rr->QueuedRData = 0;
rr->QueuedRDLen = 0;
+ mDNSPlatformMemZero(&rr->NATinfo, sizeof(rr->NATinfo));
+ rr->SRVChanged = mDNSfalse;
+ rr->mState = mergeState_Zero;
rr->namestorage.c[0] = 0; // MUST be set by client before calling mDNS_Register()
}
@@ -1609,6 +1073,7 @@ mDNSexport void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID I
q->ExpectUnique = (qtype != kDNSType_PTR);
q->ForceMCast = mDNSfalse;
q->ReturnIntermed = mDNSfalse;
+ q->SuppressUnusable = mDNSfalse;
q->QuestionCallback = callback;
q->QuestionContext = context;
}
@@ -1667,7 +1132,7 @@ mDNSexport mDNSu32 RDataHashValue(const ResourceRecord *const rr)
// r1 has to be a full ResourceRecord including rrtype and rdlength
// r2 is just a bare RDataBody, which MUST be the same rrtype and rdlength as r1
-mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2)
+mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2, DomainNameComparisonFn *samename)
{
const RDataBody2 *const b1 = (RDataBody2 *)r1->rdata->u.data;
const RDataBody2 *const b2 = (RDataBody2 *)r2;
@@ -1683,26 +1148,26 @@ mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBod
b1->soa.retry == b2->soa.retry &&
b1->soa.expire == b2->soa.expire &&
b1->soa.min == b2->soa.min &&
- SameDomainName(&b1->soa.mname, &b2->soa.mname) &&
- SameDomainName(&b1->soa.rname, &b2->soa.rname));
+ samename(&b1->soa.mname, &b2->soa.mname) &&
+ samename(&b1->soa.rname, &b2->soa.rname));
case kDNSType_MX:
case kDNSType_AFSDB:
case kDNSType_RT:
case kDNSType_KX: return(mDNSBool)( b1->mx.preference == b2->mx.preference &&
- SameDomainName(&b1->mx.exchange, &b2->mx.exchange));
+ samename(&b1->mx.exchange, &b2->mx.exchange));
- case kDNSType_RP: return(mDNSBool)( SameDomainName(&b1->rp.mbox, &b2->rp.mbox) &&
- SameDomainName(&b1->rp.txt, &b2->rp.txt));
+ case kDNSType_RP: return(mDNSBool)( samename(&b1->rp.mbox, &b2->rp.mbox) &&
+ samename(&b1->rp.txt, &b2->rp.txt));
case kDNSType_PX: return(mDNSBool)( b1->px.preference == b2->px.preference &&
- SameDomainName(&b1->px.map822, &b2->px.map822) &&
- SameDomainName(&b1->px.mapx400, &b2->px.mapx400));
+ samename(&b1->px.map822, &b2->px.map822) &&
+ samename(&b1->px.mapx400, &b2->px.mapx400));
case kDNSType_SRV: return(mDNSBool)( b1->srv.priority == b2->srv.priority &&
b1->srv.weight == b2->srv.weight &&
mDNSSameIPPort(b1->srv.port, b2->srv.port) &&
- SameDomainName(&b1->srv.target, &b2->srv.target));
+ samename(&b1->srv.target, &b2->srv.target));
case kDNSType_OPT: return mDNSfalse; // OPT is a pseudo-RR container structure; makes no sense to compare
@@ -1725,6 +1190,9 @@ mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr
q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
+ // Resource record received via unicast, the DNSServer entries should match ?
+ if (!rr->InterfaceID && rr->rDNSServer != q->qDNSServer) return(mDNSfalse);
+
// If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question
if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
@@ -1741,7 +1209,14 @@ mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr
q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
- // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question
+ // Resource record received via unicast, the DNSServer entries should match ?
+ if (!rr->InterfaceID && rr->rDNSServer != q->qDNSServer) return(mDNSfalse);
+
+ // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question.
+ // This also covers the case where the ResourceRecord is mDNSInterface_LocalOnly and the question is expecting a unicast
+ // DNS response. We don't want a local process to be able to create a fake LocalOnly address record for "www.bigbank.com"
+ // which would then cause other applications (e.g. Safari) to connect to the wrong address. If we decide to support this later,
+ // the restrictions need to be at least as strict as the restrictions on who can edit /etc/hosts and put fake addresses there.
if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
// RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
@@ -1757,6 +1232,11 @@ mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr,
q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
+ // Resource record received via unicast, the DNSServer entries should match ?
+ // Note that Auth Records are normally setup with NULL InterfaceID and
+ // both the DNSServers are assumed to be NULL in that case
+ if (!rr->InterfaceID && rr->rDNSServer != q->qDNSServer) return(mDNSfalse);
+
// If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question
if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
@@ -1765,6 +1245,20 @@ mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr,
return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
}
+// This is called only when the caller knows that it is a Unicast Resource Record and it is a Unicast Question
+// and hence we don't need InterfaceID checks like above. Though this may not be a big optimization, the main
+// reason we need this is that we can't compare DNSServers between the question and the resource record because
+// the resource record may not be completely initialized e.g., mDNSCoreReceiveResponse
+mDNSexport mDNSBool UnicastResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
+ {
+ // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
+ if (!RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
+
+ if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
+
+ return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
+ }
+
mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate)
{
const RDataBody2 *const rd = (RDataBody2 *)rr->rdata->u.data;
@@ -1815,10 +1309,11 @@ mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate
for (i=sizeof(rdataNSEC); i>0; i--) if (rd->nsec.bitmap[i-1]) break;
// For our simplified use of NSEC synthetic records:
// nextname is always the record's own name,
- // the block number is always 0,
- // the count byte is a value in the range 1-32,
- // followed by the 1-32 data bytes
- return((estimate ? 1 : DomainNameLength(rr->name)) + 2 + i);
+ // and if we have at least one record type that exists,
+ // - the block number is always 0,
+ // - the count byte is a value in the range 1-32,
+ // - followed by the 1-32 data bytes
+ return(mDNSu16)((estimate ? 2 : DomainNameLength(rr->name)) + (i ? (2 + i) : 0));
}
default: debugf("Warning! Don't know how to get length of resource type %d", rr->rrtype);
@@ -2103,7 +1598,7 @@ mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNS
{
const int space = DNSOpt_Data_Space(opt);
ptr = putVal16(ptr, opt->opt);
- ptr = putVal16(ptr, space - 4);
+ ptr = putVal16(ptr, (mDNSu16)space - 4);
switch (opt->opt)
{
case kDNSOpt_LLQ:
@@ -2148,10 +1643,13 @@ mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNS
for (i=sizeof(rdataNSEC); i>0; i--) if (rdb->nsec.bitmap[i-1]) break;
ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
if (!ptr) return(mDNSNULL);
- if (ptr + 2 + i > limit) return(mDNSNULL);
- *ptr++ = 0;
- *ptr++ = i;
- for (j=0; j<i; j++) *ptr++ = rdb->nsec.bitmap[j];
+ if (i) // Only put a block if at least one type exists for this name
+ {
+ if (ptr + 2 + i > limit) return(mDNSNULL);
+ *ptr++ = 0;
+ *ptr++ = (mDNSu8)i;
+ for (j=0; j<i; j++) *ptr++ = rdb->nsec.bitmap[j];
+ }
return ptr;
}
@@ -2189,6 +1687,8 @@ mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *
ptr[5] = (mDNSu8)((ttl >> 16) & 0xFF);
ptr[6] = (mDNSu8)((ttl >> 8) & 0xFF);
ptr[7] = (mDNSu8)( ttl & 0xFF);
+ // ptr[8] and ptr[9] filled in *after* we find out how much space the rdata takes
+
endofrdata = putRData(rdatacompressionbase, ptr+10, limit, rr);
if (!endofrdata) { verbosedebugf("Ran out of space in PutResourceRecord for %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype)); return(mDNSNULL); }
@@ -2264,9 +1764,19 @@ mDNSexport mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecor
return ptr;
}
-mDNSexport mDNSu8 *putDeleteRRSet(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype)
+// for dynamic updates
+mDNSexport mDNSu8 *putDeletionRecordWithLimit(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr, mDNSu8 *limit)
+ {
+ // deletion: specify record w/ TTL 0, class NONE
+ const mDNSu16 origclass = rr->rrclass;
+ rr->rrclass = kDNSClass_NONE;
+ ptr = PutResourceRecordTTLWithLimit(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0, limit);
+ rr->rrclass = origclass;
+ return ptr;
+ }
+
+mDNSexport mDNSu8 *putDeleteRRSetWithLimit(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype, mDNSu8 *limit)
{
- const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
mDNSu16 class = kDNSQClass_ANY;
ptr = putDomainNameAsLabels(msg, ptr, limit, name);
@@ -2317,7 +1827,22 @@ mDNSexport mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease)
return end;
}
-mDNSexport mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end, DomainAuthInfo *authInfo)
+// for dynamic updates
+mDNSexport mDNSu8 *putUpdateLeaseWithLimit(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease, mDNSu8 *limit)
+ {
+ AuthRecord rr;
+ mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
+ rr.resrec.rrclass = NormalMaxDNSMessageData;
+ rr.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record
+ rr.resrec.rdestimate = sizeof(rdataOPT);
+ rr.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease;
+ rr.resrec.rdata->u.opt[0].u.updatelease = lease;
+ end = PutResourceRecordTTLWithLimit(msg, end, &msg->h.numAdditionals, &rr.resrec, 0, limit);
+ if (!end) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTLWithLimit"); return mDNSNULL; }
+ return end;
+ }
+
+mDNSexport mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end, DomainAuthInfo *authInfo, mDNSu8 *limit)
{
if (authInfo && authInfo->AutoTunnel)
{
@@ -2334,7 +1859,7 @@ mDNSexport mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *
mDNSPlatformMemCopy(h, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]);
hinfo.resrec.rdlength = len;
hinfo.resrec.rdestimate = len;
- newptr = PutResourceRecord(msg, end, &msg->h.numAdditionals, &hinfo.resrec);
+ newptr = PutResourceRecordTTLWithLimit(msg, end, &msg->h.numAdditionals, &hinfo.resrec, 0, limit);
return newptr;
}
else
@@ -2471,13 +1996,6 @@ mDNSexport const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8
return(ptr + pktrdlength);
}
-mDNSlocal mDNSu16 getVal16(const mDNSu8 **ptr)
- {
- mDNSu16 val = (mDNSu16)(((mDNSu16)(*ptr)[0]) << 8 | (*ptr)[1]);
- *ptr += sizeof(mDNSOpaque16);
- return val;
- }
-
mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr,
const mDNSu8 *end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *const largecr)
{
@@ -2499,7 +2017,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
rr->NextInKAList = mDNSNULL;
rr->TimeRcvd = m ? m->timenow : 0;
rr->DelayDelivery = 0;
- rr->NextRequiredQuery = m ? m->timenow : 0; // Will be updated to the real value when we call SetNextCacheCheckTime()
+ rr->NextRequiredQuery = m ? m->timenow : 0; // Will be updated to the real value when we call SetNextCacheCheckTimeForRecord()
rr->LastUsed = m ? m->timenow : 0;
rr->CRActiveQuestion = mDNSNULL;
rr->UnansweredQueries = 0;
@@ -2513,8 +2031,11 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
rr->NextInCFList = mDNSNULL;
rr->resrec.InterfaceID = InterfaceID;
- ptr = getDomainName(msg, ptr, end, &largecr->namestorage);
+ rr->resrec.rDNSServer = mDNSNULL;
+
+ ptr = getDomainName(msg, ptr, end, &largecr->namestorage); // Will bail out correctly if ptr is NULL
if (!ptr) { debugf("GetLargeResourceRecord: Malformed RR name"); return(mDNSNULL); }
+ rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
if (ptr + 10 > end) { debugf("GetLargeResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
@@ -2550,7 +2071,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
rr->resrec.rdlength = 0;
else switch (rr->resrec.rrtype)
{
- case kDNSType_A: if (pktrdlength != sizeof(mDNSv4Addr)) return(mDNSNULL);
+ case kDNSType_A: if (pktrdlength != sizeof(mDNSv4Addr)) goto fail;
rdb->ipv4.b[0] = ptr[0];
rdb->ipv4.b[1] = ptr[1];
rdb->ipv4.b[2] = ptr[2];
@@ -2561,21 +2082,21 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
case kDNSType_CNAME:
case kDNSType_PTR:
case kDNSType_DNAME:ptr = getDomainName(msg, ptr, end, &rdb->name);
- if (ptr != end) { debugf("GetLargeResourceRecord: Malformed CNAME/PTR RDATA name"); return(mDNSNULL); }
+ if (ptr != end) { debugf("GetLargeResourceRecord: Malformed CNAME/PTR RDATA name"); goto fail; }
//debugf("%##s PTR %##s rdlen %d", rr->resrec.name.c, rdb->name.c, pktrdlength);
break;
case kDNSType_SOA: ptr = getDomainName(msg, ptr, end, &rdb->soa.mname);
- if (!ptr) { debugf("GetLargeResourceRecord: Malformed SOA RDATA mname"); return mDNSNULL; }
+ if (!ptr) { debugf("GetLargeResourceRecord: Malformed SOA RDATA mname"); goto fail; }
ptr = getDomainName(msg, ptr, end, &rdb->soa.rname);
- if (!ptr) { debugf("GetLargeResourceRecord: Malformed SOA RDATA rname"); return mDNSNULL; }
- if (ptr + 0x14 != end) { debugf("GetLargeResourceRecord: Malformed SOA RDATA"); return mDNSNULL; }
- rdb->soa.serial = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]);
- rdb->soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]);
- rdb->soa.retry = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]);
- rdb->soa.expire = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]);
- rdb->soa.min = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]);
- break;
+ if (!ptr) { debugf("GetLargeResourceRecord: Malformed SOA RDATA rname"); goto fail; }
+ if (ptr + 0x14 != end) { debugf("GetLargeResourceRecord: Malformed SOA RDATA"); goto fail; }
+ rdb->soa.serial = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]);
+ rdb->soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]);
+ rdb->soa.retry = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]);
+ rdb->soa.expire = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]);
+ rdb->soa.min = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]);
+ break;
case kDNSType_NULL:
case kDNSType_HINFO:
@@ -2588,7 +2109,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
{
debugf("GetLargeResourceRecord: %s rdata size (%d) exceeds storage (%d)",
DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
- return(mDNSNULL);
+ goto fail;
}
rr->resrec.rdlength = pktrdlength;
mDNSPlatformMemCopy(rdb->data, ptr, pktrdlength);
@@ -2597,38 +2118,38 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
case kDNSType_MX:
case kDNSType_AFSDB:
case kDNSType_RT:
- case kDNSType_KX: if (pktrdlength < 3) return(mDNSNULL); // Preference + domainname
+ case kDNSType_KX: if (pktrdlength < 3) goto fail; // Preference + domainname
rdb->mx.preference = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
ptr = getDomainName(msg, ptr+2, end, &rdb->mx.exchange);
- if (ptr != end) { debugf("GetLargeResourceRecord: Malformed MX name"); return(mDNSNULL); }
+ if (ptr != end) { debugf("GetLargeResourceRecord: Malformed MX name"); goto fail; }
//debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rdb->srv.target.c, pktrdlength);
break;
case kDNSType_RP: ptr = getDomainName(msg, ptr, end, &rdb->rp.mbox); // Domainname + domainname
- if (!ptr) { debugf("GetLargeResourceRecord: Malformed RP mbox"); return mDNSNULL; }
+ if (!ptr) { debugf("GetLargeResourceRecord: Malformed RP mbox"); goto fail; }
ptr = getDomainName(msg, ptr, end, &rdb->rp.txt);
- if (ptr != end) { debugf("GetLargeResourceRecord: Malformed RP txt"); return mDNSNULL; }
+ if (ptr != end) { debugf("GetLargeResourceRecord: Malformed RP txt"); goto fail; }
break;
- case kDNSType_PX: if (pktrdlength < 4) return(mDNSNULL); // Preference + domainname + domainname
+ case kDNSType_PX: if (pktrdlength < 4) goto fail; // Preference + domainname + domainname
rdb->px.preference = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
ptr = getDomainName(msg, ptr, end, &rdb->px.map822);
- if (!ptr) { debugf("GetLargeResourceRecord: Malformed PX map822"); return mDNSNULL; }
+ if (!ptr) { debugf("GetLargeResourceRecord: Malformed PX map822"); goto fail; }
ptr = getDomainName(msg, ptr, end, &rdb->px.mapx400);
- if (ptr != end) { debugf("GetLargeResourceRecord: Malformed PX mapx400"); return mDNSNULL; }
+ if (ptr != end) { debugf("GetLargeResourceRecord: Malformed PX mapx400"); goto fail; }
break;
- case kDNSType_AAAA: if (pktrdlength != sizeof(mDNSv6Addr)) return(mDNSNULL);
+ case kDNSType_AAAA: if (pktrdlength != sizeof(mDNSv6Addr)) goto fail;
mDNSPlatformMemCopy(&rdb->ipv6, ptr, sizeof(rdb->ipv6));
break;
- case kDNSType_SRV: if (pktrdlength < 7) return(mDNSNULL); // Priority + weight + port + domainname
+ case kDNSType_SRV: if (pktrdlength < 7) goto fail; // Priority + weight + port + domainname
rdb->srv.priority = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
rdb->srv.weight = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
rdb->srv.port.b[0] = ptr[4];
rdb->srv.port.b[1] = ptr[5];
ptr = getDomainName(msg, ptr+6, end, &rdb->srv.target);
- if (ptr != end) { debugf("GetLargeResourceRecord: Malformed SRV RDATA name"); return(mDNSNULL); }
+ if (ptr != end) { debugf("GetLargeResourceRecord: Malformed SRV RDATA name"); goto fail; }
//debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rdb->srv.target.c, pktrdlength);
break;
@@ -2637,49 +2158,60 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
rr->resrec.rdlength = 0;
while (ptr < end && (mDNSu8 *)(opt+1) < rr->resrec.rdata->u.data + MaximumRDSize)
{
- if (ptr + 4 > end) { LogMsg("GetLargeResourceRecord: OPT RDATA ptr + 4 > end"); return(mDNSNULL); }
- opt->opt = getVal16(&ptr);
- opt->optlen = getVal16(&ptr);
- if (!ValidDNSOpt(opt)) { LogMsg("GetLargeResourceRecord: opt %d optlen %d wrong", opt->opt, opt->optlen); return(mDNSNULL); }
- if (ptr + opt->optlen > end) { LogMsg("GetLargeResourceRecord: ptr + opt->optlen > end"); return(mDNSNULL); }
- switch(opt->opt)
+ const rdataOPT *const currentopt = opt;
+ if (ptr + 4 > end) { LogInfo("GetLargeResourceRecord: OPT RDATA ptr + 4 > end"); goto fail; }
+ opt->opt = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
+ opt->optlen = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
+ ptr += 4;
+ if (ptr + opt->optlen > end) { LogInfo("GetLargeResourceRecord: ptr + opt->optlen > end"); goto fail; }
+ switch (opt->opt)
{
case kDNSOpt_LLQ:
- opt->u.llq.vers = getVal16(&ptr);
- opt->u.llq.llqOp = getVal16(&ptr);
- opt->u.llq.err = getVal16(&ptr);
- mDNSPlatformMemCopy(opt->u.llq.id.b, ptr, 8);
- ptr += 8;
- opt->u.llq.llqlease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
- if (opt->u.llq.llqlease > 0x70000000UL / mDNSPlatformOneSecond)
- opt->u.llq.llqlease = 0x70000000UL / mDNSPlatformOneSecond;
- ptr += sizeof(mDNSOpaque32);
+ if (opt->optlen == DNSOpt_LLQData_Space - 4)
+ {
+ opt->u.llq.vers = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
+ opt->u.llq.llqOp = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
+ opt->u.llq.err = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
+ mDNSPlatformMemCopy(opt->u.llq.id.b, ptr+6, 8);
+ opt->u.llq.llqlease = (mDNSu32) ((mDNSu32)ptr[14] << 24 | (mDNSu32)ptr[15] << 16 | (mDNSu32)ptr[16] << 8 | ptr[17]);
+ if (opt->u.llq.llqlease > 0x70000000UL / mDNSPlatformOneSecond)
+ opt->u.llq.llqlease = 0x70000000UL / mDNSPlatformOneSecond;
+ opt++;
+ }
break;
case kDNSOpt_Lease:
- opt->u.updatelease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
- if (opt->u.updatelease > 0x70000000UL / mDNSPlatformOneSecond)
- opt->u.updatelease = 0x70000000UL / mDNSPlatformOneSecond;
- ptr += sizeof(mDNSs32);
+ if (opt->optlen == DNSOpt_LeaseData_Space - 4)
+ {
+ opt->u.updatelease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
+ if (opt->u.updatelease > 0x70000000UL / mDNSPlatformOneSecond)
+ opt->u.updatelease = 0x70000000UL / mDNSPlatformOneSecond;
+ opt++;
+ }
break;
case kDNSOpt_Owner:
- opt->u.owner.vers = ptr[0];
- opt->u.owner.seq = ptr[1];
- mDNSPlatformMemCopy(opt->u.owner.HMAC.b, ptr+2, 6); // 6-byte MAC address
- mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+2, 6); // 6-byte MAC address
- opt->u.owner.password = zeroEthAddr;
- if (opt->optlen >= DNSOpt_OwnerData_ID_Wake_Space-4)
+ if (ValidOwnerLength(opt->optlen))
{
- mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+8, 6); // 6-byte MAC address
- if (opt->optlen > DNSOpt_OwnerData_ID_Wake_Space-4)
- mDNSPlatformMemCopy(opt->u.owner.password.b, ptr+14, opt->optlen - (DNSOpt_OwnerData_ID_Wake_Space-4));
+ opt->u.owner.vers = ptr[0];
+ opt->u.owner.seq = ptr[1];
+ mDNSPlatformMemCopy(opt->u.owner.HMAC.b, ptr+2, 6); // 6-byte MAC address
+ mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+2, 6); // 6-byte MAC address
+ opt->u.owner.password = zeroEthAddr;
+ if (opt->optlen >= DNSOpt_OwnerData_ID_Wake_Space-4)
+ {
+ mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+8, 6); // 6-byte MAC address
+ // This mDNSPlatformMemCopy is safe because the ValidOwnerLength(opt->optlen) check above
+ // ensures that opt->optlen is no more than DNSOpt_OwnerData_ID_Wake_PW6_Space - 4
+ if (opt->optlen > DNSOpt_OwnerData_ID_Wake_Space-4)
+ mDNSPlatformMemCopy(opt->u.owner.password.b, ptr+14, opt->optlen - (DNSOpt_OwnerData_ID_Wake_Space-4));
+ }
+ opt++;
}
- ptr += opt->optlen;
break;
}
- opt++; // increment pointer into rdatabody
+ ptr += currentopt->optlen;
}
- rr->resrec.rdlength = (mDNSu8*)opt - rr->resrec.rdata->u.data;
- if (ptr != end) { LogMsg("GetLargeResourceRecord: Malformed OptRdata"); return(mDNSNULL); }
+ rr->resrec.rdlength = (mDNSu16)((mDNSu8*)opt - rr->resrec.rdata->u.data);
+ if (ptr != end) { LogInfo("GetLargeResourceRecord: Malformed OptRdata"); goto fail; }
break;
}
@@ -2687,13 +2219,16 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
unsigned int i, j;
domainname d;
ptr = getDomainName(msg, ptr, end, &d); // Ignored for our simplified use of NSEC synthetic records
- if (!ptr) { debugf("GetLargeResourceRecord: Malformed NSEC nextname"); return mDNSNULL; }
- if (*ptr++ != 0) { debugf("GetLargeResourceRecord: We only handle block zero NSECs"); return mDNSNULL; }
- i = *ptr++;
- if (i < 1 || i > sizeof(rdataNSEC)) { debugf("GetLargeResourceRecord: invalid block length %d", i); return mDNSNULL; }
+ if (!ptr) { LogInfo("GetLargeResourceRecord: Malformed NSEC nextname"); goto fail; }
mDNSPlatformMemZero(rdb->nsec.bitmap, sizeof(rdb->nsec.bitmap));
- for (j=0; j<i; j++) rdb->nsec.bitmap[j] = *ptr++;
- if (ptr != end) { LogMsg("GetLargeResourceRecord: Malformed NSEC"); return(mDNSNULL); }
+ if (ptr < end)
+ {
+ if (*ptr++ != 0) { debugf("GetLargeResourceRecord: We only handle block zero NSECs"); goto fail; }
+ i = *ptr++;
+ if (i > sizeof(rdataNSEC)) { debugf("GetLargeResourceRecord: invalid block length %d", i); goto fail; }
+ for (j=0; j<i; j++) rdb->nsec.bitmap[j] = *ptr++;
+ }
+ if (ptr != end) { debugf("GetLargeResourceRecord: Malformed NSEC"); goto fail; }
break;
}
@@ -2701,7 +2236,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
{
debugf("GetLargeResourceRecord: rdata %d (%s) size (%d) exceeds storage (%d)",
rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
- return(mDNSNULL);
+ goto fail;
}
debugf("GetLargeResourceRecord: Warning! Reading resource type %d (%s) as opaque data",
rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype));
@@ -2715,12 +2250,20 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
break;
}
- rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rdlength, rdestimate, rdatahash for us
// Success! Now fill in RecordType to show this record contains valid data
rr->resrec.RecordType = RecordType;
return(end);
+
+fail:
+ // If we were unable to parse the rdata in this record, we indicate that by
+ // returing a 'kDNSRecordTypePacketNegative' record with rdlength set to zero
+ rr->resrec.RecordType = kDNSRecordTypePacketNegative;
+ rr->resrec.rdlength = 0;
+ rr->resrec.rdestimate = 0;
+ rr->resrec.rdatahash = 0;
+ return(end);
}
mDNSexport const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
@@ -2804,7 +2347,7 @@ mDNSexport const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const
if (ptr)
{
ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
- if (ptr) return(&m->rec.r.resrec.rdata->u.opt[0]);
+ if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative) return(&m->rec.r.resrec.rdata->u.opt[0]);
}
return(mDNSNULL);
}
@@ -2833,7 +2376,7 @@ mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg,
// embedded systems) putting a 9kB object on the stack isn't a big problem.
LargeCacheRecord largecr;
ptr = GetLargeResourceRecord(m, msg, ptr, end, mDNSInterface_Any, kDNSRecordTypePacketAns, &largecr);
- if (ptr) LogMsg("%2d TTL%7d %s", i, largecr.r.resrec.rroriginalttl, CRDisplayString(m, &largecr.r));
+ if (ptr) LogMsg("%2d TTL%8d %s", i, largecr.r.resrec.rroriginalttl, CRDisplayString(m, &largecr.r));
}
if (!ptr) LogMsg("ERROR: Premature end of packet data");
return(ptr);
@@ -2930,6 +2473,7 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
mStatus status = mStatus_NoError;
const mDNSu16 numAdditionals = msg->h.numAdditionals;
mDNSu8 *newend;
+ mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
// Zero-length message data is okay (e.g. for a DNS Update ack, where all we need is an ID and an error code
if (end < msg->data || end - msg->data > AbsoluteMaxDNSMessageData)
@@ -2938,8 +2482,8 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
return mStatus_BadParamErr;
}
- newend = putHINFO(m, msg, end, authInfo);
- if (!newend) LogMsg("mDNSSendDNSMessage: putHINFO failed"); // Not fatal
+ newend = putHINFO(m, msg, end, authInfo, limit);
+ if (!newend) LogMsg("mDNSSendDNSMessage: putHINFO failed msg %p end %p, limit %p", msg->data, end, limit); // Not fatal
else end = newend;
// Put all the integer values in IETF byte-order (MSB first, LSB second)
@@ -2985,7 +2529,7 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
#pragma mark - RR List Management & Task Management
#endif
-mDNSexport void mDNS_Lock_(mDNS *const m)
+mDNSexport void mDNS_Lock_(mDNS *const m, const char * const functionname)
{
// MUST grab the platform lock FIRST!
mDNSPlatformLock(m);
@@ -2994,26 +2538,26 @@ mDNSexport void mDNS_Lock_(mDNS *const m)
// However, when we call a client callback mDNS_busy is one, and we increment mDNS_reentrancy too
// If that client callback does mDNS API calls, mDNS_reentrancy and mDNS_busy will both be one
// If mDNS_busy != mDNS_reentrancy that's a bad sign
-#if ForceAlerts
if (m->mDNS_busy != m->mDNS_reentrancy)
{
- LogMsg("mDNS_Lock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+ LogMsg("%s: mDNS_Lock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", functionname, m->mDNS_busy, m->mDNS_reentrancy);
+#if ForceAlerts
*(long*)0 = 0;
- }
#endif
+ }
// If this is an initial entry into the mDNSCore code, set m->timenow
// else, if this is a re-entrant entry into the mDNSCore code, m->timenow should already be set
if (m->mDNS_busy == 0)
{
if (m->timenow)
- LogMsg("mDNS_Lock: m->timenow already set (%ld/%ld)", m->timenow, mDNS_TimeNow_NoLock(m));
+ LogMsg("%s: mDNS_Lock: m->timenow already set (%ld/%ld)", functionname, m->timenow, mDNS_TimeNow_NoLock(m));
m->timenow = mDNS_TimeNow_NoLock(m);
if (m->timenow == 0) m->timenow = 1;
}
else if (m->timenow == 0)
{
- LogMsg("mDNS_Lock: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy);
+ LogMsg("%s: mDNS_Lock: m->mDNS_busy is %ld but m->timenow not set", functionname, m->mDNS_busy);
m->timenow = mDNS_TimeNow_NoLock(m);
if (m->timenow == 0) m->timenow = 1;
}
@@ -3021,7 +2565,7 @@ mDNSexport void mDNS_Lock_(mDNS *const m)
if (m->timenow_last - m->timenow > 0)
{
m->timenow_adjust += m->timenow_last - m->timenow;
- LogMsg("mDNSPlatformRawTime went backwards by %ld ticks; setting correction factor to %ld", m->timenow_last - m->timenow, m->timenow_adjust);
+ LogMsg("%s: mDNSPlatformRawTime went backwards by %ld ticks; setting correction factor to %ld", functionname, m->timenow_last - m->timenow, m->timenow_adjust);
m->timenow = m->timenow_last;
}
m->timenow_last = m->timenow;
@@ -3030,6 +2574,14 @@ mDNSexport void mDNS_Lock_(mDNS *const m)
m->mDNS_busy++;
}
+mDNSlocal AuthRecord *AnyLocalRecordReady(const mDNS *const m)
+ {
+ AuthRecord *rr;
+ for (rr = m->NewLocalRecords; rr; rr = rr->next)
+ if (LocalRecordReady(rr)) return rr;
+ return mDNSNULL;
+ }
+
mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
{
mDNSs32 e = m->timenow + 0x78000000;
@@ -3039,17 +2591,22 @@ mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
if (m->NewQuestions->DelayAnswering) e = m->NewQuestions->DelayAnswering;
else return(m->timenow);
}
- if (m->NewLocalOnlyQuestions) return(m->timenow);
- if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords)) return(m->timenow);
- if (m->SPSProxyListChanged) return(m->timenow);
+ if (m->NewLocalOnlyQuestions) return(m->timenow);
+ if (m->NewLocalRecords && AnyLocalRecordReady(m)) return(m->timenow);
+ if (m->SPSProxyListChanged) return(m->timenow);
+ if (m->LocalRemoveEvents) return(m->timenow);
+
#ifndef UNICAST_DISABLED
if (e - m->NextuDNSEvent > 0) e = m->NextuDNSEvent;
if (e - m->NextScheduledNATOp > 0) e = m->NextScheduledNATOp;
+ if (m->NextSRVUpdate && e - m->NextSRVUpdate > 0) e = m->NextSRVUpdate;
#endif
+
if (e - m->NextCacheCheck > 0) e = m->NextCacheCheck;
if (e - m->NextScheduledSPS > 0) e = m->NextScheduledSPS;
- if (m->SleepLimit && e - m->NextScheduledSPRetry > 0) e = m->NextScheduledSPRetry;
- if (m->DelaySleep && e - m->DelaySleep > 0) e = m->DelaySleep;
+ // NextScheduledSPRetry only valid when DelaySleep not set
+ if (!m->DelaySleep && m->SleepLimit && e - m->NextScheduledSPRetry > 0) e = m->NextScheduledSPRetry;
+ if (m->DelaySleep && e - m->DelaySleep > 0) e = m->DelaySleep;
if (m->SuppressSending)
{
@@ -3081,56 +2638,67 @@ mDNSexport void ShowTaskSchedulingError(mDNS *const m)
LogMsg("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)",
m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
- if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords))
- LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m, m->NewLocalRecords));
+ if (m->NewLocalRecords)
+ {
+ AuthRecord *rr = AnyLocalRecordReady(m);
+ if (rr) LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m, rr));
+ }
+
+ if (m->SPSProxyListChanged) LogMsg("Task Scheduling Error: SPSProxyListChanged");
+ if (m->LocalRemoveEvents) LogMsg("Task Scheduling Error: LocalRemoveEvents");
if (m->timenow - m->NextScheduledEvent >= 0)
LogMsg("Task Scheduling Error: m->NextScheduledEvent %d", m->timenow - m->NextScheduledEvent);
- if (m->SuppressSending && m->timenow - m->SuppressSending >= 0)
- LogMsg("Task Scheduling Error: m->SuppressSending %d", m->timenow - m->SuppressSending);
+
+#ifndef UNICAST_DISABLED
+ if (m->timenow - m->NextuDNSEvent >= 0)
+ LogMsg("Task Scheduling Error: m->NextuDNSEvent %d", m->timenow - m->NextuDNSEvent);
+ if (m->timenow - m->NextScheduledNATOp >= 0)
+ LogMsg("Task Scheduling Error: m->NextScheduledNATOp %d", m->timenow - m->NextScheduledNATOp);
+ if (m->NextSRVUpdate && m->timenow - m->NextSRVUpdate >= 0)
+ LogMsg("Task Scheduling Error: m->NextSRVUpdate %d", m->timenow - m->NextSRVUpdate);
+#endif
+
if (m->timenow - m->NextCacheCheck >= 0)
LogMsg("Task Scheduling Error: m->NextCacheCheck %d", m->timenow - m->NextCacheCheck);
+ if (m->timenow - m->NextScheduledSPS >= 0)
+ LogMsg("Task Scheduling Error: m->NextScheduledSPS %d", m->timenow - m->NextScheduledSPS);
+ if (!m->DelaySleep && m->SleepLimit && m->timenow - m->NextScheduledSPRetry >= 0)
+ LogMsg("Task Scheduling Error: m->NextScheduledSPRetry %d", m->timenow - m->NextScheduledSPRetry);
+ if (m->DelaySleep && m->timenow - m->DelaySleep >= 0)
+ LogMsg("Task Scheduling Error: m->DelaySleep %d", m->timenow - m->DelaySleep);
+
+ if (m->SuppressSending && m->timenow - m->SuppressSending >= 0)
+ LogMsg("Task Scheduling Error: m->SuppressSending %d", m->timenow - m->SuppressSending);
if (m->timenow - m->NextScheduledQuery >= 0)
LogMsg("Task Scheduling Error: m->NextScheduledQuery %d", m->timenow - m->NextScheduledQuery);
if (m->timenow - m->NextScheduledProbe >= 0)
LogMsg("Task Scheduling Error: m->NextScheduledProbe %d", m->timenow - m->NextScheduledProbe);
if (m->timenow - m->NextScheduledResponse >= 0)
LogMsg("Task Scheduling Error: m->NextScheduledResponse %d", m->timenow - m->NextScheduledResponse);
- if (m->timenow - m->NextScheduledNATOp >= 0)
- LogMsg("Task Scheduling Error: m->NextScheduledNATOp %d", m->timenow - m->NextScheduledNATOp);
- if (m->timenow - m->NextScheduledSPS >= 0)
- LogMsg("Task Scheduling Error: m->NextScheduledSPS %d", m->timenow - m->NextScheduledSPS);
- if (m->SleepLimit && m->timenow - m->NextScheduledSPRetry >= 0)
- LogMsg("Task Scheduling Error: m->NextScheduledSPRetry %d", m->timenow - m->NextScheduledSPRetry);
- if (m->DelaySleep && m->timenow - m->DelaySleep >= 0)
- LogMsg("Task Scheduling Error: m->DelaySleep %d", m->timenow - m->DelaySleep);
-#ifndef UNICAST_DISABLED
- if (m->timenow - m->NextuDNSEvent >= 0)
- LogMsg("Task Scheduling Error: NextuDNSEvent %d", m->timenow - m->NextuDNSEvent);
-#endif
mDNS_Unlock(m);
}
-mDNSexport void mDNS_Unlock_(mDNS *const m)
+mDNSexport void mDNS_Unlock_(mDNS *const m, const char * const functionname)
{
// Decrement mDNS_busy
m->mDNS_busy--;
// Check for locking failures
-#if ForceAlerts
if (m->mDNS_busy != m->mDNS_reentrancy)
{
- LogMsg("mDNS_Unlock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+ LogMsg("%s: mDNS_Unlock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", functionname, m->mDNS_busy, m->mDNS_reentrancy);
+#if ForceAlerts
*(long*)0 = 0;
- }
#endif
+ }
// If this is a final exit from the mDNSCore code, set m->NextScheduledEvent and clear m->timenow
if (m->mDNS_busy == 0)
{
m->NextScheduledEvent = GetNextScheduledEvent(m);
- if (m->timenow == 0) LogMsg("mDNS_Unlock: ERROR! m->timenow aready zero");
+ if (m->timenow == 0) LogMsg("%s: mDNS_Unlock: ERROR! m->timenow aready zero", functionname);
m->timenow = 0;
}
@@ -3307,7 +2875,7 @@ mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt
break;
case 'p' : F.havePrecision = F.lSize = 1;
- F.precision = 8;
+ F.precision = sizeof(void*) * 2; // 8 characters on 32-bit; 16 characters on 64-bit
case 'X' : digits = "0123456789ABCDEF";
goto hexadecimal;
case 'x' : digits = "0123456789abcdef";
diff --git a/external/apache2/mDNSResponder/dist/mDNSCore/DNSDigest.c b/external/apache2/mDNSResponder/dist/mDNSCore/DNSDigest.c
index 3dabfa22d27..d3d0a5cdf7c 100644
--- a/external/apache2/mDNSResponder/dist/mDNSCore/DNSDigest.c
+++ b/external/apache2/mDNSResponder/dist/mDNSCore/DNSDigest.c
@@ -13,99 +13,7 @@
* 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: DNSDigest.c,v $
-Revision 1.26 2008/10/10 23:21:51 mcguire
-fixed typo in original MD5 source reference
-
-Revision 1.25 2007/12/17 23:48:29 cheshire
-DNSDigest_SignMessage doesn't need to return a result -- it already updates the 'end' parameter
-
-Revision 1.24 2007/11/30 23:03:51 cheshire
-Fixes for EFI: Use "mDNSPlatformMemCopy" instead of assuming existence of "memcpy"
-
-Revision 1.23 2007/09/21 21:12:36 cheshire
-DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter
-
-Revision 1.22 2007/04/22 06:02:02 cheshire
-<rdar://problem/4615977> Query should immediately return failure when no server
-
-Revision 1.21 2007/03/22 18:31:48 cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.20 2006/12/22 20:59:49 cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.19 2006/12/21 00:06:07 cheshire
-Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us
-
-Revision 1.18 2006/12/19 22:41:21 cheshire
-Fix compiler warnings
-
-Revision 1.17 2006/08/14 23:24:22 cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.16 2006/07/05 23:05:15 cheshire
-<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-Add DNSDigest_VerifyMessage() function
-
-Revision 1.15 2006/06/20 04:12:30 cheshire
-<rdar://problem/4490961> DNS Update broken
-
-Revision 1.14 2006/02/25 23:12:07 cheshire
-<rdar://problem/4427969> Fix to avoid code generation warning/error on FreeBSD 7
-
-Revision 1.13 2004/12/16 20:12:59 cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.12 2004/12/03 07:20:50 ksekar
-<rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
-
-Revision 1.11 2004/12/02 01:10:27 cheshire
-Fix to compile cleanly on 64-bit x86
-
-Revision 1.10 2004/11/01 20:36:04 ksekar
-<rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
-
-Revision 1.9 2004/10/26 09:00:12 cheshire
-Save a few bytes by creating HMAC_MD5_AlgName as a C string instead of a 256-byte object
-
-Revision 1.8 2004/09/17 01:08:48 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.7 2004/08/15 18:36:38 cheshire
-Don't use strcpy() and strlen() on "struct domainname" objects;
-use AssignDomainName() and DomainNameLength() instead
-(A "struct domainname" is a collection of packed pascal strings, not a C string.)
-
-Revision 1.6 2004/06/02 00:17:46 ksekar
-Referenced original OpenSSL license headers in source file description.
-
-Revision 1.5 2004/05/20 18:37:37 cheshire
-Fix compiler warnings
-
-Revision 1.4 2004/04/22 20:28:20 cheshire
-Use existing facility of PutResourceRecordTTL() to update count field for us
-
-Revision 1.3 2004/04/22 03:05:28 cheshire
-kDNSClass_ANY should be kDNSQClass_ANY
-
-Revision 1.2 2004/04/15 00:51:28 bradley
-Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
-Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
-
-Revision 1.1 2004/04/14 23:09:28 ksekar
-Support for TSIG signed dynamic updates.
-
-
-
-*/
+ */
#ifdef __cplusplus
@@ -524,6 +432,11 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num);
*
* <appro@fy.chalmers.se>
*/
+ /*
+ * LLVM is more strict about compatibility of types between input & output constraints,
+ * but we want these to be rotations of 32 bits, not 64, so we explicitly drop the
+ * most significant bytes by casting to an unsigned int.
+ */
# if defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__)
# define ROTATE(a,n) ({ register unsigned int ret; \
asm ( \
diff --git a/external/apache2/mDNSResponder/dist/mDNSCore/mDNS.c b/external/apache2/mDNSResponder/dist/mDNSCore/mDNS.c
index 83217b0d6d1..5aeba5c51f1 100755
--- a/external/apache2/mDNSResponder/dist/mDNSCore/mDNS.c
+++ b/external/apache2/mDNSResponder/dist/mDNSCore/mDNS.c
@@ -34,1460 +34,7 @@
* thinking that variables x and y are both of type "char*" -- and anyone who doesn't
* understand why variable y is not of type "char*" just proves the point that poor code
* layout leads people to unfortunate misunderstandings about how the C language really works.)
-
- Change History (most recent first):
-
-Log: mDNS.c,v $
-Revision 1.969.2.1 2009/07/23 23:41:25 cheshire
-<rdar://problem/7086623> Sleep Proxy: Ten-second maintenance wake not long enough to reliably get network connectivity
-
-Revision 1.969 2009/06/30 21:18:19 cheshire
-<rdar://problem/7020041> Plugging and unplugging the power cable shouldn't cause a network change event
-Additional fixes:
-1. Made mDNS_ActivateNetWake_internal and mDNS_DeactivateNetWake_internal more defensive against bad parameters
-2. mDNS_DeactivateNetWake_internal also needs to stop any outstanding Sleep Proxy resolve operations
-
-Revision 1.968 2009/06/29 23:51:09 cheshire
-<rdar://problem/6690034> Can't bind to Active Directory
-
-Revision 1.967 2009/06/27 00:25:27 cheshire
-<rdar://problem/6959273> mDNSResponder taking up 13% CPU with 400 KBps incoming bonjour requests
-Removed overly-complicate and ineffective multi-packet known-answer snooping code
-(Bracketed it with "#if ENABLE_MULTI_PACKET_QUERY_SNOOPING" for now; will delete actual code later)
-
-Revision 1.966 2009/06/26 01:55:55 cheshire
-<rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
-Additional refinements -- except for the case of explicit queries for record types we don't have (for names we own),
-add additional NSEC records only when there's space to do that without having to generate an additional packet
-
-Revision 1.965 2009/06/24 22:14:21 cheshire
-<rdar://problem/6911445> Plugging and unplugging the power cable shouldn't cause a network change event
-
-Revision 1.964 2009/06/03 23:07:13 cheshire
-<rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
-Large records were not being added in cases where an NSEC record was also required
-
-Revision 1.963 2009/05/28 00:39:19 cheshire
-<rdar://problem/6926465> Sleep is delayed by 10 seconds if BTMM is on
-After receiving confirmation of wide-area record deletion, need to schedule another evaluation of whether we're ready to sleep yet
-
-Revision 1.962 2009/05/19 23:40:37 cheshire
-<rdar://problem/6903507> Sleep Proxy: Retransmission logic not working reliably on quiet networks
-Added m->NextScheduledSPRetry timer for scheduling Sleep Proxy registration retries
-
-Revision 1.961 2009/05/19 23:00:43 cheshire
-Improved comments and debugging messages
-
-Revision 1.960 2009/05/13 17:25:33 mkrochma
-<rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
-Sleep proxy client should only look for services being advertised via Multicast
-
-Revision 1.959 2009/05/12 23:10:31 cheshire
-<rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
-Make new routine mDNSCoreHaveAdvertisedServices so daemon.c can tell whether it needs to schedule a maintenance wake
-
-Revision 1.958 2009/05/12 19:19:20 cheshire
-<rdar://problem/6879925> Sleep Proxy delays sleep by ten seconds when logged in to VPN
-
-Revision 1.957 2009/05/07 23:56:25 cheshire
-<rdar://problem/6601427> Retransmit and retry Sleep Proxy Server requests
-To get negative answers for our AAAA query we need to set the ReturnIntermed flag on the NetWakeResolve question
-
-Revision 1.956 2009/05/07 23:46:27 cheshire
-<rdar://problem/6601427> Retransmit and retry Sleep Proxy Server requests
-
-Revision 1.955 2009/05/07 23:40:54 cheshire
-Minor code rearrangement in preparation for upcoming changes
-
-Revision 1.954 2009/05/01 21:28:34 cheshire
-<rdar://problem/6721680> AppleConnectAgent's reachability checks delay sleep by 30 seconds
-No longer suspend network operations after we've acknowledged that the machine is going to sleep,
-because other software may not have yet acknowledged the sleep event, and may be still trying
-to do unicast DNS queries or other Bonjour operations.
-
-Revision 1.953 2009/05/01 19:17:35 cheshire
-<rdar://problem/6501561> Sleep Proxy: Reduce the frequency of maintenance wakes: ODD, fans, power
-
-Revision 1.952 2009/05/01 19:16:45 mcguire
-<rdar://problem/6846322> Crash: mDNS_vsnprintf + 1844
-
-Revision 1.951 2009/04/28 23:48:19 jessic2
-<rdar://problem/6830541> regservice_callback: instance->request is NULL 0
-
-Revision 1.950 2009/04/25 01:17:10 mcguire
-Fix spurious TCP connect failures uncovered by <rdar://problem/6729406> PPP doesn't automatically reconnect on wake from sleep
-
-Revision 1.949 2009/04/25 01:11:02 mcguire
-Refactor: create separate function: RestartRecordGetZoneData
-
-Revision 1.948 2009/04/24 21:25:16 cheshire
-<rdar://problem/6601002> Special case Net Assistant port so Apple Remote Desktop doesn't wake up every machine on the network
-
-Revision 1.947 2009/04/24 19:41:12 mcguire
-<rdar://problem/6791775> 4 second delay in DNS response
-
-Revision 1.946 2009/04/24 19:28:39 mcguire
-<rdar://problem/6791775> 4 second delay in DNS response
-
-Revision 1.945 2009/04/24 00:30:30 cheshire
-<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
-Added code to generate and process NSEC records
-
-Revision 1.944 2009/04/23 22:06:29 cheshire
-Added CacheRecord and InterfaceID parameters to MakeNegativeCacheRecord, in preparation for:
-<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
-
-Revision 1.943 2009/04/22 01:19:56 jessic2
-<rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32
-
-Revision 1.942 2009/04/21 02:13:29 cheshire
-<rdar://problem/5270176> Local hostname changed even though there really isn't a name conflict
-Made code less susceptible to being tricked by stale packets echoed back from the network.
-
-Revision 1.941 2009/04/15 22:22:23 mcguire
-<rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
-Additional fix: protect against deref of NULL
-
-Revision 1.940 2009/04/15 20:42:51 mcguire
-<rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
-
-Revision 1.939 2009/04/11 00:19:32 jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.938 2009/04/06 23:44:57 cheshire
-<rdar://problem/6757838> mDNSResponder thrashing kernel lock in the UDP close path, hurting SPECweb performance
-
-Revision 1.937 2009/04/04 00:14:49 mcguire
-fix logging in BeginSleepProcessing
-
-Revision 1.936 2009/04/04 00:10:59 mcguire
-don't ignore m->SystemWakeOnLANEnabled when going to sleep
-
-Revision 1.935 2009/04/01 17:50:11 mcguire
-cleanup mDNSRandom
-
-Revision 1.934 2009/03/27 17:17:58 cheshire
-Improved "Ignoring suspect uDNS response" debugging message
-
-Revision 1.933 2009/03/21 02:40:21 cheshire
-<rdar://problem/6704514> uDNS: Need to create negative cache entries for "local" SOA
-
-Revision 1.932 2009/03/20 23:53:03 jessic2
-<rdar://problem/6646228> SIGHUP should restart all in-progress queries
-
-Revision 1.931 2009/03/18 19:08:15 cheshire
-Show old/new sleep sequence numbers in logical order
-
-Revision 1.930 2009/03/17 23:40:45 cheshire
-For now only try the highest-ranked Sleep Proxy; fixed come compiler warnings
-
-Revision 1.929 2009/03/17 21:55:56 cheshire
-Fixed mistake in logic for decided when we're ready to go to sleep
-
-Revision 1.928 2009/03/17 19:48:12 cheshire
-<rdar://problem/6688927> Don't cache negative unicast answers for Multicast DNS names
-
-Revision 1.927 2009/03/17 01:22:56 cheshire
-<rdar://problem/6601427> Sleep Proxy: Retransmit and retry Sleep Proxy Server requests
-Initial support for resolving up to three Sleep Proxies in parallel
-
-Revision 1.926 2009/03/17 01:05:07 mcguire
-<rdar://problem/6657640> Reachability fixes on DNS config change
-
-Revision 1.925 2009/03/13 01:35:36 mcguire
-<rdar://problem/6657640> Reachability fixes on DNS config change
-
-Revision 1.924 2009/03/10 23:45:20 cheshire
-Added comments explaining usage of SetSPSProxyListChanged()
-
-Revision 1.923 2009/03/09 21:53:02 cheshire
-<rdar://problem/6650479> Sleep Proxy: Need to stop proxying when it sees an ARP probe from the client
-
-Revision 1.922 2009/03/09 21:30:17 cheshire
-Improved some LogSPS messages; made RestartProbing() subroutine
-
-Revision 1.921 2009/03/06 22:53:31 cheshire
-Don't bother registering with Sleep Proxy if we have no advertised services
-
-Revision 1.920 2009/03/06 20:08:55 cheshire
-<rdar://problem/6601429> Sleep Proxy: Return error responses to clients
-
-Revision 1.919 2009/03/05 21:54:43 cheshire
-Improved "Sleep Proxy Server started / stopped" message
-
-Revision 1.918 2009/03/04 01:37:14 cheshire
-<rdar://problem/6601428> Limit maximum number of records that a Sleep Proxy Server will accept
-
-Revision 1.917 2009/03/03 23:14:25 cheshire
-Got rid of code duplication by making subroutine "SetupOwnerOpt"
-
-Revision 1.916 2009/03/03 23:04:43 cheshire
-For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC)
-
-Revision 1.915 2009/03/03 22:51:53 cheshire
-<rdar://problem/6504236> Sleep Proxy: Waking on same network but different interface will cause conflicts
-
-Revision 1.914 2009/03/03 00:46:09 cheshire
-Additional debugging information in ResolveSimultaneousProbe
-
-Revision 1.913 2009/02/27 03:08:47 cheshire
-<rdar://problem/6547720> Crash while shutting down when "local" is in the user's DNS searchlist
-
-Revision 1.912 2009/02/27 02:31:28 cheshire
-Improved "Record not found in list" debugging message
-
-Revision 1.911 2009/02/21 01:42:11 cheshire
-Updated log messages
-
-Revision 1.910 2009/02/19 01:50:53 cheshire
-Converted some LogInfo messages to LogSPS
-
-Revision 1.909 2009/02/14 00:04:59 cheshire
-Left-justify interface names
-
-Revision 1.908 2009/02/13 19:40:07 cheshire
-Improved alignment of LogSPS messages
-
-Revision 1.907 2009/02/13 18:16:05 cheshire
-Fixed some compile warnings
-
-Revision 1.906 2009/02/13 06:10:17 cheshire
-Convert LogOperation messages to LogInfo
-
-Revision 1.905 2009/02/12 20:57:24 cheshire
-Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
-
-Revision 1.904 2009/02/11 02:37:29 cheshire
-m->p->SystemWakeForNetworkAccessEnabled renamed to m->SystemWakeOnLANEnabled
-Moved code to send goodbye packets from mDNSCoreMachineSleep into BeginSleepProcessing,
-so that it happens correctly even when we delay re-sleep due to a very short wakeup.
-
-Revision 1.903 2009/02/09 23:34:31 cheshire
-Additional logging for debugging unknown packets
-
-Revision 1.902 2009/02/07 05:57:01 cheshire
-Fixed debugging log message
-
-Revision 1.901 2009/02/07 02:57:31 cheshire
-<rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
-
-Revision 1.900 2009/02/02 21:29:24 cheshire
-<rdar://problem/4786302> Implement logic to determine when to send dot-local lookups via Unicast
-If Negative response for our special Microsoft Active Directory "local SOA" check has no
-SOA record in the authority section, assume we should cache the negative result for 24 hours
-
-Revision 1.899 2009/01/31 00:37:50 cheshire
-When marking cache records for deletion in response to a uDNS response,
-make sure InterfaceID matches (i.e. it should be NULL for a uDNS cache record)
-
-Revision 1.898 2009/01/30 23:49:20 cheshire
-Exclude mDNSInterface_Unicast from "InterfaceID ... not currently found" test
-
-Revision 1.897 2009/01/30 22:04:49 cheshire
-Workaround to reduce load on root name servers when caching the SOA record for "."
-
-Revision 1.896 2009/01/30 22:00:05 cheshire
-Made mDNS_StartQuery_internal pay attention to mDNSInterface_Unicast
-
-Revision 1.895 2009/01/30 17:46:39 cheshire
-Improved debugging messages for working out why spurious name conflicts are happening
-
-Revision 1.894 2009/01/30 00:22:09 cheshire
-<rdar://problem/6540743> No announcement after probing & no conflict notice
-
-Revision 1.893 2009/01/29 22:27:03 mcguire
-<rdar://problem/6407429> Cleanup: Logs about Unknown DNS packet type 5450
-
-Revision 1.892 2009/01/24 01:38:23 cheshire
-Fixed error in logic for targeted queries
-
-Revision 1.891 2009/01/22 02:14:25 cheshire
-<rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
-
-Revision 1.890 2009/01/22 00:45:02 cheshire
-Improved SPS debugging log messages; we are eligible to start answering ARP requests
-after we send our first announcement, not after we send our last probe
-
-Revision 1.889 2009/01/21 03:43:56 mcguire
-<rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore
-
-Revision 1.888 2009/01/20 00:27:43 mcguire
-<rdar://problem/6305725> when removing a uDNS record, if a dup exists, copy information to it
-
-Revision 1.887 2009/01/17 05:14:37 cheshire
-Convert SendQueries Probe messages to LogSPS messages
-
-Revision 1.886 2009/01/17 03:43:09 cheshire
-Added SPSLogging switch to facilitate Sleep Proxy Server debugging
-
-Revision 1.885 2009/01/16 22:44:18 cheshire
-<rdar://problem/6402123> Sleep Proxy: Begin ARP Announcements sooner
-
-Revision 1.884 2009/01/16 21:43:52 cheshire
-Let InitializeLastAPTime compute the correct interval, instead of having it passed in as a parameter
-
-Revision 1.883 2009/01/16 21:11:18 cheshire
-When purging expired Sleep Proxy records, need to check DuplicateRecords list too
-
-Revision 1.882 2009/01/16 19:54:28 cheshire
-Use symbols "SleepProxyServiceType" and "localdomain" instead of literal strings
-
-Revision 1.881 2009/01/14 01:38:38 mcguire
-<rdar://problem/6492710> Write out DynamicStore per-interface SleepProxyServer info
-
-Revision 1.880 2009/01/10 01:51:19 cheshire
-q->CurrentAnswers not being incremented/decremented when answering a question with a local AuthRecord
-
-Revision 1.879 2009/01/10 01:43:52 cheshire
-Changed misleading function name 'AnsweredLOQ' to more informative 'AnsweredLocalQ'
-
-Revision 1.878 2009/01/10 01:38:10 cheshire
-Changed misleading function name 'AnswerLocalOnlyQuestionWithResourceRecord' to more informative 'AnswerLocalQuestionWithLocalAuthRecord'
-
-Revision 1.877 2009/01/10 01:36:08 cheshire
-Changed misleading function name 'AnswerLocalOnlyQuestions' to more informative 'AnswerAllLocalQuestionsWithLocalAuthRecord'
-
-Revision 1.876 2009/01/09 22:56:06 cheshire
-Don't touch rr after calling mDNS_Deregister_internal -- the memory may have been free'd
-
-Revision 1.875 2009/01/09 22:54:46 cheshire
-When tranferring record from DuplicateRecords list to ResourceRecords list,
-need to copy across state of 'Answered Local-Only-Questions' flag
-
-Revision 1.874 2009/01/07 23:07:24 cheshire
-<rdar://problem/6479416> SPS Client not canceling outstanding resolve call before sleeping
-
-Revision 1.873 2008/12/17 00:18:59 mkrochma
-Change some LogMsg to LogOperation before submitting
-
-Revision 1.872 2008/12/12 01:30:40 cheshire
-Update platform-layer BPF filters when we add or remove AddressProxy records
-
-Revision 1.871 2008/12/10 02:25:31 cheshire
-Minor fixes to use of LogClientOperations symbol
-
-Revision 1.870 2008/12/10 02:11:41 cheshire
-ARMv5 compiler doesn't like uncommented stuff after #endif
-
-Revision 1.869 2008/12/05 02:35:24 mcguire
-<rdar://problem/6107390> Write to the DynamicStore when a Sleep Proxy server is available on the network
-
-Revision 1.868 2008/12/04 21:08:51 mcguire
-<rdar://problem/6116863> mDNS: Provide mechanism to disable Multicast advertisements
-
-Revision 1.867 2008/11/26 21:19:36 cheshire
-<rdar://problem/6374334> Sleeping Server should choose the best Sleep Proxy by using advertised metrics
-
-Revision 1.866 2008/11/26 20:32:46 cheshire
-<rdar://problem/6374328> Sleep Proxy: Advertise BSP metrics in service name
-Update advertised name when Sleep Proxy "intent" metric changes
-
-Revision 1.865 2008/11/26 19:49:25 cheshire
-Record originally-requested port in sr->NATinfo.IntPort
-
-Revision 1.864 2008/11/26 19:02:37 cheshire
-Don't answer ARP Probes from owner machine as it wakes up and rejoins the network
-
-Revision 1.863 2008/11/26 03:59:03 cheshire
-Wait 30 seconds before starting ARP Announcements
-
-Revision 1.862 2008/11/25 23:43:07 cheshire
-<rdar://problem/5745355> Crashes at ServiceRegistrationGotZoneData + 397
-Made code more defensive to guard against ServiceRegistrationGotZoneData being called with invalid ServiceRecordSet object
-
-Revision 1.861 2008/11/25 22:46:30 cheshire
-For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta"
-
-Revision 1.860 2008/11/25 05:07:15 cheshire
-<rdar://problem/6374328> Advertise Sleep Proxy metrics in service name
-
-Revision 1.859 2008/11/20 02:07:56 cheshire
-<rdar://problem/6387470> Refresh our NAT mappings on wake from sleep
-
-Revision 1.858 2008/11/20 01:38:36 cheshire
-For consistency with other parts of the code, changed code to only check
-that the first 4 bytes of MAC address are zero, not the whole 6 bytes.
-
-Revision 1.857 2008/11/14 22:55:18 cheshire
-Fixed log messages
-
-Revision 1.856 2008/11/14 21:08:28 cheshire
-Only put owner option in query packet if we have a non-zero MAC address to put
-Only process owner options in received query packets if the MAC address in the option is non-zero
-
-Revision 1.855 2008/11/14 02:29:54 cheshire
-If Sleep Proxy client fails to renew proxy records before they expire, remove them from our m->ResourceRecords list
-
-Revision 1.854 2008/11/14 00:00:53 cheshire
-After client machine wakes up, Sleep Proxy machine need to remove any records
-it was temporarily holding as proxy for that client
-
-Revision 1.853 2008/11/13 19:07:30 cheshire
-Added code to put OPT record, containing owner and lease lifetime, into SPS registration packet
-
-Revision 1.852 2008/11/12 23:23:11 cheshire
-Before waking a host, check to see if it has an SRV record advertising
-a service on the port in question, and if not, don't bother waking it.
-
-Revision 1.851 2008/11/12 01:54:15 cheshire
-<rdar://problem/6338021> Add domain back to end of _services._dns-sd._udp PTR records
-It turns out it is beneficial to have the domain on the end, because it allows better name compression
-
-Revision 1.850 2008/11/11 01:56:57 cheshire
-Improved name conflict log messages
-
-Revision 1.849 2008/11/06 23:50:43 cheshire
-Allow plain (non-SYN) ssh data packets to wake sleeping host
-
-Revision 1.848 2008/11/05 02:40:28 mkrochma
-Change mDNS_SetFQDN syslog mesage to debugf
-
-Revision 1.847 2008/11/04 23:06:50 cheshire
-Split RDataBody union definition into RDataBody and RDataBody2, and removed
-SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord
-
-Revision 1.846 2008/11/04 22:21:44 cheshire
-Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord
-
-Revision 1.845 2008/11/03 23:52:05 cheshire
-Improved ARP debugging messages to differentiate ARP Announcements from Requests
-
-Revision 1.844 2008/10/31 23:43:51 cheshire
-Fixed compile error in Posix build
-
-Revision 1.843 2008/10/31 22:55:04 cheshire
-Initial support for structured SPS names
-
-Revision 1.842 2008/10/30 00:12:07 cheshire
-Fixed spin when PutSPSRec fails to put a record because it's too big to fit
-
-Revision 1.841 2008/10/29 23:23:38 cheshire
-Refined cache size reporting to go in steps of 1000 when number is above 1000
-
-Revision 1.840 2008/10/29 21:34:10 cheshire
-Removed some old debugging messages
-
-Revision 1.839 2008/10/29 21:31:32 cheshire
-Five seconds not always enough time for machine to go to sleep -- increased to ten seconds
-
-Revision 1.838 2008/10/28 18:30:37 cheshire
-Added debugging message in mDNSCoreReceiveRawPacket
-
-Revision 1.837 2008/10/24 23:58:05 cheshire
-Wake up for Back to My Mac IPSEC packets, except NAT keepalive packets
-
-Revision 1.836 2008/10/24 23:18:18 cheshire
-If we have a Sleep Proxy Server, don't remove service registrations from the DNS server
-
-Revision 1.835 2008/10/24 23:07:59 cheshire
-Wake SPS client if we receive conflicting mDNS respoonse (record with same name as one of our unique records, but different rdata)
-
-Revision 1.834 2008/10/24 23:03:24 cheshire
-Wake SPS client if we receive a conflicting ARP (some other machine claiming to own that IP address)
-
-Revision 1.833 2008/10/24 23:01:26 cheshire
-To reduce spurious wakeups for now, we'll only wake for incoming TCP SYN packets
-
-Revision 1.832 2008/10/24 22:58:24 cheshire
-For now, since we don't get IPv6 ND or data packets, don't advertise AAAA records for our SPS clients
-
-Revision 1.831 2008/10/24 22:50:41 cheshire
-When waking SPS client, include interface name in syslog message
-
-Revision 1.830 2008/10/24 20:50:34 cheshire
-Use "#if USE_SEPARATE_UDNS_SERVICE_LIST" instead of "#if defined(USE_SEPARATE_UDNS_SERVICE_LIST)"
-
-Revision 1.829 2008/10/23 23:55:57 cheshire
-Fixed some missing "const" declarations
-
-Revision 1.828 2008/10/23 22:25:56 cheshire
-Renamed field "id" to more descriptive "updateid"
-
-Revision 1.827 2008/10/23 03:06:25 cheshire
-Fixed "Waking host" log message
-
-Revision 1.826 2008/10/22 23:21:30 cheshire
-Make sure we have enough bytes before reading into the transport-level header
-
-Revision 1.825 2008/10/22 22:31:53 cheshire
-Log SYN/FIN/RST bits from TCP header, and don't wake for FIN/RST
-
-Revision 1.824 2008/10/22 20:00:31 cheshire
-If we ourselves go to sleep, stop advertising sleep proxy service, then re-advertise after we wake up
-
-Revision 1.823 2008/10/22 19:55:35 cheshire
-Miscellaneous fixes; renamed FindFirstAnswerInCache to FindSPSInCache
-
-Revision 1.822 2008/10/22 01:41:39 cheshire
-Set question->ThisQInterval back to -1 after we cancel our NetWakeResolve
-
-Revision 1.821 2008/10/22 01:12:53 cheshire
-Answer ARP Requests for any IP address we're proxying for
-
-Revision 1.820 2008/10/21 01:11:11 cheshire
-Added mDNSCoreReceiveRawPacket for handling raw packets received by platform layer
-
-Revision 1.819 2008/10/20 22:16:27 cheshire
-Updated comments; increased cache shedding threshold from 3000 to 4000
-
-Revision 1.818 2008/10/16 22:01:54 cheshire
-Fix last checkin: Should be "ar->resrec.rdata->u.data", not "ar->resrec.rdata.u.data"
-
-Revision 1.817 2008/10/16 21:40:49 cheshire
-Need to set ar->resrec.rdlength correctly before calling mDNS_Register_internal()
-
-Revision 1.816 2008/10/15 23:12:36 cheshire
-On receiving SPS registration from client, broadcast ARP Announcements claiming ownership of that IP address
-
-Revision 1.815 2008/10/15 20:46:38 cheshire
-When transferring records to SPS, include Lease Option
-
-Revision 1.814 2008/10/15 19:51:27 cheshire
-Change "NOTE:" to "Note:" so that BBEdit 9 stops putting those lines into the funtion popup menu
-
-Revision 1.813 2008/10/15 00:09:23 cheshire
-When acting as Sleep Proxy Server, handle DNS Updates received from SPS clients on the network
-
-Revision 1.812 2008/10/15 00:01:40 cheshire
-When going to sleep, discover and resolve SPS, and if successful, transfer records to it
-
-Revision 1.811 2008/10/14 23:51:57 cheshire
-Created new routine GetRDLengthMem() to compute the in-memory storage requirements for particular rdata
-
-Revision 1.810 2008/10/14 21:37:55 cheshire
-Removed unnecessary m->BeSleepProxyServer variable
-
-Revision 1.809 2008/10/10 23:45:48 cheshire
-For ForceMCast records, SetTargetToHostName should use the dot-local multicast hostname,
-not a wide-area unicast hostname
-
-Revision 1.808 2008/10/09 18:59:19 cheshire
-Added NetWakeResolve code, removed unused m->SendDeregistrations and m->SendImmediateAnswers
-
-Revision 1.807 2008/10/07 15:56:58 cheshire
-Fixed "unused variable" warnings in non-debug builds
-
-Revision 1.806 2008/10/04 00:53:37 cheshire
-On interfaces that support Wake-On-LAN, browse to discover Sleep Proxy Servers
-
-Revision 1.805 2008/10/03 18:17:28 cheshire
-<rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
-Update advertised Sleep Proxy Server name if user changes computer name
-
-Revision 1.804 2008/10/03 01:26:06 mcguire
-<rdar://problem/6266145> mDNS_FinalExit failed to send goodbye for duplicate uDNS records
-Put back Duplicate Record check
-
-Revision 1.803 2008/10/02 23:38:56 mcguire
-<rdar://problem/6266145> mDNS_FinalExit failed to send goodbye for duplicate uDNS records
-
-Revision 1.802 2008/10/02 23:13:48 cheshire
-<rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
-Need to drop lock before calling "mDNSCoreBeSleepProxyServer(m, mDNSfalse);"
-
-Revision 1.801 2008/10/02 22:51:04 cheshire
-<rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
-Added mDNSCoreBeSleepProxyServer() routine to start and stop Sleep Proxy Service
-
-Revision 1.800 2008/10/02 22:13:15 cheshire
-<rdar://problem/6230680> 100ms delay on shutdown
-Additional refinement: Also need to clear m->SuppressSending
-
-Revision 1.799 2008/09/29 20:12:37 cheshire
-Rename 'AnswerLocalQuestions' to more descriptive 'AnswerLocalOnlyQuestions' and 'AnsweredLocalQ' to 'AnsweredLOQ'
-
-Revision 1.798 2008/09/26 19:53:14 cheshire
-Fixed locking error: should not call mDNS_Deregister_internal within "mDNS_DropLock" section
-
-Revision 1.797 2008/09/25 20:40:59 cheshire
-<rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
-In mDNS_SetFQDN, need to update all AutoTarget SRV records, even if m->MulticastHostname hasn't changed
-
-Revision 1.796 2008/09/25 20:17:10 cheshire
-<rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
-Added defensive code to make sure *all* records of a ServiceRecordSet have
-completed deregistering before we pass on the mStatus_MemFree message
-
-Revision 1.795 2008/09/25 00:30:11 cheshire
-<rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
-
-Revision 1.794 2008/09/24 23:48:05 cheshire
-Don't need to pass whole ServiceRecordSet reference to GetServiceTarget;
-it only needs to access the embedded SRV member of the set
-
-Revision 1.793 2008/09/23 04:11:53 cheshire
-<rdar://problem/6238774> Remove "local" from the end of _services._dns-sd._udp PTR records
-
-Revision 1.792 2008/09/23 02:30:07 cheshire
-Get rid of PutResourceRecordCappedTTL()
-
-Revision 1.791 2008/09/20 00:34:21 mcguire
-<rdar://problem/6129039> BTMM: Add support for WANPPPConnection
-
-Revision 1.790 2008/09/18 22:46:34 cheshire
-<rdar://problem/6230680> 100ms delay on shutdown
-
-Revision 1.789 2008/09/18 06:15:06 mkrochma
-<rdar://problem/6117156> Cleanup: mDNSResponder logging debugging information to console
-
-Revision 1.788 2008/09/16 21:11:41 cheshire
-<rdar://problem/6223969> mDNS: Duplicate TXT record queries being produced by iPhone Remote
-
-Revision 1.787 2008/09/05 22:53:24 cheshire
-Improve "How is rr->resrec.rroriginalttl <= SecsSinceRcvd" debugging message
-
-Revision 1.786 2008/09/05 22:23:28 cheshire
-Moved initialization of "question->LocalSocket" to more logical place
-
-Revision 1.785 2008/08/14 19:20:55 cheshire
-<rdar://problem/6143846> Negative responses over TCP incorrectly rejected
-
-Revision 1.784 2008/08/13 00:47:53 mcguire
-Handle failures when packet logging
-
-Revision 1.783 2008/07/25 07:09:51 mcguire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-
-Revision 1.782 2008/07/24 20:23:03 cheshire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-
-Revision 1.781 2008/07/18 21:37:35 mcguire
-<rdar://problem/5736845> BTMM: alternate SSDP queries between multicast & unicast
-
-Revision 1.780 2008/07/18 02:24:36 cheshire
-<rdar://problem/6041178> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response
-Additional fix: Don't want to do the ReconfirmAntecedents() stuff if q->RequestUnicast is set (that indicates
-we're still on our first or second query after an interface registration or wake from sleep).
-
-Revision 1.779 2008/07/18 01:05:23 cheshire
-<rdar://problem/6041178> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response
-
-Revision 1.778 2008/06/26 17:24:11 mkrochma
-<rdar://problem/5450912> BTMM: Stop listening on UDP 5351 for NAT Status Announcements
-
-Revision 1.777 2008/06/19 01:20:48 mcguire
-<rdar://problem/4206534> Use all configured DNS servers
-
-Revision 1.776 2008/04/17 20:14:14 cheshire
-<rdar://problem/5870023> CurrentAnswers/LargeAnswers/UniqueAnswers counter mismatch
-
-Revision 1.775 2008/03/26 01:53:34 mcguire
-<rdar://problem/5820489> Can't resolve via uDNS when an interface is specified
-
-Revision 1.774 2008/03/17 17:46:08 mcguire
-When activating an LLQ, reset all the important state and destroy any tcp connection,
-so that everything will be restarted as if the question had just been asked.
-Also reset servPort, so that the SOA query will be re-issued.
-
-Revision 1.773 2008/03/14 22:52:36 mcguire
-<rdar://problem/5321824> write status to the DS
-Update status when any unicast LLQ is started
-
-Revision 1.772 2008/03/06 02:48:34 mcguire
-<rdar://problem/5321824> write status to the DS
-
-Revision 1.771 2008/02/26 22:04:44 cheshire
-<rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
-Additional fixes -- should not be calling uDNS_CheckCurrentQuestion on a
-question while it's still in our 'm->NewQuestions' section of the list
-
-Revision 1.770 2008/02/22 23:09:02 cheshire
-<rdar://problem/5338420> BTMM: Not processing additional records
-Refinements:
-1. Check rdatahash == namehash, to skip expensive SameDomainName check when possible
-2. Once we decide a record is acceptable, we can break out of the loop
-
-Revision 1.769 2008/02/22 00:00:19 cheshire
-<rdar://problem/5338420> BTMM: Not processing additional records
-
-Revision 1.768 2008/02/19 23:26:50 cheshire
-<rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
-
-Revision 1.767 2007/12/22 02:25:29 cheshire
-<rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
-
-Revision 1.766 2007/12/15 01:12:27 cheshire
-<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
-
-Revision 1.765 2007/12/15 00:18:51 cheshire
-Renamed question->origLease to question->ReqLease
-
-Revision 1.764 2007/12/14 00:49:53 cheshire
-Fixed crash in mDNS_StartExit -- the service deregistration loop needs to use
-the CurrentServiceRecordSet mechanism to guard against services being deleted,
-just like the record deregistration loop uses m->CurrentRecord.
-
-Revision 1.763 2007/12/13 20:20:17 cheshire
-Minor efficiency tweaks -- converted IdenticalResourceRecord, IdenticalSameNameRecord, and
-SameRData from functions to macros, which allows the code to be inlined (the compiler can't
-inline a function defined in a different compilation unit) and therefore optimized better.
-
-Revision 1.762 2007/12/13 00:13:03 cheshire
-Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody
-
-Revision 1.761 2007/12/13 00:03:31 cheshire
-Improved efficiency in IdenticalResourceRecord() by doing SameRData() check before SameDomainName() check
-
-Revision 1.760 2007/12/08 00:36:19 cheshire
-<rdar://problem/5636422> Updating TXT records is too slow
-Remove unnecessary delays on announcing record updates, and on processing them on reception
-
-Revision 1.759 2007/12/07 22:41:29 cheshire
-<rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
-Further refinements -- records on the DuplicateRecords list were getting missed on shutdown
-
-Revision 1.758 2007/12/07 00:45:57 cheshire
-<rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
-
-Revision 1.757 2007/12/06 00:22:27 mcguire
-<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
-
-Revision 1.756 2007/12/05 01:52:30 cheshire
-<rdar://problem/5624763> BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname
-Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to)
-
-Revision 1.755 2007/12/03 23:36:45 cheshire
-<rdar://problem/5623140> mDNSResponder unicast DNS improvements
-Need to check GetServerForName() result is non-null before dereferencing pointer
-
-Revision 1.754 2007/12/01 01:21:27 jgraessley
-<rdar://problem/5623140> mDNSResponder unicast DNS improvements
-
-Revision 1.753 2007/12/01 00:44:15 cheshire
-Fixed compile warnings, e.g. declaration of 'rr' shadows a previous local
-
-Revision 1.752 2007/11/14 01:10:51 cheshire
-Fixed LogOperation() message wording
-
-Revision 1.751 2007/10/30 23:49:41 cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-LLQ state was not being transferred properly between duplicate questions
-
-Revision 1.750 2007/10/29 23:58:52 cheshire
-<rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
-Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet
-
-Revision 1.749 2007/10/29 21:28:36 cheshire
-Change "Correcting TTL" log message to LogOperation to suppress it in customer build
-
-Revision 1.748 2007/10/29 20:02:50 cheshire
-<rdar://problem/5526813> BTMM: Wide-area records being announced via multicast
-
-Revision 1.747 2007/10/26 22:53:50 cheshire
-Made mDNS_Register_internal and mDNS_Deregister_internal use AuthRecord_uDNS macro
-instead of replicating the logic in both places
-
-Revision 1.746 2007/10/25 22:48:50 cheshire
-Added LogOperation message saying when we restart GetZoneData for record and service registrations
-
-Revision 1.745 2007/10/25 20:48:47 cheshire
-For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
-
-Revision 1.744 2007/10/25 20:06:14 cheshire
-Don't try to do SOA queries using private DNS (TLS over TCP) queries
-
-Revision 1.743 2007/10/25 00:12:46 cheshire
-<rdar://problem/5496734> BTMM: Need to retry registrations after failures
-Retrigger service registrations whenever a new network interface is added
-
-Revision 1.742 2007/10/24 22:40:06 cheshire
-Renamed: RecordRegistrationCallback -> RecordRegistrationGotZoneData
-Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
-
-Revision 1.741 2007/10/24 00:50:29 cheshire
-<rdar://problem/5496734> BTMM: Need to retry registrations after failures
-Retrigger record registrations whenever a new network interface is added
-
-Revision 1.740 2007/10/23 00:38:03 cheshire
-When sending uDNS cache expiration query, need to increment rr->UnansweredQueries
-or code will spin sending the same cache expiration query repeatedly
-
-Revision 1.739 2007/10/22 23:46:41 cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-Need to clear question->nta pointer after calling CancelGetZoneData()
-
-Revision 1.738 2007/10/19 22:08:49 cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-Additional fixes and refinements
-
-Revision 1.737 2007/10/18 23:06:42 cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-Additional fixes and refinements
-
-Revision 1.736 2007/10/18 20:23:17 cheshire
-Moved SuspendLLQs into mDNS.c, since it's only called from one place
-
-Revision 1.735 2007/10/18 00:12:34 cheshire
-Fixed "unused variable" compiler warning
-
-Revision 1.734 2007/10/17 22:49:54 cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-
-Revision 1.733 2007/10/17 22:37:23 cheshire
-<rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
-
-Revision 1.732 2007/10/17 21:53:51 cheshire
-Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
-
-Revision 1.731 2007/10/17 18:37:50 cheshire
-<rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
-Further refinement: pre-increment m->CurrentRecord before calling mDNS_Deregister_internal()
-
-Revision 1.730 2007/10/16 21:16:07 cheshire
-<rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
-
-Revision 1.729 2007/10/05 17:56:10 cheshire
-Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
-
-Revision 1.728 2007/10/04 23:18:14 cheshire
-<rdar://problem/5523706> mDNSResponder flooding DNS servers with unreasonable query level
-
-Revision 1.727 2007/10/04 22:51:57 cheshire
-Added debugging LogOperation message to show when we're sending cache expiration queries
-
-Revision 1.726 2007/10/03 00:14:24 cheshire
-Removed write to null to generate stack trace for SetNextQueryTime locking failure
-
-Revision 1.725 2007/10/02 21:11:08 cheshire
-<rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
-
-Revision 1.724 2007/10/02 20:10:23 cheshire
-Additional debugging checks on shutdown -- list all records we didn't send a goodbye for, not just the first one
-
-Revision 1.723 2007/10/02 19:56:54 cheshire
-<rdar://problem/5518310> Double-dispose causes crash changing Dynamic DNS hostname
-
-Revision 1.722 2007/10/01 22:59:46 cheshire
-<rdar://problem/5516303> mDNSResponder did not shut down after 20 seconds
-Need to shut down NATTraversals on exit
-
-Revision 1.721 2007/10/01 18:42:07 cheshire
-To make packet logs appear in a more intuitive order, dump received packets *before* handling them, not after
-
-Revision 1.720 2007/09/29 20:40:19 cheshire
-<rdar://problem/5513378> Crash in ReissueBlockedQuestions
-
-Revision 1.719 2007/09/27 22:23:56 cheshire
-<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
-Need to clear m->rec.r.resrec.RecordType after we've finished using m->rec
-
-Revision 1.718 2007/09/27 22:02:33 cheshire
-<rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
-
-Revision 1.717 2007/09/27 21:21:39 cheshire
-Export CompleteDeregistration so it's callable from other files
-
-Revision 1.716 2007/09/27 02:12:21 cheshire
-Updated GrantCacheExtensions degugging message to show new record lifetime
-
-Revision 1.715 2007/09/27 01:20:06 cheshire
-<rdar://problem/5500077> BTMM: Need to refresh LLQs based on lease life and not TTL of response
-
-Revision 1.714 2007/09/27 00:37:01 cheshire
-<rdar://problem/4947392> BTMM: Use SOA to determine TTL for negative answers
-
-Revision 1.713 2007/09/27 00:25:39 cheshire
-Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
-<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
-
-Revision 1.712 2007/09/26 23:16:58 cheshire
-<rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
-
-Revision 1.711 2007/09/26 22:06:02 cheshire
-<rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
-
-Revision 1.710 2007/09/26 00:49:46 cheshire
-Improve packet logging to show sent and received packets,
-transport protocol (UDP/TCP/TLS) and source/destination address:port
-
-Revision 1.709 2007/09/21 21:12:36 cheshire
-<rdar://problem/5498009> BTMM: Need to log updates and query packet contents
-
-Revision 1.708 2007/09/20 23:13:37 cheshire
-<rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
-Additional fix: If we have no DNS servers at all, then immediately purge all unicast cache records (including for LLQs)
-
-Revision 1.707 2007/09/20 02:29:37 cheshire
-<rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
-
-Revision 1.706 2007/09/20 01:13:19 cheshire
-Export CacheGroupForName so it's callable from other files
-
-Revision 1.705 2007/09/20 01:12:06 cheshire
-Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files
-
-Revision 1.704 2007/09/19 22:47:25 cheshire
-<rdar://problem/5490182> Memory corruption freeing a "no such service" service record
-
-Revision 1.703 2007/09/14 01:46:59 cheshire
-Fix Posix build (#ifdef _LEGACY_NAT_TRAVERSAL_ section included a closing curly brace it should not have)
-
-Revision 1.702 2007/09/13 22:06:46 cheshire
-<rdar://problem/5480643> Tully's Free WiFi: DNS fails
-Need to accept DNS responses where the query ID field matches, even if the source address does not
-
-Revision 1.701 2007/09/12 23:22:32 cheshire
-<rdar://problem/5476979> Only accept NAT Port Mapping packets from our default gateway
-
-Revision 1.700 2007/09/12 23:03:08 cheshire
-<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
-
-Revision 1.699 2007/09/12 22:19:28 cheshire
-<rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
-
-Revision 1.698 2007/09/12 22:13:27 cheshire
-Remove DynDNSHostNames cleanly on shutdown
-
-Revision 1.697 2007/09/12 01:44:47 cheshire
-<rdar://problem/5475938> Eliminate "Correcting TTL" syslog messages for unicast DNS records
-
-Revision 1.696 2007/09/12 01:26:08 cheshire
-Initialize LastNATReplyLocalTime to timenow, so that gateway uptime checks work more reliably
-
-Revision 1.695 2007/09/11 19:19:16 cheshire
-Correct capitalization of "uPNP" to "UPnP"
-
-Revision 1.694 2007/09/10 22:06:51 cheshire
-Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
-
-Revision 1.693 2007/09/07 22:24:36 vazquez
-<rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
-
-Revision 1.692 2007/09/07 00:12:09 cheshire
-<rdar://problem/5466010> Unicast DNS changes broke efficiency fix 3928456
-
-Revision 1.691 2007/09/05 22:25:01 vazquez
-<rdar://problem/5400521> update_record mDNSResponder leak
-
-Revision 1.690 2007/09/05 21:48:01 cheshire
-<rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
-Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code needs
-to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
-otherwise those records will expire and vanish from the cache.
-
-Revision 1.689 2007/09/05 02:29:06 cheshire
-<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
-Additional fixes to code implementing "NoAnswer" logic
-
-Revision 1.688 2007/08/31 22:56:39 cheshire
-<rdar://problem/5407080> BTMM: TTLs incorrect on cached BTMM records
-
-Revision 1.687 2007/08/31 19:53:14 cheshire
-<rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
-If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
-
-Revision 1.686 2007/08/30 00:01:56 cheshire
-Added comment about SetTargetToHostName()
-
-Revision 1.685 2007/08/29 01:19:24 cheshire
-<rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
-Set AutoTarget to Target_AutoHostAndNATMAP for non-AutoTunnel wide-area services
-
-Revision 1.684 2007/08/28 23:58:42 cheshire
-Rename HostTarget -> AutoTarget
-
-Revision 1.683 2007/08/28 23:53:21 cheshire
-Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
-
-Revision 1.682 2007/08/27 20:28:19 cheshire
-Improve "suspect uDNS response" log message
-
-Revision 1.681 2007/08/24 23:37:23 cheshire
-Added debugging message to show when ExtraResourceRecord callback gets invoked
-
-Revision 1.680 2007/08/24 00:15:19 cheshire
-Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
-
-Revision 1.679 2007/08/23 21:47:09 vazquez
-<rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
-make sure we clean up port mappings on base stations by sending a lease value of 0,
-and only send NAT-PMP packets on private networks; also save some memory by
-not using packet structs in NATTraversals.
-
-Revision 1.678 2007/08/01 16:09:13 cheshire
-Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
-
-Revision 1.677 2007/08/01 01:58:24 cheshire
-Added RecordType sanity check in mDNS_Register_internal
-
-Revision 1.676 2007/08/01 00:04:13 cheshire
-<rdar://problem/5261696> Crash in tcpKQSocketCallback
-Half-open TCP connections were not being cancelled properly
-
-Revision 1.675 2007/07/31 02:28:35 vazquez
-<rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
-
-Revision 1.674 2007/07/31 01:57:23 cheshire
-Adding code to respect TTL received in uDNS responses turned out to
-expose other problems; backing out change for now.
-
-Revision 1.673 2007/07/30 23:31:26 cheshire
-Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
-
-Revision 1.672 2007/07/28 01:25:56 cheshire
-<rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
-
-Revision 1.671 2007/07/27 22:32:54 cheshire
-When processing TTLs in uDNS responses, we'll currently impose a minimum effective TTL
-of 2 seconds, or other stuff breaks (e.g. we end up making a negative cache entry).
-
-Revision 1.670 2007/07/27 20:54:43 cheshire
-Fixed code to respect real record TTL received in uDNS responses
-
-Revision 1.669 2007/07/27 20:09:32 cheshire
-Don't need to dump out all received mDNS packets; they're easily viewed using mDNSNetMonitor
-
-Revision 1.668 2007/07/27 19:58:47 cheshire
-Use symbolic names QC_add and QC_rmv instead of mDNStrue/mDNSfalse
-
-Revision 1.667 2007/07/27 19:52:10 cheshire
-Don't increment m->rrcache_active for no-cache add events
-
-Revision 1.666 2007/07/27 19:30:39 cheshire
-Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
-to properly reflect tri-state nature of the possible responses
-
-Revision 1.665 2007/07/27 18:44:01 cheshire
-Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
-
-Revision 1.664 2007/07/27 18:38:56 cheshire
-Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
-
-Revision 1.663 2007/07/25 03:05:02 vazquez
-Fixes for:
-<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
-<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
-and a myriad of other security problems
-
-Revision 1.662 2007/07/24 20:22:46 cheshire
-Make sure all fields of main mDNS object are initialized correctly
-
-Revision 1.661 2007/07/21 00:54:45 cheshire
-<rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
-
-Revision 1.660 2007/07/20 20:00:45 cheshire
-"Legacy Browse" is better called "Automatic Browse"
-
-Revision 1.659 2007/07/20 00:54:18 cheshire
-<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-
-Revision 1.658 2007/07/18 02:28:57 cheshire
-Don't set AutoTunnel settings in uDNS_RegisterService; should be done in GetServiceTarget
-
-Revision 1.657 2007/07/18 00:57:10 cheshire
-<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
-Only need to call AddNewClientTunnel() for IPv6 addresses
-
-Revision 1.656 2007/07/16 23:54:48 cheshire
-<rdar://problem/5338850> Crash when removing or changing DNS keys
-
-Revision 1.655 2007/07/16 20:11:37 vazquez
-<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
-Init LNT stuff and handle SSDP packets
-
-Revision 1.654 2007/07/12 23:30:23 cheshire
-Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
-
-Revision 1.653 2007/07/12 02:51:27 cheshire
-<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
-
-Revision 1.652 2007/07/11 23:43:42 cheshire
-Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
-
-Revision 1.651 2007/07/11 22:44:40 cheshire
-<rdar://problem/5328801> SIGHUP should purge the cache
-
-Revision 1.650 2007/07/11 21:34:09 cheshire
-<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
-Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName/mDNS_RemoveDynDNSHostName
-
-Revision 1.649 2007/07/11 02:52:52 cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-In uDNS_RegisterService, set HostTarget for AutoTunnel services
-
-Revision 1.648 2007/07/09 23:48:12 cheshire
-Add parentheses around bitwise operation for clarity
-
-Revision 1.647 2007/07/06 21:17:55 cheshire
-Initialize m->retryGetAddr to timenow + 0x78000000;
-
-Revision 1.646 2007/07/06 18:55:49 cheshire
-Initialize m->NextScheduledNATOp
-
-Revision 1.645 2007/06/29 22:55:54 cheshire
-Move declaration of DNSServer *s; Fixed incomplete comment.
-
-Revision 1.644 2007/06/29 00:07:29 vazquez
-<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-
-Revision 1.643 2007/06/20 01:10:12 cheshire
-<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-
-Revision 1.642 2007/06/15 21:54:50 cheshire
-<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
-
-Revision 1.641 2007/05/25 00:30:24 cheshire
-When checking for duplicate questions, make sure privacy (or not) status, and long-lived (or not)
-status matches. This is particularly important when doing a private query for an SOA record,
-which will result in a call StartGetZoneData which does a non-private query for the same SOA record.
-If the latter is tagged as a duplicate of the former, then we have deadlock, and neither will complete.
-
-Revision 1.640 2007/05/25 00:25:44 cheshire
-<rdar://problem/5227737> Need to enhance putRData to output all current known types
-
-Revision 1.639 2007/05/23 00:51:33 cheshire
-Increase threshold for shedding cache records from 512 to 3000. The 512 figure was calculated when
-each cache entry took about 700 bytes; now they're only 164 bytes. Also, machines have more RAM these
-days, and there are more services being advertised using DNS-SD, so it makes sense to cache more.
-
-Revision 1.638 2007/05/23 00:43:16 cheshire
-If uDNS UDP response has TC (truncated) bit set, don't interpret it as being the entire RRSet
-
-Revision 1.637 2007/05/14 23:53:00 cheshire
-Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c
-
-Revision 1.636 2007/05/10 23:27:15 cheshire
-Update mDNS_Deregister_internal debugging messages
-
-Revision 1.635 2007/05/07 20:43:45 cheshire
-<rdar://problem/4241419> Reduce the number of queries and announcements
-
-Revision 1.634 2007/05/04 22:09:08 cheshire
-Only do "restarting exponential backoff sequence" for mDNS questions
-In mDNS_RegisterInterface, only retrigger mDNS questions
-In uDNS_SetupDNSConfig, use ActivateUnicastQuery() instead of just setting q->ThisQInterval directly
-
-Revision 1.633 2007/05/04 21:45:12 cheshire
-Get rid of unused q->RestartTime; Get rid of uDNS_Close (synonym for uDNS_Sleep)
-
-Revision 1.632 2007/05/04 20:20:50 cheshire
-<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
-Need to set srs->nta = mDNSNULL; when regState_NoTarget
-
-Revision 1.631 2007/05/04 00:39:42 cheshire
-<rdar://problem/4410011> Eliminate looping SOA lookups
-When creating a cascade of negative SOA cache entries, CacheGroup pointer cg needs to be updated
-each time round the loop to reference the right CacheGroup for each newly fabricated SOA name
-
-Revision 1.630 2007/05/03 22:40:38 cheshire
-<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
-
-Revision 1.629 2007/05/03 00:15:51 cheshire
-<rdar://problem/4410011> Eliminate looping SOA lookups
-
-Revision 1.628 2007/05/02 22:21:33 cheshire
-<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
-
-Revision 1.627 2007/04/30 19:29:13 cheshire
-Fix display of port number in "Updating DNS Server" message
-
-Revision 1.626 2007/04/30 04:21:13 cheshire
-Can't safely call AnswerLocalQuestions() from within mDNS_Deregister() -- need to defer it until mDNS_Execute time
-
-Revision 1.625 2007/04/28 01:34:21 cheshire
-Fixed crashing bug: We need to update rr->CRActiveQuestion pointers for *all* questions
-(Code was explicitly ignoring wide-area unicast questions, leading to stale pointers and crashes)
-
-Revision 1.624 2007/04/27 21:04:30 cheshire
-On network configuration change, need to call uDNS_RegisterSearchDomains
-
-Revision 1.623 2007/04/27 19:28:01 cheshire
-Any code that calls StartGetZoneData needs to keep a handle to the structure, so
-it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
--- it would start a query and then quickly cancel it, and then when
-StartGetZoneData completed, it had a dangling pointer and crashed.)
-
-Revision 1.622 2007/04/26 16:09:22 cheshire
-mDNS_StopQueryWithRemoves should ignore kDNSRecordTypePacketNegative records
-
-Revision 1.621 2007/04/26 15:43:22 cheshire
-Make sure DNSServer *s is non-null before using value in LogOperation
-
-Revision 1.620 2007/04/26 13:11:05 cheshire
-Fixed crash when logging out of VPN
-
-Revision 1.619 2007/04/26 00:35:15 cheshire
-<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
-Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
-inside the firewall may give answers where a public one gives none, and vice versa.)
-
-Revision 1.618 2007/04/25 19:26:01 cheshire
-m->NextScheduledQuery was getting set too early in SendQueries()
-Improved "SendQueries didn't send all its queries" debugging message
-
-Revision 1.617 2007/04/25 17:48:22 cheshire
-Update debugging message
-
-Revision 1.616 2007/04/25 16:38:32 cheshire
-If negative cache entry already exists, reactivate it instead of creating a new one
-
-Revision 1.615 2007/04/25 02:14:38 cheshire
-<rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
-Additional fixes to make LLQs work properly
-
-Revision 1.614 2007/04/23 21:52:45 cheshire
-<rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
-
-Revision 1.613 2007/04/23 04:58:20 cheshire
-<rdar://problem/5072548> Crash when setting extremely large TXT records
-
-Revision 1.612 2007/04/22 20:39:38 cheshire
-<rdar://problem/4633194> Add 20 to 120ms random delay to browses
-
-Revision 1.611 2007/04/22 18:16:29 cheshire
-Removed incorrect ActiveQuestion(q) check that was preventing suspended questions from getting reactivated
-
-Revision 1.610 2007/04/22 06:02:02 cheshire
-<rdar://problem/4615977> Query should immediately return failure when no server
-
-Revision 1.609 2007/04/20 21:17:24 cheshire
-For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
-
-Revision 1.608 2007/04/20 19:45:31 cheshire
-In LogClientOperations mode, dump out unknown DNS packets in their entirety
-
-Revision 1.607 2007/04/19 23:56:25 cheshire
-Don't do cache-flush processing for LLQ answers
-
-Revision 1.606 2007/04/19 22:50:53 cheshire
-<rdar://problem/4246187> Identical client queries should reference a single shared core query
-
-Revision 1.605 2007/04/19 20:06:41 cheshire
-Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
-
-Revision 1.604 2007/04/19 18:03:04 cheshire
-Add "const" declaration
-
-Revision 1.603 2007/04/06 21:00:25 cheshire
-Fix log message typo
-
-Revision 1.602 2007/04/05 22:55:35 cheshire
-<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
-
-Revision 1.601 2007/04/04 21:48:52 cheshire
-<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
-
-Revision 1.600 2007/04/04 01:31:33 cheshire
-Improve debugging message
-
-Revision 1.599 2007/04/04 00:03:26 cheshire
-<rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
-
-Revision 1.598 2007/04/03 19:43:16 cheshire
-Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
-
-Revision 1.597 2007/03/31 00:32:32 cheshire
-After skipping OPT and TSIG, clear m->rec.r.resrec.RecordType
-
-Revision 1.596 2007/03/28 20:59:26 cheshire
-<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
-
-Revision 1.595 2007/03/26 23:48:16 cheshire
-<rdar://problem/4848295> Advertise model information via Bonjour
-Refinements to reduce unnecessary transmissions of the DeviceInfo TXT record
-
-Revision 1.594 2007/03/26 23:05:05 cheshire
-<rdar://problem/5089257> Don't cache TSIG records
-
-Revision 1.593 2007/03/23 17:40:08 cheshire
-<rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
-
-Revision 1.592 2007/03/22 18:31:48 cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.591 2007/03/22 00:49:19 cheshire
-<rdar://problem/4848295> Advertise model information via Bonjour
-
-Revision 1.590 2007/03/21 23:05:59 cheshire
-Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
-
-Revision 1.589 2007/03/20 15:37:19 cheshire
-Delete unnecessary log message
-
-Revision 1.588 2007/03/20 00:24:44 cheshire
-<rdar://problem/4175213> Should deliver "name registered" callback slightly *before* announcing PTR record
-
-Revision 1.587 2007/03/16 22:10:56 cheshire
-<rdar://problem/4471307> mDNS: Query for *either* type A or AAAA should return both types
-
-Revision 1.586 2007/03/10 03:26:44 cheshire
-<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
-
-Revision 1.585 2007/03/10 02:02:58 cheshire
-<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
-Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
-
-Revision 1.584 2007/02/28 01:51:27 cheshire
-Added comment about reverse-order IP address
-
-Revision 1.583 2007/01/27 03:19:33 cheshire
-Need to initialize question->sock
-
-Revision 1.582 2007/01/25 00:40:16 cheshire
-Unified CNAME-following functionality into cache management code (which means CNAME-following
-should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
-
-Revision 1.581 2007/01/23 02:56:11 cheshire
-Store negative results in the cache, instead of generating them out of pktResponseHndlr()
-
-Revision 1.580 2007/01/19 21:17:33 cheshire
-StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
-
-Revision 1.579 2007/01/19 18:39:10 cheshire
-Fix a bunch of parameters that should have been declared "const"
-
-Revision 1.578 2007/01/10 22:51:57 cheshire
-<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
-
-Revision 1.577 2007/01/10 02:05:21 cheshire
-Delay uDNS_SetupDNSConfig() until *after* the platform layer
-has set up the interface list and security credentials
-
-Revision 1.576 2007/01/09 02:40:57 cheshire
-uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
-moved it to mDNS_Init() in mDNS.c (core code)
-
-Revision 1.575 2007/01/09 00:17:25 cheshire
-Improve "ERROR m->CurrentRecord already set" debugging messages
-
-Revision 1.574 2007/01/05 08:30:41 cheshire
-Trim excessive "Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.573 2007/01/05 06:34:03 cheshire
-Improve "ERROR m->CurrentQuestion already set" debugging messages
-
-Revision 1.572 2007/01/04 23:11:11 cheshire
-<rdar://problem/4720673> uDNS: Need to start caching unicast records
-When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
-
-Revision 1.571 2007/01/04 21:45:20 cheshire
-Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
-to do additional lock sanity checking around callback invocations
-
-Revision 1.570 2007/01/04 20:57:47 cheshire
-Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
-
-Revision 1.569 2007/01/04 20:27:27 cheshire
-Change a LogMsg() to debugf()
-
-Revision 1.568 2007/01/04 02:39:53 cheshire
-<rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
-
-Revision 1.567 2006/12/21 00:01:37 cheshire
-Tidy up code alignment
-
-Revision 1.566 2006/12/20 04:07:34 cheshire
-Remove uDNS_info substructure from AuthRecord_struct
-
-Revision 1.565 2006/12/19 22:49:23 cheshire
-Remove uDNS_info substructure from ServiceRecordSet_struct
-
-Revision 1.564 2006/12/19 02:38:20 cheshire
-Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
-
-Revision 1.563 2006/12/19 02:18:48 cheshire
-Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
-
-Revision 1.562 2006/12/16 01:58:31 cheshire
-<rdar://problem/4720673> uDNS: Need to start caching unicast records
-
-Revision 1.561 2006/12/01 07:38:53 herscher
-Only perform cache workaround fix if query is wide-area
-
-Revision 1.560 2006/11/30 23:07:56 herscher
-<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
-
-Revision 1.559 2006/11/27 08:20:57 cheshire
-Preliminary support for unifying the uDNS and mDNS code, including caching of uDNS answers
-
-Revision 1.558 2006/11/10 07:44:03 herscher
-<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
-
-Revision 1.557 2006/11/10 01:12:51 cheshire
-<rdar://problem/4829718> Incorrect TTL corrections
-
-Revision 1.556 2006/11/10 00:54:14 cheshire
-<rdar://problem/4816598> Changing case of Computer Name doesn't work
-
-Revision 1.555 2006/10/30 20:03:37 cheshire
-<rdar://problem/4456945> After service restarts on different port, for a few seconds DNS-SD may return stale port number
-
-Revision 1.554 2006/10/20 05:35:04 herscher
-<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
-
-Revision 1.553 2006/10/05 03:42:43 herscher
-Remove embedded uDNS_info struct in DNSQuestion_struct
-
-Revision 1.552 2006/09/15 21:20:15 cheshire
-Remove uDNS_info substructure from mDNS_struct
-
-Revision 1.551 2006/08/14 23:24:22 cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.550 2006/07/27 17:58:34 cheshire
-Improved text of "SendQueries didn't send all its queries; will try again" debugging message
-
-Revision 1.549 2006/07/20 22:07:31 mkrochma
-<rdar://problem/4633196> Wide-area browsing is currently broken in TOT
-More fixes for uninitialized variables
-
-Revision 1.548 2006/07/20 19:30:19 mkrochma
-<rdar://problem/4633196> Wide-area browsing sometimes doesn't work in TOT
-
-Revision 1.547 2006/07/15 02:31:30 cheshire
-<rdar://problem/4630812> Suppress log messages for certain old devices with inconsistent TXT RRSet TTLs
-
-Revision 1.546 2006/07/07 01:09:09 cheshire
-<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
-
-Revision 1.545 2006/07/05 23:10:30 cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
-
-Revision 1.544 2006/06/29 07:42:14 cheshire
-<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
-
-Revision 1.543 2006/06/29 01:38:43 cheshire
-<rdar://problem/4605285> Only request unicast responses on wake from sleep and network connection
-
-Revision 1.542 2006/06/27 23:40:29 cheshire
-Fix typo in comment: mis-spelled "compile"
-
-Revision 1.541 2006/06/27 19:46:24 cheshire
-Updated comments and debugging messages
-
-Revision 1.540 2006/06/15 21:35:16 cheshire
-Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants
-from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code
-
-Revision 1.539 2006/06/08 23:45:46 cheshire
-Change SimultaneousProbe messages from debugf() to LogOperation()
-
-Revision 1.538 2006/03/19 17:13:06 cheshire
-<rdar://problem/4483117> Need faster purging of stale records
-Shorten kDefaultReconfirmTimeForNoAnswer to five seconds
-and reconfirm whole chain of antecedents ot once
-
-Revision 1.537 2006/03/19 02:00:07 cheshire
-<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-
-Revision 1.536 2006/03/08 23:29:53 cheshire
-<rdar://problem/4468716> Improve "Service Renamed" log message
-
-Revision 1.535 2006/03/02 20:41:17 cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-Minor code tidying and comments to reduce the risk of similar programming errors in future
-
-Revision 1.534 2006/03/02 03:25:46 cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
-
-Revision 1.533 2006/02/26 00:54:41 cheshire
-Fixes to avoid code generation warning/error on FreeBSD 7
-
-*/
+ */
#include "DNSCommon.h" // Defines general DNS untility routines
#include "uDNS.h" // Defines entry points into unicast-specific routines
@@ -1507,9 +54,27 @@ Fixes to avoid code generation warning/error on FreeBSD 7
#pragma warning(disable:4706)
#endif
+#if APPLE_OSX_mDNSResponder
+
+#include <WebFilterDNS/WebFilterDNS.h>
+
+#if ! NO_WCF
+WCFConnection *WCFConnectionNew(void) __attribute__((weak_import));
+void WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import));
+
+// Do we really need to define a macro for "if"?
+#define CHECK_WCF_FUNCTION(X) if (X)
+#endif // ! NO_WCF
+
+#else
+
+#define NO_WCF 1
+#endif // APPLE_OSX_mDNSResponder
+
// Forward declarations
mDNSlocal void BeginSleepProcessing(mDNS *const m);
mDNSlocal void RetrySPSRegistrations(mDNS *const m);
+mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password);
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
@@ -1518,7 +83,6 @@ mDNSlocal void RetrySPSRegistrations(mDNS *const m);
#define NO_HINFO 1
-mDNSlocal const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)~0;
// Any records bigger than this are considered 'large' records
#define SmallRecordLimit 1024
@@ -1545,9 +109,6 @@ mDNSexport const char *const mDNS_DomainTypeNames[] =
#pragma mark - General Utility Functions
#endif
-#define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
-#define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0)
-
mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
{
if (m->mDNS_busy != m->mDNS_reentrancy+1)
@@ -1559,14 +120,12 @@ mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
if (ActiveQuestion(q))
{
- mDNSs32 sendtime = q->LastQTime + q->ThisQInterval;
-
- // Don't allow sendtime to be earlier than SuppressStdPort53Queries
- if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && m->SuppressStdPort53Queries && (sendtime - m->SuppressStdPort53Queries < 0))
- sendtime = m->SuppressStdPort53Queries;
-
- if (m->NextScheduledQuery - sendtime > 0)
- m->NextScheduledQuery = sendtime;
+ // Depending on whether this is a multicast or unicast question we want to set either:
+ // m->NextScheduledQuery = NextQSendTime(q) or
+ // m->NextuDNSEvent = NextQSendTime(q)
+ mDNSs32 *const timer = mDNSOpaque16IsZero(q->TargetQID) ? &m->NextScheduledQuery : &m->NextuDNSEvent;
+ if (*timer - NextQSendTime(q) > 0)
+ *timer = NextQSendTime(q);
}
}
@@ -1584,7 +143,7 @@ mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slo
return(CacheGroupForName(m, slot, rr->namehash, rr->name));
}
-mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
+mDNSexport mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
{
NetworkInterfaceInfo *intf;
@@ -1620,16 +179,24 @@ mDNSlocal NetworkInterfaceInfo *FirstInterfaceForID(mDNS *const m, const mDNSInt
return(intf);
}
-mDNSlocal char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
+mDNSexport char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
{
NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
- return(intf ? intf->ifname : "<NULL InterfaceID>");
+ return(intf ? intf->ifname : mDNSNULL);
}
// For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord
// Used by AnswerAllLocalQuestionsWithLocalAuthRecord() and AnswerNewLocalOnlyQuestion()
mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, QC_result AddRecord)
{
+ // We should not be delivering results for record types Unregistered, Deregistering, and (unverified) Unique
+ if (!(rr->resrec.RecordType & kDNSRecordTypeActiveMask))
+ {
+ LogMsg("AnswerLocalQuestionWithLocalAuthRecord: *NOT* delivering %s event for local record type %X %s",
+ AddRecord ? "Add" : "Rmv", rr->resrec.RecordType, ARDisplayString(m, rr));
+ return;
+ }
+
// Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
if (AddRecord) rr->AnsweredLocalQ = mDNStrue;
mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
@@ -1641,15 +208,22 @@ mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, DNSQuestion
mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
}
-// When a new local AuthRecord is created or deleted, AnswerAllLocalQuestionsWithLocalAuthRecord() runs though
-// all our local questions (both LocalOnlyQuestions and mDNSInterface_Any questions) delivering answers to each,
-// stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
-// If the AuthRecord is marked mDNSInterface_LocalOnly, then we also deliver it to any other questions we have using mDNSInterface_Any.
-// Used by AnswerForNewLocalRecords() and mDNS_Deregister_internal()
+// When a new local AuthRecord is created or deleted, AnswerAllLocalQuestionsWithLocalAuthRecord()
+// delivers the appropriate add/remove events to listening questions:
+// 1. It runs though all our LocalOnlyQuestions delivering answers as appropriate,
+// stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
+// 2. If the AuthRecord is marked mDNSInterface_LocalOnly or mDNSInterface_P2P, then it also runs though
+// our main question list, delivering answers to mDNSInterface_Any questions as appropriate,
+// stopping if it reaches a NewQuestion -- brand-new questions are handled by AnswerNewQuestion().
+//
+// AnswerAllLocalQuestionsWithLocalAuthRecord is used by the m->NewLocalRecords loop in mDNS_Execute(),
+// and by mDNS_Deregister_internal()
+
mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
{
if (m->CurrentQuestion)
- LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+ LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)",
+ m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
m->CurrentQuestion = m->LocalOnlyQuestions;
while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions)
@@ -1660,8 +234,8 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec
AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, AddRecord); // MUST NOT dereference q again
}
- // If this AuthRecord is marked LocalOnly, then we want to deliver it to all local 'mDNSInterface_Any' questions
- if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
+ // If this AuthRecord is marked LocalOnly or P2P, then we want to deliver it to all local 'mDNSInterface_Any' questions
+ if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->resrec.InterfaceID == mDNSInterface_P2P)
{
m->CurrentQuestion = m->Questions;
while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
@@ -1698,6 +272,12 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec
#define InitialAnnounceCount ((mDNSu8)8)
+// For goodbye packets we set the count to 3, and for wakeups we set it to 18
+// (which will be up to 15 wakeup attempts over the course of 30 seconds,
+// and then if the machine fails to wake, 3 goodbye packets).
+#define GoodbyeCount ((mDNSu8)3)
+#define WakeupCount ((mDNSu8)18)
+
// Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
// This means that because the announce interval is doubled after sending the first packet, the first
// observed on-the-wire inter-packet interval between announcements is actually one second.
@@ -1706,9 +286,9 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec
#define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2)
#define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2)
-#define DefaultAPIntervalForRecordType(X) ((X) & (kDNSRecordTypeAdvisory | kDNSRecordTypeShared ) ? DefaultAnnounceIntervalForTypeShared : \
- (X) & (kDNSRecordTypeUnique ) ? DefaultProbeIntervalForTypeUnique : \
- (X) & (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique) ? DefaultAnnounceIntervalForTypeUnique : 0)
+#define DefaultAPIntervalForRecordType(X) ((X) & kDNSRecordTypeActiveSharedMask ? DefaultAnnounceIntervalForTypeShared : \
+ (X) & kDNSRecordTypeUnique ? DefaultProbeIntervalForTypeUnique : \
+ (X) & kDNSRecordTypeActiveUniqueMask ? DefaultAnnounceIntervalForTypeUnique : 0)
#define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0)
#define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR))
@@ -1792,11 +372,21 @@ mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const r
{
if (rr->resrec.RecordType == kDNSRecordTypeUnique)
{
- //LogMsg("ProbeCount %d Next %ld %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
+ if ((rr->LastAPTime + rr->ThisAPInterval) - m->timenow > mDNSPlatformOneSecond * 10)
+ {
+ LogMsg("SetNextAnnounceProbeTime: ProbeCount %d Next in %d %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
+ LogMsg("SetNextAnnounceProbeTime: m->SuppressProbes %d m->timenow %d diff %d", m->SuppressProbes, m->timenow, m->SuppressProbes - m->timenow);
+ }
if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval);
+ // Some defensive code:
+ // If (rr->LastAPTime + rr->ThisAPInterval) happens to be far in the past, we don't want to allow
+ // NextScheduledProbe to be set excessively in the past, because that can cause bad things to happen.
+ // See: <rdar://problem/7795434> mDNS: Sometimes advertising stops working and record interval is set to zero
+ if (m->NextScheduledProbe - m->timenow < 0)
+ m->NextScheduledProbe = m->timenow;
}
- else if (rr->AnnounceCount && ResourceRecordIsValidAnswer(rr))
+ else if (rr->AnnounceCount && (ResourceRecordIsValidAnswer(rr) || rr->resrec.RecordType == kDNSRecordTypeDeregistering))
{
if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval);
@@ -1808,47 +398,62 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
// For reverse-mapping Sleep Proxy PTR records, probe interval is one second
rr->ThisAPInterval = rr->AddressProxy.type ? mDNSPlatformOneSecond : DefaultAPIntervalForRecordType(rr->resrec.RecordType);
- // To allow us to aggregate probes when a group of services are registered together,
- // the first probe is delayed 1/4 second. This means the common-case behaviour is:
- // 1/4 second wait; probe
- // 1/4 second wait; probe
- // 1/4 second wait; probe
- // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered)
+ // * If this is a record type that's going to probe, then we use the m->SuppressProbes time.
+ // * Otherwise, if it's not going to probe, but m->SuppressProbes is set because we have other
+ // records that are going to probe, then we delay its first announcement so that it will
+ // go out synchronized with the first announcement for the other records that *are* probing.
+ // This is a minor performance tweak that helps keep groups of related records synchronized together.
+ // The addition of "interval / 2" is to make sure that, in the event that any of the probes are
+ // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete.
+ // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated,
+ // because they will meet the criterion of being at least half-way to their scheduled announcement time.
+ // * If it's not going to probe and m->SuppressProbes is not already set then we should announce immediately.
if (rr->ProbeCount)
{
// If we have no probe suppression time set, or it is in the past, set it now
if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0)
{
- m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique);
+ // To allow us to aggregate probes when a group of services are registered together,
+ // the first probe is delayed 1/4 second. This means the common-case behaviour is:
+ // 1/4 second wait; probe
+ // 1/4 second wait; probe
+ // 1/4 second wait; probe
+ // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered)
+ m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2));
+
// If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation
if (m->SuppressProbes - m->NextScheduledProbe >= 0)
- m->SuppressProbes = m->NextScheduledProbe;
+ m->SuppressProbes = NonZeroTime(m->NextScheduledProbe);
+ if (m->SuppressProbes - m->timenow < 0) // Make sure we don't set m->SuppressProbes excessively in the past
+ m->SuppressProbes = m->timenow;
+
// If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation
if (m->SuppressProbes - m->NextScheduledQuery >= 0)
- m->SuppressProbes = m->NextScheduledQuery;
+ m->SuppressProbes = NonZeroTime(m->NextScheduledQuery);
+ if (m->SuppressProbes - m->timenow < 0) // Make sure we don't set m->SuppressProbes excessively in the past
+ m->SuppressProbes = m->timenow;
+
+ // except... don't expect to be able to send before the m->SuppressSending timer fires
+ if (m->SuppressSending && m->SuppressProbes - m->SuppressSending < 0)
+ m->SuppressProbes = NonZeroTime(m->SuppressSending);
+
+ if (m->SuppressProbes - m->timenow > mDNSPlatformOneSecond * 8)
+ {
+ LogMsg("InitializeLastAPTime ERROR m->SuppressProbes %d m->NextScheduledProbe %d m->NextScheduledQuery %d m->SuppressSending %d %d",
+ m->SuppressProbes - m->timenow,
+ m->NextScheduledProbe - m->timenow,
+ m->NextScheduledQuery - m->timenow,
+ m->SuppressSending,
+ m->SuppressSending - m->timenow);
+ m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2));
+ }
}
+ rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval;
}
-
- rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval;
- // Set LastMCTime to now, to inhibit multicast responses
- // (no need to send additional multicast responses when we're announcing anyway)
- rr->LastMCTime = m->timenow;
- rr->LastMCInterface = mDNSInterfaceMark;
-
- // If this is a record type that's not going to probe, then delay its first announcement so that
- // it will go out synchronized with the first announcement for the other records that *are* probing.
- // This is a minor performance tweak that helps keep groups of related records synchronized together.
- // The addition of "interval / 2" is to make sure that, in the event that any of the probes are
- // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete.
- // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated,
- // because they will meet the criterion of being at least half-way to their scheduled announcement time.
- if (rr->resrec.RecordType != kDNSRecordTypeUnique)
- rr->LastAPTime += DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2;
-
- // The exception is unique records that have already been verified and are just being updated
- // via mDNS_Update() -- for these we want to announce the new value immediately, without delay.
- if (rr->resrec.RecordType == kDNSRecordTypeVerified)
+ else if (m->SuppressProbes && m->SuppressProbes - m->timenow >= 0)
+ rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval + DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2;
+ else
rr->LastAPTime = m->timenow - rr->ThisAPInterval;
// For reverse-mapping Sleep Proxy PTR records we don't want to start probing instantly -- we
@@ -1859,13 +464,50 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
// (depending on the OS and networking stack it's using) that it might interpret it as a conflict and change its IP address.
if (rr->AddressProxy.type) rr->LastAPTime = m->timenow;
- // For now, since we don't yet handle IPv6 ND or data packets, we send deletions for our SPS clients' AAAA records
- if (rr->WakeUp.HMAC.l[0] && rr->resrec.rrtype == kDNSType_AAAA)
- rr->LastAPTime = m->timenow - rr->ThisAPInterval + mDNSPlatformOneSecond * 10;
+ // Unsolicited Neighbor Advertisements (RFC 2461 Section 7.2.6) give us fast address cache updating,
+ // but some older IPv6 clients get confused by them, so for now we don't send them. Without Unsolicited
+ // Neighbor Advertisements we have to rely on Neighbor Unreachability Detection instead, which is slower.
+ // Given this, we'll do our best to wake for existing IPv6 connections, but we don't want to encourage
+ // new ones for sleeping clients, so we'll we send deletions for our SPS clients' AAAA records.
+ if (m->KnownBugs & mDNS_KnownBug_LimitedIPv6)
+ if (rr->WakeUp.HMAC.l[0] && rr->resrec.rrtype == kDNSType_AAAA)
+ rr->LastAPTime = m->timenow - rr->ThisAPInterval + mDNSPlatformOneSecond * 10;
+
+ // Set LastMCTime to now, to inhibit multicast responses
+ // (no need to send additional multicast responses when we're announcing anyway)
+ rr->LastMCTime = m->timenow;
+ rr->LastMCInterface = mDNSInterfaceMark;
SetNextAnnounceProbeTime(m, rr);
}
+mDNSlocal const domainname *SetUnicastTargetToHostName(mDNS *const m, AuthRecord *rr)
+ {
+ const domainname *target;
+ if (rr->AutoTarget)
+ {
+ // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other
+ // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate,
+ // with the port number in our advertised SRV record automatically tracking the external mapped port.
+ DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
+ if (!AuthInfo || !AuthInfo->AutoTunnel) rr->AutoTarget = Target_AutoHostAndNATMAP;
+ }
+
+ target = GetServiceTarget(m, rr);
+ if (!target || target->c[0] == 0)
+ {
+ // defer registration until we've got a target
+ LogInfo("SetUnicastTargetToHostName No target for %s", ARDisplayString(m, rr));
+ rr->state = regState_NoTarget;
+ return mDNSNULL;
+ }
+ else
+ {
+ LogInfo("SetUnicastTargetToHostName target %##s for resource record %s", target->c, ARDisplayString(m,rr));
+ return target;
+ }
+ }
+
// Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname
// Eventually we should unify this with GetServiceTarget() in uDNS.c
mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
@@ -1873,12 +515,13 @@ mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
domainname *const target = GetRRDomainNameTarget(&rr->resrec);
const domainname *newname = &m->MulticastHostname;
- if (!target) debugf("SetTargetToHostName: Don't know how to set the target of rrtype %d", rr->resrec.rrtype);
+ if (!target) LogInfo("SetTargetToHostName: Don't know how to set the target of rrtype %s", DNSTypeName(rr->resrec.rrtype));
- if (!(rr->ForceMCast || rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&rr->namestorage)))
+ if (!(rr->ForceMCast || rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->resrec.InterfaceID == mDNSInterface_P2P || IsLocalDomain(&rr->namestorage)))
{
- const domainname *const n = GetServiceTarget(m, rr);
+ const domainname *const n = SetUnicastTargetToHostName(m, rr);
if (n) newname = n;
+ else { target->c[0] = 0; SetNewRData(&rr->resrec, mDNSNULL, 0); return; }
}
if (target && SameDomainName(target, newname))
@@ -1920,19 +563,84 @@ mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr)
}
}
-mDNSlocal void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr)
+mDNSexport void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr)
{
+ // Make sure that we don't activate the SRV record and associated service records, if it is in
+ // NoTarget state. First time when a service is being instantiated, SRV record may be in NoTarget state.
+ // We should not activate any of the other reords (PTR, TXT) that are part of the service. When
+ // the target becomes available, the records will be reregistered.
+ if (rr->resrec.rrtype != kDNSType_SRV)
+ {
+ AuthRecord *srvRR = mDNSNULL;
+ if (rr->resrec.rrtype == kDNSType_PTR)
+ srvRR = rr->Additional1;
+ else if (rr->resrec.rrtype == kDNSType_TXT)
+ srvRR = rr->DependentOn;
+ if (srvRR)
+ {
+ if (srvRR->resrec.rrtype != kDNSType_SRV)
+ {
+ LogMsg("ActivateUnicastRegistration: ERROR!! Resource record %s wrong, expecting SRV type", ARDisplayString(m, srvRR));
+ }
+ else
+ {
+ LogInfo("ActivateUnicastRegistration: Found Service Record %s in state %d for %##s (%s)",
+ ARDisplayString(m, srvRR), srvRR->state, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+ rr->state = srvRR->state;
+ }
+ }
+ }
+
+ if (rr->state == regState_NoTarget)
+ {
+ LogInfo("ActivateUnicastRegistration record %s in regState_NoTarget, not activating", ARDisplayString(m, rr));
+ return;
+ }
+ // When we wake up from sleep, we call ActivateUnicastRegistration. It is possible that just before we went to sleep,
+ // the service/record was being deregistered. In that case, we should not try to register again. For the cases where
+ // the records are deregistered due to e.g., no target for the SRV record, we would have returned from above if it
+ // was already in NoTarget state. If it was in the process of deregistration but did not complete fully before we went
+ // to sleep, then it is okay to start in Pending state as we will go back to NoTarget state if we don't have a target.
+ if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
+ {
+ LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to DeregPending", ARDisplayString(m, rr), rr->state);
+ rr->state = regState_DeregPending;
+ }
+ else
+ {
+ LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to Pending", ARDisplayString(m, rr), rr->state);
+ rr->state = regState_Pending;
+ }
rr->ProbeCount = 0;
rr->AnnounceCount = 0;
- rr->ThisAPInterval = 5 * mDNSPlatformOneSecond; // After doubling, first retry will happen after ten seconds
+ rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
rr->LastAPTime = m->timenow - rr->ThisAPInterval;
- rr->state = regState_FetchingZoneData;
- rr->uselease = mDNStrue;
- }
-
-// Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified
+ rr->expire = 0; // Forget about all the leases, start fresh
+ rr->uselease = mDNStrue;
+ rr->updateid = zeroID;
+ rr->SRVChanged = mDNSfalse;
+ rr->updateError = mStatus_NoError;
+ // RestartRecordGetZoneData calls this function whenever a new interface gets registered with core.
+ // The records might already be registered with the server and hence could have NAT state.
+ if (rr->NATinfo.clientContext)
+ {
+ mDNS_StopNATOperation_internal(m, &rr->NATinfo);
+ rr->NATinfo.clientContext = mDNSNULL;
+ }
+ if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; }
+ if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
+ if (m->NextuDNSEvent - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
+ m->NextuDNSEvent = (rr->LastAPTime + rr->ThisAPInterval);
+ }
+
+// Two records qualify to be local duplicates if:
+// (a) the RecordTypes are the same, or
+// (b) one is Unique and the other Verified
+// (c) either is in the process of deregistering
#define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \
- ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
+ ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified) || \
+ ((A)->resrec.RecordType == kDNSRecordTypeDeregistering || (B)->resrec.RecordType == kDNSRecordTypeDeregistering))
+
#define RecordIsLocalDuplicate(A,B) \
((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
@@ -1945,7 +653,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
AuthRecord **d = &m->DuplicateRecords;
if ((mDNSs32)rr->resrec.rroriginalttl <= 0)
- { LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
+ { LogMsg("mDNS_Register_internal: TTL %X should be 1 - 0x7FFFFFFF %s", rr->resrec.rroriginalttl, ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
if (!rr->resrec.RecordType)
{ LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
@@ -1956,7 +664,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
if (m->DivertMulticastAdvertisements && !AuthRecord_uDNS(rr))
{
mDNSInterfaceID previousID = rr->resrec.InterfaceID;
- if (rr->resrec.InterfaceID == mDNSInterface_Any) rr->resrec.InterfaceID = mDNSInterface_LocalOnly;
+ if (rr->resrec.InterfaceID == mDNSInterface_Any || rr->resrec.InterfaceID == mDNSInterface_P2P) rr->resrec.InterfaceID = mDNSInterface_LocalOnly;
if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
{
NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
@@ -1994,7 +702,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
}
// If this resource record is referencing a specific interface, make sure it exists
- if (rr->resrec.InterfaceID && rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
+ if (rr->resrec.InterfaceID && rr->resrec.InterfaceID != mDNSInterface_LocalOnly && rr->resrec.InterfaceID != mDNSInterface_P2P)
{
NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
if (!intf)
@@ -2060,8 +768,6 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
rr->Private = 0;
rr->updateid = zeroID;
rr->zone = rr->resrec.name;
- rr->UpdateServer = zeroAddr;
- rr->UpdatePort = zeroIPPort;
rr->nta = mDNSNULL;
rr->tcp = mDNSNULL;
rr->OrigRData = 0;
@@ -2078,8 +784,26 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
// rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord
// rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
+ // 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.
+ if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; }
+
if (rr->AutoTarget)
+ {
SetTargetToHostName(m, rr); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime();
+#ifndef UNICAST_DISABLED
+ // If we have no target record yet, SetTargetToHostName will set rr->state == regState_NoTarget
+ // In this case we leave the record half-formed in the list, and later we'll remove it from the list and re-add it properly.
+ if (rr->state == regState_NoTarget)
+ {
+ // Initialize the target so that we don't crash while logging etc.
+ domainname *tar = GetRRDomainNameTarget(&rr->resrec);
+ if (tar) tar->c[0] = 0;
+ LogInfo("mDNS_Register_internal: record %s in NoTarget state", ARDisplayString(m, rr));
+ }
+#endif
+ }
else
{
rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse);
@@ -2089,11 +813,6 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
if (!ValidateDomainName(rr->resrec.name))
{ LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
- // 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.
- if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; }
-
// Don't do this until *after* we've set rr->resrec.rdlength
if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
{ LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
@@ -2101,7 +820,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(&rr->resrec);
- if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
+ if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->resrec.InterfaceID == mDNSInterface_P2P)
{
// If this is supposed to be unique, make sure we don't have any name conflicts
if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
@@ -2119,17 +838,41 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
rr->resrec.RecordType = kDNSRecordTypeDeregistering;
rr->resrec.rroriginalttl = 0;
rr->ImmedAnswer = mDNSInterfaceMark;
+ m->LocalRemoveEvents = mDNStrue;
m->NextScheduledResponse = m->timenow;
}
}
}
+ // For uDNS records, we don't support duplicate checks at this time
+#ifndef UNICAST_DISABLED
+ if (AuthRecord_uDNS(rr))
+ {
+ if (!m->NewLocalRecords) m->NewLocalRecords = rr;
+ // When we called SetTargetToHostName, it may have caused mDNS_Register_internal to be re-entered, appending new
+ // records to the list, so we now need to update p to advance to the new end to the list before appending our new record.
+ // Note that for AutoTunnel this should never happen, but this check makes the code future-proof.
+ while (*p) p=&(*p)->next;
+ *p = rr;
+ if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
+ rr->ProbeCount = 0;
+ rr->AnnounceCount = 0;
+ if (rr->state != regState_NoTarget) ActivateUnicastRegistration(m, rr);
+ return(mStatus_NoError); // <--- Note: For unicast records, code currently bails out at this point
+ }
+#endif
+
// Now that we've finished building our new record, make sure it's not identical to one we already have
- for (r = m->ResourceRecords; r; r=r->next) if (RecordIsLocalDuplicate(r, rr)) break;
+ for (r = m->ResourceRecords; r; r=r->next)
+ if (RecordIsLocalDuplicate(r, rr))
+ {
+ if (r->resrec.RecordType == kDNSRecordTypeDeregistering) r->AnnounceCount = 0;
+ else break;
+ }
if (r)
{
- debugf("Adding to duplicate list %p %s", rr, ARDisplayString(m,rr));
+ debugf("mDNS_Register_internal:Adding to duplicate list %s", ARDisplayString(m,rr));
*d = rr;
// If the previous copy of this record is already verified unique,
// then indicate that we should move this record promptly to kDNSRecordTypeUnique state.
@@ -2140,25 +883,21 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
}
else
{
- debugf("Adding to active record list %p %s", rr, ARDisplayString(m,rr));
+ debugf("mDNS_Register_internal: Adding to active record list %s", ARDisplayString(m,rr));
if (!m->NewLocalRecords) m->NewLocalRecords = rr;
*p = rr;
}
- if (!AuthRecord_uDNS(rr))
+ if (!AuthRecord_uDNS(rr)) // This check is superfluous, given that for unicast records we (currently) bail out above
{
// For records that are not going to probe, acknowledge them right away
if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering)
AcknowledgeRecord(m, rr);
+
+ // Adding a record may affect whether or not we should sleep
+ mDNS_UpdateAllowSleep(m);
}
-#ifndef UNICAST_DISABLED
- else
- {
- if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
- ActivateUnicastRegistration(m, rr);
- }
-#endif
-
+
return(mStatus_NoError);
}
@@ -2184,10 +923,11 @@ mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr)
mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr)
{
RData *OldRData = rr->resrec.rdata;
+ mDNSu16 OldRDLen = rr->resrec.rdlength;
SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); // Update our rdata
rr->NewRData = mDNSNULL; // Clear the NewRData pointer ...
if (rr->UpdateCallback)
- rr->UpdateCallback(m, rr, OldRData); // ... and let the client know
+ rr->UpdateCallback(m, rr, OldRData, OldRDLen); // ... and let the client know
}
// Note: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list.
@@ -2219,7 +959,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
if (*d)
{
AuthRecord *dup = *d;
- debugf("Duplicate record %p taking over from %p %##s (%s)",
+ debugf("mDNS_Register_internal: Duplicate record %p taking over from %p %##s (%s)",
dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
*d = dup->next; // Cut replacement record from DuplicateRecords list
dup->next = rr->next; // And then...
@@ -2238,8 +978,6 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
dup->LastAPTime = rr->LastAPTime;
dup->LastMCTime = rr->LastMCTime;
dup->LastMCInterface = rr->LastMCInterface;
- dup->UpdateServer = rr->UpdateServer;
- dup->UpdatePort = rr->UpdatePort;
dup->Private = rr->Private;
dup->state = rr->state;
rr->RequireGoodbye = mDNSfalse;
@@ -2254,7 +992,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
while (*p && *p != rr) p=&(*p)->next;
// If we found our record on the duplicate list, then make sure we don't send a goodbye for it
if (*p) rr->RequireGoodbye = mDNSfalse;
- if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)",
+ if (*p) debugf("mDNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)",
rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
}
@@ -2281,25 +1019,66 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
// actual goodbye packets.
#ifndef UNICAST_DISABLED
- if (AuthRecord_uDNS(rr) && rr->RequireGoodbye)
- {
- if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
- rr->resrec.RecordType = kDNSRecordTypeDeregistering;
- uDNS_DeregisterRecord(m, rr);
- // At this point unconditionally we bail out
- // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration,
- // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration
- // process and will complete asynchronously. Either way we don't need to do anything more here.
- return(mStatus_NoError);
+ if (AuthRecord_uDNS(rr))
+ {
+ if (rr->RequireGoodbye)
+ {
+ if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
+ rr->resrec.RecordType = kDNSRecordTypeDeregistering;
+ m->LocalRemoveEvents = mDNStrue;
+ uDNS_DeregisterRecord(m, rr);
+ // At this point unconditionally we bail out
+ // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration,
+ // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration
+ // process and will complete asynchronously. Either way we don't need to do anything more here.
+ return(mStatus_NoError);
+ }
+ // Sometimes the records don't complete proper deregistration i.e., don't wait for a response
+ // from the server. In that case, if the records have been part of a group update, clear the
+ // state here. Some recors e.g., AutoTunnel gets reused without ever being completely initialized
+ rr->updateid = zeroID;
+
+ // We defer cleaning up NAT state only after sending goodbyes. This is important because
+ // RecordRegistrationGotZoneData guards against creating NAT state if clientContext is non-NULL.
+ // This happens today when we turn on/off interface where we get multiple network transitions
+ // and RestartRecordGetZoneData triggers re-registration of the resource records even though
+ // they may be in Registered state which causes NAT information to be setup multiple times. Defering
+ // the cleanup here keeps clientContext non-NULL and hence prevents that. Note that cleaning up
+ // NAT state here takes care of the case where we did not send goodbyes at all.
+ if (rr->NATinfo.clientContext)
+ {
+ mDNS_StopNATOperation_internal(m, &rr->NATinfo);
+ rr->NATinfo.clientContext = mDNSNULL;
+ }
+ if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; }
+ if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
}
#endif // UNICAST_DISABLED
- if (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ))
+ if (RecordType == kDNSRecordTypeUnregistered)
+ LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m, rr));
+ else if (RecordType == kDNSRecordTypeDeregistering)
{
- verbosedebugf("mDNS_Deregister_internal: Sending deregister for %s", ARDisplayString(m, rr));
+ LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m, rr));
+ return(mStatus_BadReferenceErr);
+ }
+
+ // <rdar://problem/7457925> Local-only questions don't get remove events for unique records
+ // We may want to consider changing this code so that we generate local-only question "rmv"
+ // events (and maybe goodbye packets too) for unique records as well as for shared records
+ // Note: If we change the logic for this "if" statement, need to ensure that the code in
+ // CompleteDeregistration() sets the appropriate state variables to gaurantee that "else"
+ // clause will execute here and the record will be cut from the list.
+ if (rr->WakeUp.HMAC.l[0] ||
+ (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ)))
+ {
+ verbosedebugf("mDNS_Deregister_internal: Starting deregistration for %s", ARDisplayString(m, rr));
rr->resrec.RecordType = kDNSRecordTypeDeregistering;
rr->resrec.rroriginalttl = 0;
- rr->ImmedAnswer = mDNSInterfaceMark;
+ rr->AnnounceCount = rr->WakeUp.HMAC.l[0] ? WakeupCount : (drt == mDNS_Dereg_rapid) ? 1 : GoodbyeCount;
+ rr->ThisAPInterval = mDNSPlatformOneSecond * 2;
+ rr->LastAPTime = m->timenow - rr->ThisAPInterval;
+ m->LocalRemoveEvents = mDNStrue;
if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0)
m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10);
}
@@ -2311,15 +1090,12 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next;
rr->next = mDNSNULL;
- if (RecordType == kDNSRecordTypeUnregistered)
- LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m, rr));
- else if (RecordType == kDNSRecordTypeDeregistering)
- LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m, rr));
- else
- {
- verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr));
- rr->resrec.RecordType = kDNSRecordTypeUnregistered;
- }
+ // Should we generate local remove events here?
+ // i.e. something like:
+ // if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; }
+
+ verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr));
+ rr->resrec.RecordType = kDNSRecordTypeUnregistered;
if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared)
debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)",
@@ -2328,8 +1104,6 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
// If we have an update queued up which never executed, give the client a chance to free that memory
if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client
- if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; }
- if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
// CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
// is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
@@ -2338,6 +1112,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
if (drt != mDNS_Dereg_conflict)
{
mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
+ LogInfo("mDNS_Deregister_internal: mStatus_MemFree for %s", ARDisplayString(m, rr));
if (rr->RecordCallback)
rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this
mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
@@ -2360,6 +1135,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
}
}
}
+ mDNS_UpdateAllowSleep(m);
return(mStatus_NoError);
}
@@ -2496,22 +1272,29 @@ mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const d
rr->NR_AdditionalTo = mDNSNULL;
}
- if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSNULL);
+ if (m->omsg.h.numAnswers)
+ mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSNULL);
}
}
+// CompleteDeregistration guarantees that on exit the record will have been cut from the m->ResourceRecords list
+// and the client's mStatus_MemFree callback will have been invoked
mDNSexport void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
{
+ LogInfo("CompleteDeregistration: called for Resource record %s", ARDisplayString(m, rr));
// Clearing rr->RequireGoodbye signals mDNS_Deregister_internal() that
// it should go ahead and immediately dispose of this registration
rr->resrec.RecordType = kDNSRecordTypeShared;
rr->RequireGoodbye = mDNSfalse;
+ rr->WakeUp.HMAC = zeroEthAddr;
if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; }
mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); // Don't touch rr after this
}
-// Note: DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback, which may change
-// the record list and/or question list.
+// DiscardDeregistrations is used on shutdown and sleep to discard (forcibly and immediately)
+// any deregistering records that remain in the m->ResourceRecords list.
+// DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback,
+// which may change the record list and/or question list.
// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
mDNSlocal void DiscardDeregistrations(mDNS *const m)
{
@@ -2522,7 +1305,7 @@ mDNSlocal void DiscardDeregistrations(mDNS *const m)
while (m->CurrentRecord)
{
AuthRecord *rr = m->CurrentRecord;
- if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
+ if (!AuthRecord_uDNS(rr) && rr->resrec.RecordType == kDNSRecordTypeDeregistering)
CompleteDeregistration(m, rr); // Don't touch rr after this
else
m->CurrentRecord = rr->next;
@@ -2539,7 +1322,7 @@ mDNSlocal mStatus GetLabelDecimalValue(const mDNSu8 *const src, mDNSu8 *dst)
val = val * 10 + src[i] - '0';
}
if (val > 255) return(mStatus_Invalid);
- *dst = val;
+ *dst = (mDNSu8)val;
return(mStatus_NoError);
}
@@ -2579,7 +1362,7 @@ mDNSlocal mStatus GetIPv6FromName(mDNSAddr *const a, const domainname *const nam
n = (const domainname *)(n->c + 2);
if (l<0 || h<0) return mStatus_Invalid;
- a->ip.v6.b[15-i] = (h << 4) | l;
+ a->ip.v6.b[15-i] = (mDNSu8)((h << 4) | l);
}
a->type = mDNSAddrType_IPv6;
@@ -2599,7 +1382,7 @@ mDNSlocal mDNSs32 ReverseMapDomainType(const domainname *const name)
}
mDNSlocal void SendARP(mDNS *const m, const mDNSu8 op, const AuthRecord *const rr,
- const mDNSu8 *const spa, const mDNSu8 *const tha, const mDNSu8 *const tpa, const mDNSu8 *const dst)
+ const mDNSv4Addr *const spa, const mDNSEthAddr *const tha, const mDNSv4Addr *const tpa, const mDNSEthAddr *const dst)
{
int i;
mDNSu8 *ptr = m->omsg.data;
@@ -2607,10 +1390,10 @@ mDNSlocal void SendARP(mDNS *const m, const mDNSu8 op, const AuthRecord *const r
if (!intf) { LogMsg("SendARP: No interface with InterfaceID %p found %s", rr->resrec.InterfaceID, ARDisplayString(m,rr)); return; }
// 0x00 Destination address
- for (i=0; i<6; i++) *ptr++ = dst[i];
+ for (i=0; i<6; i++) *ptr++ = dst->b[i];
- // 0x06 Source address (we just use zero -- driver/hardware will fill in real interface address)
- for (i=0; i<6; i++) *ptr++ = 0x0;
+ // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us)
+ for (i=0; i<6; i++) *ptr++ = intf->MAC.b[0];
// 0x0C ARP Ethertype (0x0806)
*ptr++ = 0x08; *ptr++ = 0x06;
@@ -2626,18 +1409,131 @@ mDNSlocal void SendARP(mDNS *const m, const mDNSu8 op, const AuthRecord *const r
for (i=0; i<6; i++) *ptr++ = intf->MAC.b[i];
// 0x1C Sender protocol address
- for (i=0; i<4; i++) *ptr++ = spa[i];
+ for (i=0; i<4; i++) *ptr++ = spa->b[i];
// 0x20 Target hardware address
- for (i=0; i<6; i++) *ptr++ = tha[i];
+ for (i=0; i<6; i++) *ptr++ = tha->b[i];
// 0x26 Target protocol address
- for (i=0; i<4; i++) *ptr++ = tpa[i];
+ for (i=0; i<4; i++) *ptr++ = tpa->b[i];
// 0x2A Total ARP Packet length 42 bytes
mDNSPlatformSendRawPacket(m->omsg.data, ptr, rr->resrec.InterfaceID);
}
+mDNSlocal mDNSu16 CheckSum(const void *const data, mDNSs32 length, mDNSu32 sum)
+ {
+ const mDNSu16 *ptr = data;
+ while (length > 0) { length -= 2; sum += *ptr++; }
+ sum = (sum & 0xFFFF) + (sum >> 16);
+ sum = (sum & 0xFFFF) + (sum >> 16);
+ return(sum != 0xFFFF ? sum : 0);
+ }
+
+mDNSlocal mDNSu16 IPv6CheckSum(const mDNSv6Addr *const src, const mDNSv6Addr *const dst, const mDNSu8 protocol, const void *const data, const mDNSu32 length)
+ {
+ IPv6PseudoHeader ph;
+ ph.src = *src;
+ ph.dst = *dst;
+ ph.len.b[0] = length >> 24;
+ ph.len.b[1] = length >> 16;
+ ph.len.b[2] = length >> 8;
+ ph.len.b[3] = length;
+ ph.pro.b[0] = 0;
+ ph.pro.b[1] = 0;
+ ph.pro.b[2] = 0;
+ ph.pro.b[3] = protocol;
+ return CheckSum(&ph, sizeof(ph), CheckSum(data, length, 0));
+ }
+
+mDNSlocal void SendNDP(mDNS *const m, const mDNSu8 op, const mDNSu8 flags, const AuthRecord *const rr,
+ const mDNSv6Addr *const spa, const mDNSEthAddr *const tha, const mDNSv6Addr *const tpa, const mDNSEthAddr *const dst)
+ {
+ int i;
+ mDNSOpaque16 checksum;
+ mDNSu8 *ptr = m->omsg.data;
+ // Some recipient hosts seem to ignore Neighbor Solicitations if the IPv6-layer destination address is not the
+ // appropriate IPv6 solicited node multicast address, so we use that IPv6-layer destination address, even though
+ // at the Ethernet-layer we unicast the packet to the intended target, to avoid wasting network bandwidth.
+ const mDNSv6Addr mc = { { 0xFF,0x02,0x00,0x00, 0,0,0,0, 0,0,0,1, 0xFF,tpa->b[0xD],tpa->b[0xE],tpa->b[0xF] } };
+ const mDNSv6Addr *const v6dst = (op == NDP_Sol) ? &mc : tpa;
+ NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
+ if (!intf) { LogMsg("SendNDP: No interface with InterfaceID %p found %s", rr->resrec.InterfaceID, ARDisplayString(m,rr)); return; }
+
+ // 0x00 Destination address
+ for (i=0; i<6; i++) *ptr++ = dst->b[i];
+ // Right now we only send Neighbor Solicitations to verify whether the host we're proxying for has gone to sleep yet.
+ // Since we know who we're looking for, we send it via Ethernet-layer unicast, rather than bothering every host on the
+ // link with a pointless link-layer multicast.
+ // Should we want to send traditional Neighbor Solicitations in the future, where we really don't know in advance what
+ // Ethernet-layer address we're looking for, we'll need to send to the appropriate Ethernet-layer multicast address:
+ // *ptr++ = 0x33;
+ // *ptr++ = 0x33;
+ // *ptr++ = 0xFF;
+ // *ptr++ = tpa->b[0xD];
+ // *ptr++ = tpa->b[0xE];
+ // *ptr++ = tpa->b[0xF];
+
+ // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us)
+ for (i=0; i<6; i++) *ptr++ = (tha ? *tha : intf->MAC).b[i];
+
+ // 0x0C IPv6 Ethertype (0x86DD)
+ *ptr++ = 0x86; *ptr++ = 0xDD;
+
+ // 0x0E IPv6 header
+ *ptr++ = 0x60; *ptr++ = 0x00; *ptr++ = 0x00; *ptr++ = 0x00; // Version, Traffic Class, Flow Label
+ *ptr++ = 0x00; *ptr++ = 0x20; // Length
+ *ptr++ = 0x3A; // Protocol == ICMPv6
+ *ptr++ = 0xFF; // Hop Limit
+
+ // 0x16 Sender IPv6 address
+ for (i=0; i<16; i++) *ptr++ = spa->b[i];
+
+ // 0x26 Destination IPv6 address
+ for (i=0; i<16; i++) *ptr++ = v6dst->b[i];
+
+ // 0x36 NDP header
+ *ptr++ = op; // 0x87 == Neighbor Solicitation, 0x88 == Neighbor Advertisement
+ *ptr++ = 0x00; // Code
+ *ptr++ = 0x00; *ptr++ = 0x00; // Checksum placeholder (0x38, 0x39)
+ *ptr++ = flags;
+ *ptr++ = 0x00; *ptr++ = 0x00; *ptr++ = 0x00;
+
+ if (op == NDP_Sol) // Neighbor Solicitation. The NDP "target" is the address we seek.
+ {
+ // 0x3E NDP target.
+ for (i=0; i<16; i++) *ptr++ = tpa->b[i];
+ // 0x4E Source Link-layer Address
+ // <http://www.ietf.org/rfc/rfc2461.txt>
+ // MUST NOT be included when the source IP address is the unspecified address.
+ // Otherwise, on link layers that have addresses this option MUST be included
+ // in multicast solicitations and SHOULD be included in unicast solicitations.
+ if (!mDNSIPv6AddressIsZero(*spa))
+ {
+ *ptr++ = NDP_SrcLL; // Option Type 1 == Source Link-layer Address
+ *ptr++ = 0x01; // Option length 1 (in units of 8 octets)
+ for (i=0; i<6; i++) *ptr++ = (tha ? *tha : intf->MAC).b[i];
+ }
+ }
+ else // Neighbor Advertisement. The NDP "target" is the address we're giving information about.
+ {
+ // 0x3E NDP target.
+ for (i=0; i<16; i++) *ptr++ = spa->b[i];
+ // 0x4E Target Link-layer Address
+ *ptr++ = NDP_TgtLL; // Option Type 2 == Target Link-layer Address
+ *ptr++ = 0x01; // Option length 1 (in units of 8 octets)
+ for (i=0; i<6; i++) *ptr++ = (tha ? *tha : intf->MAC).b[i];
+ }
+
+ // 0x4E or 0x56 Total NDP Packet length 78 or 86 bytes
+ m->omsg.data[0x13] = ptr - &m->omsg.data[0x36]; // Compute actual length
+ checksum.NotAnInteger = ~IPv6CheckSum(spa, v6dst, 0x3A, &m->omsg.data[0x36], m->omsg.data[0x13]);
+ m->omsg.data[0x38] = checksum.b[0];
+ m->omsg.data[0x39] = checksum.b[1];
+
+ mDNSPlatformSendRawPacket(m->omsg.data, ptr, rr->resrec.InterfaceID);
+ }
+
mDNSlocal void SetupOwnerOpt(const mDNS *const m, const NetworkInterfaceInfo *const intf, rdataOPT *const owner)
{
owner->u.owner.vers = 0;
@@ -2647,8 +1543,9 @@ mDNSlocal void SetupOwnerOpt(const mDNS *const m, const NetworkInterfaceInfo *co
owner->u.owner.password = zeroEthAddr;
// Don't try to compute the optlen until *after* we've set up the data fields
+ // Right now the DNSOpt_Owner_Space macro does not depend on the owner->u.owner being set up correctly, but in the future it might
owner->opt = kDNSOpt_Owner;
- owner->optlen = DNSOpt_Owner_Space(owner) - 4;
+ owner->optlen = DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC) - 4;
}
mDNSlocal void GrantUpdateCredit(AuthRecord *rr)
@@ -2708,30 +1605,61 @@ mDNSlocal void SendResponses(mDNS *const m)
for (rr = m->ResourceRecords; rr; rr=rr->next)
{
while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
- if (TimeToAnnounceThisRecord(rr, m->timenow) && ResourceRecordIsValidAnswer(rr))
+ if (TimeToAnnounceThisRecord(rr, m->timenow))
{
- if (rr->AddressProxy.type)
+ if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
{
- rr->AnnounceCount--;
- rr->ThisAPInterval *= 2;
- rr->LastAPTime = m->timenow;
- if (rr->AddressProxy.type == mDNSAddrType_IPv4)
+ if (!rr->WakeUp.HMAC.l[0])
{
- LogSPS("ARP Announcement %d Capturing traffic for H-MAC %.6a I-MAC %.6a %s", rr->AnnounceCount, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m,rr));
- SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
+ if (rr->AnnounceCount) rr->ImmedAnswer = mDNSInterfaceMark; // Send goodbye packet on all interfaces
}
- else if (rr->AddressProxy.type == mDNSAddrType_IPv6)
+ else
{
- //LogSPS("NDP Announcement %d %s", rr->AnnounceCount, ARDisplayString(m,rr));
- //SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
+ LogSPS("SendResponses: Sending wakeup %2d for %.6a %s", rr->AnnounceCount-3, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
+ SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password);
+ for (r2 = rr; r2; r2=r2->next)
+ if (r2->AnnounceCount && r2->resrec.InterfaceID == rr->resrec.InterfaceID && mDNSSameEthAddress(&r2->WakeUp.IMAC, &rr->WakeUp.IMAC))
+ {
+ // For now we only want to send a single Unsolicited Neighbor Advertisement restoring the address to the original
+ // owner, because these packets can cause some IPv6 stacks to falsely conclude that there's an address conflict.
+ if (r2->AddressProxy.type == mDNSAddrType_IPv6 && r2->AnnounceCount == WakeupCount)
+ {
+ LogSPS("NDP Announcement %2d Releasing traffic for H-MAC %.6a I-MAC %.6a %s",
+ r2->AnnounceCount-3, &r2->WakeUp.HMAC, &r2->WakeUp.IMAC, ARDisplayString(m,r2));
+ SendNDP(m, NDP_Adv, NDP_Override, r2, &r2->AddressProxy.ip.v6, &r2->WakeUp.IMAC, &AllHosts_v6, &AllHosts_v6_Eth);
+ }
+ r2->LastAPTime = m->timenow;
+ if (--r2->AnnounceCount <= GoodbyeCount) r2->WakeUp.HMAC = zeroEthAddr;
+ }
}
}
- else
+ else if (ResourceRecordIsValidAnswer(rr))
{
- rr->ImmedAnswer = mDNSInterfaceMark; // Send on all interfaces
- if (maxExistingAnnounceInterval < rr->ThisAPInterval)
- maxExistingAnnounceInterval = rr->ThisAPInterval;
- if (rr->UpdateBlocked) rr->UpdateBlocked = 0;
+ if (rr->AddressProxy.type)
+ {
+ rr->AnnounceCount--;
+ rr->ThisAPInterval *= 2;
+ rr->LastAPTime = m->timenow;
+ if (rr->AddressProxy.type == mDNSAddrType_IPv4)
+ {
+ LogSPS("ARP Announcement %2d Capturing traffic for H-MAC %.6a I-MAC %.6a %s",
+ rr->AnnounceCount, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m,rr));
+ SendARP(m, 1, rr, &rr->AddressProxy.ip.v4, &zeroEthAddr, &rr->AddressProxy.ip.v4, &onesEthAddr);
+ }
+ else if (rr->AddressProxy.type == mDNSAddrType_IPv6)
+ {
+ LogSPS("NDP Announcement %2d Capturing traffic for H-MAC %.6a I-MAC %.6a %s",
+ rr->AnnounceCount, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m,rr));
+ SendNDP(m, NDP_Adv, NDP_Override, rr, &rr->AddressProxy.ip.v6, mDNSNULL, &AllHosts_v6, &AllHosts_v6_Eth);
+ }
+ }
+ else
+ {
+ rr->ImmedAnswer = mDNSInterfaceMark; // Send on all interfaces
+ if (maxExistingAnnounceInterval < rr->ThisAPInterval)
+ maxExistingAnnounceInterval = rr->ThisAPInterval;
+ if (rr->UpdateBlocked) rr->UpdateBlocked = 0;
+ }
}
}
}
@@ -2811,7 +1739,8 @@ mDNSlocal void SendResponses(mDNS *const m)
if (TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2))
{
rr->AnnounceCount--;
- rr->ThisAPInterval *= 2;
+ if (rr->resrec.RecordType != kDNSRecordTypeDeregistering)
+ rr->ThisAPInterval *= 2;
rr->LastAPTime = m->timenow;
debugf("Announcing %##s (%s) %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->AnnounceCount);
}
@@ -2833,6 +1762,7 @@ mDNSlocal void SendResponses(mDNS *const m)
while (intf)
{
+ const int OwnerRecordSpace = (m->AnnounceOwner && intf->MAC.l[0]) ? DNSOpt_Header_Space + DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC) : 0;
int numDereg = 0;
int numAnnounce = 0;
int numAnswer = 0;
@@ -2848,50 +1778,44 @@ mDNSlocal void SendResponses(mDNS *const m)
{
if (rr->SendRNow == intf->InterfaceID)
{
+ RData *OldRData = rr->resrec.rdata;
+ mDNSu16 oldrdlength = rr->resrec.rdlength;
+ mDNSu8 active = (mDNSu8)
+ (rr->resrec.RecordType != kDNSRecordTypeDeregistering &&
+ (m->SleepState != SleepState_Sleeping || intf->SPSAddr[0].type || intf->SPSAddr[1].type || intf->SPSAddr[2].type));
newptr = mDNSNULL;
- if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
+ if (rr->NewRData && active)
{
- newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
- if (newptr) { responseptr = newptr; numDereg++; }
- }
- else if (rr->NewRData && !m->SleepState) // If we have new data for this record
- {
- RData *OldRData = rr->resrec.rdata;
- mDNSu16 oldrdlength = rr->resrec.rdlength;
// See if we should send a courtesy "goodbye" for the old data before we replace it.
- if (ResourceRecordIsValidAnswer(rr) && rr->RequireGoodbye)
+ if (ResourceRecordIsValidAnswer(rr) && rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
{
- newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
+ newptr = PutRR_OS_TTL(responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
if (newptr) { responseptr = newptr; numDereg++; rr->RequireGoodbye = mDNSfalse; }
+ else continue; // If this packet is already too full to hold the goodbye for this record, skip it for now and we'll retry later
}
- // Now try to see if we can fit the update in the same packet (not fatal if we can't)
SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
- if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
- rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
- newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
- rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
- if (newptr) { responseptr = newptr; rr->RequireGoodbye = mDNStrue; }
- SetNewRData(&rr->resrec, OldRData, oldrdlength);
}
- else
+
+ if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
+ rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
+ newptr = PutRR_OS_TTL(responseptr, &m->omsg.h.numAnswers, &rr->resrec, active ? rr->resrec.rroriginalttl : 0);
+ rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
+ if (newptr)
{
- mDNSu8 active = (m->SleepState != SleepState_Sleeping || intf->SPSAddr[0].type || intf->SPSAddr[1].type || intf->SPSAddr[2].type);
- if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
- rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
- newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, active ? rr->resrec.rroriginalttl : 0);
- rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
- if (newptr)
- {
- responseptr = newptr;
- rr->RequireGoodbye = active;
- if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++;
- }
-
- // The first time through (pktcount==0), if this record is verified unique
- // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too.
- if (!pktcount && active && rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->SendNSECNow) rr->SendNSECNow = (mDNSInterfaceID)1;
+ responseptr = newptr;
+ rr->RequireGoodbye = active;
+ if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) numDereg++;
+ else if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++;
}
+ if (rr->NewRData && active)
+ SetNewRData(&rr->resrec, OldRData, oldrdlength);
+
+ // The first time through (pktcount==0), if this record is verified unique
+ // (i.e. typically A, AAAA, SRV, TXT and reverse-mapping PTR), set the flag to add an NSEC too.
+ if (!pktcount && active && (rr->resrec.RecordType & kDNSRecordTypeActiveUniqueMask) && !rr->SendNSECNow)
+ rr->SendNSECNow = mDNSInterfaceMark;
+
if (newptr) // If succeeded in sending, advance to next interface
{
// If sending on all interfaces, go to next interface; else we're finished now
@@ -2928,12 +1852,13 @@ mDNSlocal void SendResponses(mDNS *const m)
else if (newptr) // Else, try to add it if we can
{
// The first time through (pktcount==0), if this record is verified unique
- // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too.
- if (!pktcount && rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->SendNSECNow) rr->SendNSECNow = (mDNSInterfaceID)1;
+ // (i.e. typically A, AAAA, SRV, TXT and reverse-mapping PTR), set the flag to add an NSEC too.
+ if (!pktcount && (rr->resrec.RecordType & kDNSRecordTypeActiveUniqueMask) && !rr->SendNSECNow)
+ rr->SendNSECNow = mDNSInterfaceMark;
if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
- newptr = PutResourceRecord(&m->omsg, newptr, &m->omsg.h.numAdditionals, &rr->resrec);
+ newptr = PutRR_OS(newptr, &m->omsg.h.numAdditionals, &rr->resrec);
rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
if (newptr)
{
@@ -2951,8 +1876,11 @@ mDNSlocal void SendResponses(mDNS *const m)
}
// Third Pass. Add NSEC records, if there's space.
+ // When we're generating an NSEC record in response to a specify query for that type
+ // (recognized by rr->SendNSECNow == intf->InterfaceID) we should really put the NSEC in the Answer Section,
+ // not Additional Section, but for now it's easier to handle both cases in this Additional Section loop here.
for (rr = m->ResourceRecords; rr; rr=rr->next)
- if (rr->SendNSECNow == (mDNSInterfaceID)1 || rr->SendNSECNow == intf->InterfaceID)
+ if (rr->SendNSECNow == mDNSInterfaceMark || rr->SendNSECNow == intf->InterfaceID)
{
AuthRecord nsec;
mDNS_SetupResourceRecord(&nsec, mDNSNULL, mDNSInterface_Any, kDNSType_NSEC, rr->resrec.rroriginalttl, kDNSRecordTypeUnique, mDNSNULL, mDNSNULL);
@@ -2968,25 +1896,45 @@ mDNSlocal void SendResponses(mDNS *const m)
newptr = responseptr;
if (!r2) // If we successfully built our NSEC record, add it to the packet now
{
- newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &nsec.resrec);
+ newptr = PutRR_OS(responseptr, &m->omsg.h.numAdditionals, &nsec.resrec);
if (newptr) responseptr = newptr;
}
// If we successfully put the NSEC record, clear the SendNSECNow flag
// If we consider this NSEC optional, then we unconditionally clear the SendNSECNow flag, even if we fail to put this additional record
- if (newptr || rr->SendNSECNow == (mDNSInterfaceID)1)
+ if (newptr || rr->SendNSECNow == mDNSInterfaceMark)
{
rr->SendNSECNow = mDNSNULL;
// Run through remainder of list clearing SendNSECNow flag for all other records which would generate the same NSEC
for (r2 = rr->next; r2; r2=r2->next)
if (SameResourceRecordNameClassInterface(r2, rr))
- if (r2->SendNSECNow == (mDNSInterfaceID)1 || r2->SendNSECNow == intf->InterfaceID)
+ if (r2->SendNSECNow == mDNSInterfaceMark || r2->SendNSECNow == intf->InterfaceID)
r2->SendNSECNow = mDNSNULL;
}
}
- if (m->omsg.h.numAnswers > 0 || m->omsg.h.numAdditionals)
+ if (m->omsg.h.numAnswers || m->omsg.h.numAdditionals)
{
+ // If we have data to send, add OWNER option if necessary, then send packet
+
+ if (OwnerRecordSpace)
+ {
+ AuthRecord opt;
+ mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
+ opt.resrec.rrclass = NormalMaxDNSMessageData;
+ opt.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record
+ opt.resrec.rdestimate = sizeof(rdataOPT);
+ SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]);
+ newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &opt.resrec);
+ if (newptr) { responseptr = newptr; LogSPS("SendResponses put %s", ARDisplayString(m, &opt)); }
+ else if (m->omsg.h.numAnswers + m->omsg.h.numAuthorities + m->omsg.h.numAdditionals == 1)
+ LogSPS("SendResponses: No space in packet for Owner OPT record (%d/%d/%d/%d) %s",
+ m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt));
+ else
+ LogMsg("SendResponses: How did we fail to have space for Owner OPT record (%d/%d/%d/%d) %s",
+ m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt));
+ }
+
debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p",
numDereg, numDereg == 1 ? "" : "s",
numAnnounce, numAnnounce == 1 ? "" : "s",
@@ -3024,17 +1972,20 @@ mDNSlocal void SendResponses(mDNS *const m)
if (rr->SendRNow)
{
- if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
- LogMsg("SendResponses: No active interface to send: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr));
+ if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly && rr->resrec.InterfaceID != mDNSInterface_P2P)
+ LogMsg("SendResponses: No active interface %p to send: %p %02X %s", rr->SendRNow, rr->resrec.InterfaceID, rr->resrec.RecordType, ARDisplayString(m, rr));
rr->SendRNow = mDNSNULL;
}
- if (rr->ImmedAnswer)
+ if (rr->ImmedAnswer || rr->resrec.RecordType == kDNSRecordTypeDeregistering)
{
if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client
- if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
- CompleteDeregistration(m, rr); // Don't touch rr after this
+ if (rr->resrec.RecordType == kDNSRecordTypeDeregistering && rr->AnnounceCount == 0)
+ {
+ // For Unicast, when we get the response from the server, we will call CompleteDeregistration
+ if (!AuthRecord_uDNS(rr)) CompleteDeregistration(m, rr); // Don't touch rr after this
+ }
else
{
rr->ImmedAnswer = mDNSNULL;
@@ -3060,20 +2011,27 @@ mDNSlocal void SendResponses(mDNS *const m)
// 5. For records with rroriginalttl set to zero, that means we really want to delete them immediately
// (we have a new record with DelayDelivery set, waiting for the old record to go away before we can notify clients).
#define CacheCheckGracePeriod(RR) ( \
- ((RR)->DelayDelivery ) ? (mDNSPlatformOneSecond/10) : \
((RR)->CRActiveQuestion == mDNSNULL ) ? (60 * mDNSPlatformOneSecond) : \
((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50) : \
((RR)->resrec.rroriginalttl > 10 ) ? (mDNSPlatformOneSecond) : \
((RR)->resrec.rroriginalttl > 0 ) ? (mDNSPlatformOneSecond/10) : 0)
-// Note: MUST call SetNextCacheCheckTime any time we change:
+#define NextCacheCheckEvent(RR) ((RR)->NextRequiredQuery + CacheCheckGracePeriod(RR))
+
+mDNSexport void ScheduleNextCacheCheckTime(mDNS *const m, const mDNSu32 slot, const mDNSs32 event)
+ {
+ if (m->rrcache_nextcheck[slot] - event > 0)
+ m->rrcache_nextcheck[slot] = event;
+ if (m->NextCacheCheck - event > 0)
+ m->NextCacheCheck = event;
+ }
+
+// Note: MUST call SetNextCacheCheckTimeForRecord any time we change:
// rr->TimeRcvd
// rr->resrec.rroriginalttl
// rr->UnansweredQueries
// rr->CRActiveQuestion
-// Also, any time we set rr->DelayDelivery we should call SetNextCacheCheckTime to ensure m->NextCacheCheck is set if necessary
-// Clearing rr->DelayDelivery does not require a call to SetNextCacheCheckTime
-mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr)
+mDNSlocal void SetNextCacheCheckTimeForRecord(mDNS *const m, CacheRecord *const rr)
{
rr->NextRequiredQuery = RRExpireTime(rr);
@@ -3083,17 +2041,11 @@ mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr)
{
rr->NextRequiredQuery -= TicksTTL(rr)/20 * (MaxUnansweredQueries - rr->UnansweredQueries);
rr->NextRequiredQuery += mDNSRandom((mDNSu32)TicksTTL(rr)/50);
- verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks",
- rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype),
- (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr));
+ verbosedebugf("SetNextCacheCheckTimeForRecord: NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks for %s",
+ (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m,rr));
}
- if (m->NextCacheCheck - (rr->NextRequiredQuery + CacheCheckGracePeriod(rr)) > 0)
- m->NextCacheCheck = (rr->NextRequiredQuery + CacheCheckGracePeriod(rr));
-
- if (rr->DelayDelivery)
- if (m->NextCacheCheck - rr->DelayDelivery > 0)
- m->NextCacheCheck = rr->DelayDelivery;
+ ScheduleNextCacheCheckTime(m, HashSlot(rr->resrec.name), NextCacheCheckEvent(rr));
}
#define kMinimumReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 5)
@@ -3118,7 +2070,7 @@ mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr,
interval += m->RandomReconfirmDelay % ((interval/3) + 1);
rr->TimeRcvd = m->timenow - (mDNSs32)interval * 3;
rr->resrec.rroriginalttl = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond;
- SetNextCacheCheckTime(m, rr);
+ SetNextCacheCheckTimeForRecord(m, rr);
}
debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s %p",
RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr), rr->CRActiveQuestion);
@@ -3136,19 +2088,12 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer
mDNSBool ucast = (q->LargeAnswers || q->RequestUnicast) && m->CanReceiveUnicastOn5353;
mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
const mDNSu8 *const limit = query->data + NormalMaxDNSMessageData;
- mDNSu8 *newptr = putQuestion(query, *queryptr, limit, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
+ mDNSu8 *newptr = putQuestion(query, *queryptr, limit - *answerforecast, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
if (!newptr)
{
debugf("BuildQuestion: No more space in this packet for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
return(mDNSfalse);
}
- else if (newptr + *answerforecast >= limit)
- {
- verbosedebugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
- q->qname.c, DNSTypeName(q->qtype), newptr + *answerforecast - query->data);
- query->h.numQuestions--;
- return(mDNSfalse);
- }
else
{
mDNSu32 forecast = *answerforecast;
@@ -3159,12 +2104,19 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache,
if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface
+ !(rr->resrec.RecordType & kDNSRecordTypeUniqueMask) && // which is a shared (i.e. not unique) record type
rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not already in the known answer list
rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question
rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow > // and its half-way-to-expiry time is at least 1 second away
mDNSPlatformOneSecond) // (also ensures we never include goodbye records with TTL=1)
{
+ // We don't want to include unique records in the Known Answer section. The Known Answer section
+ // is intended to suppress floods of shared-record replies from many other devices on the network.
+ // That concept really does not apply to unique records, and indeed if we do send a query for
+ // which we have a unique record already in our cache, then including that unique record as a
+ // Known Answer, so as to suppress the only answer we were expecting to get, makes little sense.
+
*ka = rr; // Link this record into our known answer chain
ka = &rr->NextInKAList;
// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
@@ -3195,7 +2147,7 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer
{
rr->UnansweredQueries++; // indicate that we're expecting a response
rr->LastUnansweredTime = m->timenow;
- SetNextCacheCheckTime(m, rr);
+ SetNextCacheCheckTimeForRecord(m, rr);
}
return(mDNStrue);
@@ -3377,235 +2329,232 @@ mDNSlocal void SendQueries(mDNS *const m)
CacheRecord *KnownAnswerList = mDNSNULL;
// 1. If time for a query, work out what we need to do
- if (m->timenow - m->NextScheduledQuery >= 0)
- {
- CacheRecord *rr;
- // We're expecting to send a query anyway, so see if any expiring cache records are close enough
- // to their NextRequiredQuery to be worth batching them together with this one
- FORALL_CACHERECORDS(slot, cg, rr)
- if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
- if (m->timenow + TicksTTL(rr)/50 - rr->NextRequiredQuery >= 0)
- {
- debugf("Sending %d%% cache expiration query for %s", 80 + 5 * rr->UnansweredQueries, CRDisplayString(m, rr));
- q = rr->CRActiveQuestion;
- ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(rr)/20, rr->resrec.InterfaceID);
- // For uDNS queries (TargetQID non-zero) we adjust LastQTime,
- // and bump UnansweredQueries so that we don't spin trying to send the same cache expiration query repeatedly
- if (q->Target.type) q->SendQNow = mDNSInterfaceMark; // If targeted query, mark it
- else if (!mDNSOpaque16IsZero(q->TargetQID)) { q->LastQTime = m->timenow - q->ThisQInterval; rr->UnansweredQueries++; }
- else if (q->SendQNow == mDNSNULL) q->SendQNow = rr->resrec.InterfaceID;
- else if (q->SendQNow != rr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark;
- }
+ // We're expecting to send a query anyway, so see if any expiring cache records are close enough
+ // to their NextRequiredQuery to be worth batching them together with this one
+ FORALL_CACHERECORDS(slot, cg, cr)
+ if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries)
+ if (m->timenow + TicksTTL(cr)/50 - cr->NextRequiredQuery >= 0)
+ {
+ debugf("Sending %d%% cache expiration query for %s", 80 + 5 * cr->UnansweredQueries, CRDisplayString(m, cr));
+ q = cr->CRActiveQuestion;
+ ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(cr)/20, cr->resrec.InterfaceID);
+ // For uDNS queries (TargetQID non-zero) we adjust LastQTime,
+ // and bump UnansweredQueries so that we don't spin trying to send the same cache expiration query repeatedly
+ if (q->Target.type) q->SendQNow = mDNSInterfaceMark; // If targeted query, mark it
+ else if (!mDNSOpaque16IsZero(q->TargetQID)) { q->LastQTime = m->timenow - q->ThisQInterval; cr->UnansweredQueries++; }
+ else if (q->SendQNow == mDNSNULL) q->SendQNow = cr->resrec.InterfaceID;
+ else if (q->SendQNow != cr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark;
+ }
- if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
- m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it
-
- // Scan our list of questions to see which:
- // *WideArea* queries need to be sent
- // *unicast* queries need to be sent
- // *multicast* queries we're definitely going to send
- if (m->CurrentQuestion)
- LogMsg("SendQueries ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
- m->CurrentQuestion = m->Questions;
- while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
+ // Scan our list of questions to see which:
+ // *WideArea* queries need to be sent
+ // *unicast* queries need to be sent
+ // *multicast* queries we're definitely going to send
+ if (m->CurrentQuestion)
+ LogMsg("SendQueries ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+ m->CurrentQuestion = m->Questions;
+ while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
+ {
+ q = m->CurrentQuestion;
+ if (q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
{
- q = m->CurrentQuestion;
- if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID)) uDNS_CheckCurrentQuestion(m);
- else if (mDNSOpaque16IsZero(q->TargetQID) && q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
- {
- mDNSu8 *qptr = m->omsg.data;
- const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
+ mDNSu8 *qptr = m->omsg.data;
+ const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
- // If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion), we'll try again next time
- if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
- if (q->LocalSocket)
- {
- InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags);
- qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass);
- mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, q->LocalSocket, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL);
- q->ThisQInterval *= QuestionIntervalStep;
- }
- if (q->ThisQInterval > MaxQuestionInterval)
- q->ThisQInterval = MaxQuestionInterval;
- q->LastQTime = m->timenow;
- q->LastQTxTime = m->timenow;
- q->RecentAnswerPkts = 0;
- q->SendQNow = mDNSNULL;
- q->ExpectUnicastResp = NonZeroTime(m->timenow);
- }
- else if (mDNSOpaque16IsZero(q->TargetQID) && !q->Target.type && TimeToSendThisQuestion(q, m->timenow))
+ // If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion), we'll try again next time
+ if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
+ if (q->LocalSocket)
{
- //LogInfo("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
- q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces
- if (maxExistingQuestionInterval < q->ThisQInterval)
- maxExistingQuestionInterval = q->ThisQInterval;
+ InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags);
+ qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass);
+ mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, q->LocalSocket, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL);
+ q->ThisQInterval *= QuestionIntervalStep;
}
- // If m->CurrentQuestion wasn't modified out from under us, advance it now
- // We can't do this at the start of the loop because uDNS_CheckCurrentQuestion() depends on having
- // m->CurrentQuestion point to the right question
- if (q == m->CurrentQuestion) m->CurrentQuestion = m->CurrentQuestion->next;
- }
- m->CurrentQuestion = mDNSNULL;
+ if (q->ThisQInterval > MaxQuestionInterval)
+ q->ThisQInterval = MaxQuestionInterval;
+ q->LastQTime = m->timenow;
+ q->LastQTxTime = m->timenow;
+ q->RecentAnswerPkts = 0;
+ q->SendQNow = mDNSNULL;
+ q->ExpectUnicastResp = NonZeroTime(m->timenow);
+ }
+ else if (mDNSOpaque16IsZero(q->TargetQID) && !q->Target.type && TimeToSendThisQuestion(q, m->timenow))
+ {
+ //LogInfo("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - NextQSendTime(q));
+ q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces
+ if (maxExistingQuestionInterval < q->ThisQInterval)
+ maxExistingQuestionInterval = q->ThisQInterval;
+ }
+ // If m->CurrentQuestion wasn't modified out from under us, advance it now
+ // We can't do this at the start of the loop because uDNS_CheckCurrentQuestion() depends on having
+ // m->CurrentQuestion point to the right question
+ if (q == m->CurrentQuestion) m->CurrentQuestion = m->CurrentQuestion->next;
+ }
+ while (m->CurrentQuestion)
+ {
+ LogInfo("SendQueries question loop 1: Skipping NewQuestion %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+ m->CurrentQuestion = m->CurrentQuestion->next;
+ }
+ m->CurrentQuestion = mDNSNULL;
- // Scan our list of questions
- // (a) to see if there are any more that are worth accelerating, and
- // (b) to update the state variables for *all* the questions we're going to send
- // Note: Don't set NextScheduledQuery until here, because uDNS_CheckCurrentQuestion in the loop above can add new questions to the list,
- // which causes NextScheduledQuery to get (incorrectly) set to m->timenow. Setting it here is the right place, because the very
- // next thing we do is scan the list and call SetNextQueryTime() for every question we find, so we know we end up with the right value.
- m->NextScheduledQuery = m->timenow + 0x78000000;
- for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
- {
- if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow ||
- (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q))))
+ // Scan our list of questions
+ // (a) to see if there are any more that are worth accelerating, and
+ // (b) to update the state variables for *all* the questions we're going to send
+ // Note: Don't set NextScheduledQuery until here, because uDNS_CheckCurrentQuestion in the loop above can add new questions to the list,
+ // which causes NextScheduledQuery to get (incorrectly) set to m->timenow. Setting it here is the right place, because the very
+ // next thing we do is scan the list and call SetNextQueryTime() for every question we find, so we know we end up with the right value.
+ m->NextScheduledQuery = m->timenow + 0x78000000;
+ for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
+ {
+ if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow ||
+ (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q))))
+ {
+ // If at least halfway to next query time, advance to next interval
+ // If less than halfway to next query time, then
+ // treat this as logically a repeat of the last transmission, without advancing the interval
+ if (m->timenow - (q->LastQTime + (q->ThisQInterval/2)) >= 0)
{
- // If at least halfway to next query time, advance to next interval
- // If less than halfway to next query time, then
- // treat this as logically a repeat of the last transmission, without advancing the interval
- if (m->timenow - (q->LastQTime + q->ThisQInterval/2) >= 0)
+ //LogInfo("Accelerating %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - NextQSendTime(q));
+ q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces
+ debugf("SendQueries: %##s (%s) next interval %d seconds RequestUnicast = %d",
+ q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval / InitialQuestionInterval, q->RequestUnicast);
+ q->ThisQInterval *= QuestionIntervalStep;
+ if (q->ThisQInterval > MaxQuestionInterval)
+ q->ThisQInterval = MaxQuestionInterval;
+ else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * QuestionIntervalStep3 && !q->RequestUnicast &&
+ !(RRTypeIsAddressType(q->qtype) && CacheHasAddressTypeForName(m, &q->qname, q->qnamehash)))
{
- //LogInfo("Accelerating %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
- q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces
- debugf("SendQueries: %##s (%s) next interval %d seconds RequestUnicast = %d",
- q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval / InitialQuestionInterval, q->RequestUnicast);
- q->ThisQInterval *= QuestionIntervalStep;
- if (q->ThisQInterval > MaxQuestionInterval)
- q->ThisQInterval = MaxQuestionInterval;
- else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * QuestionIntervalStep3 && !q->RequestUnicast &&
- !(RRTypeIsAddressType(q->qtype) && CacheHasAddressTypeForName(m, &q->qname, q->qnamehash)))
- {
- // Generally don't need to log this.
- // It's not especially noteworthy if a query finds no results -- this usually happens for domain
- // enumeration queries in the LL subdomain (e.g. "db._dns-sd._udp.0.0.254.169.in-addr.arpa")
- // and when there simply happen to be no instances of the service the client is looking
- // for (e.g. iTunes is set to look for RAOP devices, and the current network has none).
- debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents",
- q->qname.c, DNSTypeName(q->qtype));
- // Sending third query, and no answers yet; time to begin doubting the source
- ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0);
- }
+ // Generally don't need to log this.
+ // It's not especially noteworthy if a query finds no results -- this usually happens for domain
+ // enumeration queries in the LL subdomain (e.g. "db._dns-sd._udp.0.0.254.169.in-addr.arpa")
+ // and when there simply happen to be no instances of the service the client is looking
+ // for (e.g. iTunes is set to look for RAOP devices, and the current network has none).
+ debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents",
+ q->qname.c, DNSTypeName(q->qtype));
+ // Sending third query, and no answers yet; time to begin doubting the source
+ ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0);
}
+ }
- // Mark for sending. (If no active interfaces, then don't even try.)
- q->SendOnAll = (q->SendQNow == mDNSInterfaceMark);
- if (q->SendOnAll)
- {
- q->SendQNow = !intf ? mDNSNULL : (q->InterfaceID) ? q->InterfaceID : intf->InterfaceID;
- q->LastQTime = m->timenow;
- }
+ // Mark for sending. (If no active interfaces, then don't even try.)
+ q->SendOnAll = (q->SendQNow == mDNSInterfaceMark);
+ if (q->SendOnAll)
+ {
+ q->SendQNow = !intf ? mDNSNULL : (q->InterfaceID) ? q->InterfaceID : intf->InterfaceID;
+ q->LastQTime = m->timenow;
+ }
- // If we recorded a duplicate suppression for this question less than half an interval ago,
- // then we consider it recent enough that we don't need to do an identical query ourselves.
- ExpireDupSuppressInfo(q->DupSuppress, m->timenow - q->ThisQInterval/2);
+ // If we recorded a duplicate suppression for this question less than half an interval ago,
+ // then we consider it recent enough that we don't need to do an identical query ourselves.
+ ExpireDupSuppressInfo(q->DupSuppress, m->timenow - q->ThisQInterval/2);
- q->LastQTxTime = m->timenow;
- q->RecentAnswerPkts = 0;
- if (q->RequestUnicast) q->RequestUnicast--;
- }
- // For all questions (not just the ones we're sending) check what the next scheduled event will be
- SetNextQueryTime(m,q);
+ q->LastQTxTime = m->timenow;
+ q->RecentAnswerPkts = 0;
+ if (q->RequestUnicast) q->RequestUnicast--;
}
+ // For all questions (not just the ones we're sending) check what the next scheduled event will be
+ // We don't need to consider NewQuestions here because for those we'll set m->NextScheduledQuery in AnswerNewQuestion
+ SetNextQueryTime(m,q);
}
// 2. Scan our authoritative RR list to see what probes we might need to send
- if (m->timenow - m->NextScheduledProbe >= 0)
- {
- m->NextScheduledProbe = m->timenow + 0x78000000;
- if (m->CurrentRecord)
- LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
- m->CurrentRecord = m->ResourceRecords;
- while (m->CurrentRecord)
+ m->NextScheduledProbe = m->timenow + 0x78000000;
+
+ if (m->CurrentRecord)
+ LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
+ m->CurrentRecord = m->ResourceRecords;
+ while (m->CurrentRecord)
+ {
+ ar = m->CurrentRecord;
+ m->CurrentRecord = ar->next;
+ if (!AuthRecord_uDNS(ar) && ar->resrec.RecordType == kDNSRecordTypeUnique) // For all records that are still probing...
{
- AuthRecord *rr = m->CurrentRecord;
- m->CurrentRecord = rr->next;
- if (!AuthRecord_uDNS(rr) && rr->resrec.RecordType == kDNSRecordTypeUnique) // For all records that are still probing...
+ // 1. If it's not reached its probe time, just make sure we update m->NextScheduledProbe correctly
+ if (m->timenow - (ar->LastAPTime + ar->ThisAPInterval) < 0)
+ {
+ SetNextAnnounceProbeTime(m, ar);
+ }
+ // 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly
+ else if (ar->ProbeCount)
{
- // 1. If it's not reached its probe time, just make sure we update m->NextScheduledProbe correctly
- if (m->timenow - (rr->LastAPTime + rr->ThisAPInterval) < 0)
+ if (ar->AddressProxy.type == mDNSAddrType_IPv4)
{
- SetNextAnnounceProbeTime(m, rr);
+ LogSPS("SendQueries ARP Probe %d %s %s", ar->ProbeCount, InterfaceNameForID(m, ar->resrec.InterfaceID), ARDisplayString(m,ar));
+ SendARP(m, 1, ar, &zerov4Addr, &zeroEthAddr, &ar->AddressProxy.ip.v4, &ar->WakeUp.IMAC);
}
- // 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly
- else if (rr->ProbeCount)
+ else if (ar->AddressProxy.type == mDNSAddrType_IPv6)
{
- if (rr->AddressProxy.type == mDNSAddrType_IPv4)
- {
- LogSPS("SendQueries ARP Probe %d %s %s", rr->ProbeCount, InterfaceNameForID(m, rr->resrec.InterfaceID), ARDisplayString(m,rr));
- SendARP(m, 1, rr, zerov4Addr.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, rr->WakeUp.IMAC.b);
- }
- else if (rr->AddressProxy.type == mDNSAddrType_IPv6)
- {
- //LogSPS("SendQueries NDP Probe %d %s", rr->ProbeCount, ARDisplayString(m,rr));
- //SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
- }
- // Mark for sending. (If no active interfaces, then don't even try.)
- rr->SendRNow = (!intf || rr->WakeUp.HMAC.l[0]) ? mDNSNULL : rr->resrec.InterfaceID ? rr->resrec.InterfaceID : intf->InterfaceID;
- rr->LastAPTime = m->timenow;
- // When we have a late conflict that resets a record to probing state we use a special marker value greater
- // than DefaultProbeCountForTypeUnique. Here we detect that state and reset rr->ProbeCount back to the right value.
- if (rr->ProbeCount > DefaultProbeCountForTypeUnique)
- rr->ProbeCount = DefaultProbeCountForTypeUnique;
- rr->ProbeCount--;
- SetNextAnnounceProbeTime(m, rr);
- if (rr->ProbeCount == 0)
- {
- // If this is the last probe for this record, then see if we have any matching records
- // on our duplicate list which should similarly have their ProbeCount cleared to zero...
- AuthRecord *r2;
- for (r2 = m->DuplicateRecords; r2; r2=r2->next)
- if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, rr))
- r2->ProbeCount = 0;
- // ... then acknowledge this record to the client.
- // We do this optimistically, just as we're about to send the third probe.
- // This helps clients that both advertise and browse, and want to filter themselves
- // from the browse results list, because it helps ensure that the registration
- // confirmation will be delivered 1/4 second *before* the browse "add" event.
- // A potential downside is that we could deliver a registration confirmation and then find out
- // moments later that there's a name conflict, but applications have to be prepared to handle
- // late conflicts anyway (e.g. on connection of network cable, etc.), so this is nothing new.
- if (!rr->Acknowledged) AcknowledgeRecord(m, rr);
- }
+ LogSPS("SendQueries NDP Probe %d %s %s", ar->ProbeCount, InterfaceNameForID(m, ar->resrec.InterfaceID), ARDisplayString(m,ar));
+ // IPv6 source = zero
+ // No target hardware address
+ // IPv6 target address is address we're probing
+ // Ethernet destination address is Ethernet interface address of the Sleep Proxy client we're probing
+ SendNDP(m, NDP_Sol, 0, ar, &zerov6Addr, mDNSNULL, &ar->AddressProxy.ip.v6, &ar->WakeUp.IMAC);
}
- // else, if it has now finished probing, move it to state Verified,
- // and update m->NextScheduledResponse so it will be announced
- else
+ // Mark for sending. (If no active interfaces, then don't even try.)
+ ar->SendRNow = (!intf || ar->WakeUp.HMAC.l[0]) ? mDNSNULL : ar->resrec.InterfaceID ? ar->resrec.InterfaceID : intf->InterfaceID;
+ ar->LastAPTime = m->timenow;
+ // When we have a late conflict that resets a record to probing state we use a special marker value greater
+ // than DefaultProbeCountForTypeUnique. Here we detect that state and reset ar->ProbeCount back to the right value.
+ if (ar->ProbeCount > DefaultProbeCountForTypeUnique)
+ ar->ProbeCount = DefaultProbeCountForTypeUnique;
+ ar->ProbeCount--;
+ SetNextAnnounceProbeTime(m, ar);
+ if (ar->ProbeCount == 0)
{
- if (!rr->Acknowledged) AcknowledgeRecord(m, rr); // Defensive, just in case it got missed somehow
- rr->resrec.RecordType = kDNSRecordTypeVerified;
- rr->ThisAPInterval = DefaultAnnounceIntervalForTypeUnique;
- rr->LastAPTime = m->timenow - DefaultAnnounceIntervalForTypeUnique;
- SetNextAnnounceProbeTime(m, rr);
+ // If this is the last probe for this record, then see if we have any matching records
+ // on our duplicate list which should similarly have their ProbeCount cleared to zero...
+ AuthRecord *r2;
+ for (r2 = m->DuplicateRecords; r2; r2=r2->next)
+ if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, ar))
+ r2->ProbeCount = 0;
+ // ... then acknowledge this record to the client.
+ // We do this optimistically, just as we're about to send the third probe.
+ // This helps clients that both advertise and browse, and want to filter themselves
+ // from the browse results list, because it helps ensure that the registration
+ // confirmation will be delivered 1/4 second *before* the browse "add" event.
+ // A potential downside is that we could deliver a registration confirmation and then find out
+ // moments later that there's a name conflict, but applications have to be prepared to handle
+ // late conflicts anyway (e.g. on connection of network cable, etc.), so this is nothing new.
+ if (!ar->Acknowledged) AcknowledgeRecord(m, ar);
}
}
+ // else, if it has now finished probing, move it to state Verified,
+ // and update m->NextScheduledResponse so it will be announced
+ else
+ {
+ if (!ar->Acknowledged) AcknowledgeRecord(m, ar); // Defensive, just in case it got missed somehow
+ ar->resrec.RecordType = kDNSRecordTypeVerified;
+ ar->ThisAPInterval = DefaultAnnounceIntervalForTypeUnique;
+ ar->LastAPTime = m->timenow - DefaultAnnounceIntervalForTypeUnique;
+ SetNextAnnounceProbeTime(m, ar);
+ }
}
- m->CurrentRecord = m->DuplicateRecords;
- while (m->CurrentRecord)
- {
- AuthRecord *rr = m->CurrentRecord;
- m->CurrentRecord = rr->next;
- if (rr->resrec.RecordType == kDNSRecordTypeUnique && rr->ProbeCount == 0 && !rr->Acknowledged)
- AcknowledgeRecord(m, rr);
- }
+ }
+ m->CurrentRecord = m->DuplicateRecords;
+ while (m->CurrentRecord)
+ {
+ ar = m->CurrentRecord;
+ m->CurrentRecord = ar->next;
+ if (ar->resrec.RecordType == kDNSRecordTypeUnique && ar->ProbeCount == 0 && !ar->Acknowledged)
+ AcknowledgeRecord(m, ar);
}
// 3. Now we know which queries and probes we're sending,
// go through our interface list sending the appropriate queries on each interface
while (intf)
{
- const int os = !intf->MAC.l[0] ? 0 : DNSOpt_Header_Space + (mDNSSameEthAddress(&m->PrimaryMAC, &intf->MAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space);
- int OwnerRecordSpace = 0;
- AuthRecord *rr;
+ const int OwnerRecordSpace = (m->AnnounceOwner && intf->MAC.l[0]) ? DNSOpt_Header_Space + DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC) : 0;
mDNSu8 *queryptr = m->omsg.data;
- mDNSu8 *limit = m->omsg.data + AbsoluteMaxDNSMessageData;
InitializeDNSMessage(&m->omsg.h, zeroID, QueryFlags);
if (KnownAnswerList) verbosedebugf("SendQueries: KnownAnswerList set... Will continue from previous packet");
if (!KnownAnswerList)
{
// Start a new known-answer list
CacheRecord **kalistptr = &KnownAnswerList;
- mDNSu32 answerforecast = 0;
+ mDNSu32 answerforecast = OwnerRecordSpace; // We start by assuming we'll need at least enough space to put the Owner Option
// Put query questions in this packet
for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
@@ -3619,55 +2568,44 @@ mDNSlocal void SendQueries(mDNS *const m)
// If we're suppressing this question, or we successfully put it, update its SendQNow state
if (SuppressOnThisInterface(q->DupSuppress, intf) ||
BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast))
- q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
-
- // Once we've put at least one question, cut back our limit to the normal single-packet size
- if (m->omsg.h.numQuestions) limit = m->omsg.data + NormalMaxDNSMessageData;
+ q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
}
}
// Put probe questions in this packet
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- if (rr->SendRNow == intf->InterfaceID)
+ for (ar = m->ResourceRecords; ar; ar=ar->next)
+ if (ar->SendRNow == intf->InterfaceID)
{
- mDNSBool ucast = (rr->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353;
+ mDNSBool ucast = (ar->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353;
mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
- mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit, rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit));
+ const mDNSu8 *const limit = m->omsg.data + (m->omsg.h.numQuestions ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData);
// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
- mDNSu32 forecast = answerforecast + 12 + rr->resrec.rdestimate;
- if (newptr && newptr + forecast + os < limit)
+ mDNSu32 forecast = answerforecast + 12 + ar->resrec.rdestimate;
+ mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit - forecast, ar->resrec.name, kDNSQType_ANY, (mDNSu16)(ar->resrec.rrclass | ucbit));
+ if (newptr)
{
- queryptr = newptr;
- limit = m->omsg.data + NormalMaxDNSMessageData;
- answerforecast = forecast;
- OwnerRecordSpace = os;
- rr->SendRNow = (rr->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
- rr->IncludeInProbe = mDNStrue;
+ queryptr = newptr;
+ answerforecast = forecast;
+ ar->SendRNow = (ar->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
+ ar->IncludeInProbe = mDNStrue;
verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d",
- rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount);
- }
- else
- {
- verbosedebugf("SendQueries: Retracting Question %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
- m->omsg.h.numQuestions--;
+ ar->resrec.name->c, DNSTypeName(ar->resrec.rrtype), ar->ProbeCount);
}
}
}
- if (m->omsg.h.numQuestions) limit = m->omsg.data + NormalMaxDNSMessageData - OwnerRecordSpace;
-
// Put our known answer list (either new one from this question or questions, or remainder of old one from last time)
while (KnownAnswerList)
{
CacheRecord *ka = KnownAnswerList;
mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - ka->TimeRcvd)) / mDNSPlatformOneSecond;
- mDNSu8 *newptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAnswers, &ka->resrec, ka->resrec.rroriginalttl - SecsSinceRcvd, limit);
+ mDNSu8 *newptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAnswers,
+ &ka->resrec, ka->resrec.rroriginalttl - SecsSinceRcvd, m->omsg.data + NormalMaxDNSMessageData - OwnerRecordSpace);
if (newptr)
{
verbosedebugf("SendQueries: Put %##s (%s) at %d - %d",
ka->resrec.name->c, DNSTypeName(ka->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
queryptr = newptr;
- limit = m->omsg.data + NormalMaxDNSMessageData - OwnerRecordSpace;
KnownAnswerList = ka->NextInKAList;
ka->NextInKAList = mDNSNULL;
}
@@ -3682,33 +2620,38 @@ mDNSlocal void SendQueries(mDNS *const m)
}
}
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- if (rr->IncludeInProbe)
+ for (ar = m->ResourceRecords; ar; ar=ar->next)
+ if (ar->IncludeInProbe)
{
- mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, &rr->resrec);
- rr->IncludeInProbe = mDNSfalse;
+ mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, &ar->resrec);
+ ar->IncludeInProbe = mDNSfalse;
if (newptr) queryptr = newptr;
- else LogMsg("SendQueries: How did we fail to have space for the Update record %s", ARDisplayString(m,rr));
+ else LogMsg("SendQueries: How did we fail to have space for the Update record %s", ARDisplayString(m,ar));
}
- if (OwnerRecordSpace)
- {
- AuthRecord opt;
- mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
- opt.resrec.rrclass = NormalMaxDNSMessageData;
- opt.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record
- opt.resrec.rdestimate = sizeof(rdataOPT);
- SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]);
- LogSPS("SendQueries putting %s", ARDisplayString(m, &opt));
- queryptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAdditionals,
- &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData);
- if (!queryptr)
- LogMsg("SendQueries: How did we fail to have space for the OPT record (%d/%d/%d/%d) %s",
- m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt));
- }
-
if (queryptr > m->omsg.data)
{
+ if (OwnerRecordSpace)
+ {
+ AuthRecord opt;
+ mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
+ opt.resrec.rrclass = NormalMaxDNSMessageData;
+ opt.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record
+ opt.resrec.rdestimate = sizeof(rdataOPT);
+ SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]);
+ LogSPS("SendQueries putting %s", ARDisplayString(m, &opt));
+ queryptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAdditionals,
+ &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData);
+ if (!queryptr)
+ LogMsg("SendQueries: How did we fail to have space for the OPT record (%d/%d/%d/%d) %s",
+ m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt));
+ if (queryptr > m->omsg.data + NormalMaxDNSMessageData)
+ if (m->omsg.h.numQuestions != 1 || m->omsg.h.numAnswers != 0 || m->omsg.h.numAuthorities != 1 || m->omsg.h.numAdditionals != 1)
+ LogMsg("SendQueries: Why did we generate oversized packet with OPT record %p %p %p (%d/%d/%d/%d) %s",
+ m->omsg.data, m->omsg.data + NormalMaxDNSMessageData, queryptr,
+ m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt));
+ }
+
if ((m->omsg.h.flags.b[0] & kDNSFlag0_TC) && m->omsg.h.numQuestions > 1)
LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m->omsg.h.numQuestions);
debugf("SendQueries: Sending %d Question%s %d Answer%s %d Update%s on %p",
@@ -3740,8 +2683,8 @@ mDNSlocal void SendQueries(mDNS *const m)
for (ar = m->ResourceRecords; ar; ar=ar->next)
if (ar->SendRNow)
{
- if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly)
- LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, ar));
+ if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly && ar->resrec.InterfaceID != mDNSInterface_P2P)
+ LogMsg("SendQueries: No active interface %p to send probe: %p %s", ar->SendRNow, ar->resrec.InterfaceID, ARDisplayString(m, ar));
ar->SendRNow = mDNSNULL;
}
@@ -3751,12 +2694,13 @@ mDNSlocal void SendQueries(mDNS *const m)
// state machine ticking over we just pretend we did so.
// If the interface does not come back in time, the cache record will expire naturally
FORALL_CACHERECORDS(slot, cg, cr)
- if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries && m->timenow - cr->NextRequiredQuery >= 0)
- {
- cr->UnansweredQueries++;
- cr->CRActiveQuestion->SendQNow = mDNSNULL;
- SetNextCacheCheckTime(m, cr);
- }
+ if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries)
+ if (m->timenow + TicksTTL(cr)/50 - cr->NextRequiredQuery >= 0)
+ {
+ cr->UnansweredQueries++;
+ cr->CRActiveQuestion->SendQNow = mDNSNULL;
+ SetNextCacheCheckTimeForRecord(m, cr);
+ }
// 4c. Debugging check: Make sure we sent all our planned questions
// Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions
@@ -3764,7 +2708,9 @@ mDNSlocal void SendQueries(mDNS *const m)
for (q = m->Questions; q; q=q->next)
if (q->SendQNow)
{
- LogMsg("SendQueries: No active interface to send: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ DNSQuestion *x;
+ for (x = m->NewQuestions; x; x=x->next) if (x == q) break; // Check if this question is a NewQuestion
+ LogMsg("SendQueries: No active interface %p to send %s question: %p %##s (%s)", q->SendQNow, x ? "new" : "old", q->InterfaceID, q->qname.c, DNSTypeName(q->qtype));
q->SendQNow = mDNSNULL;
}
}
@@ -3773,14 +2719,14 @@ mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAdd
{
int i, j;
mDNSu8 *ptr = m->omsg.data;
-
- if (!InterfaceID) { LogMsg("SendWakeup: No InterfaceID specified"); return; }
+ NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
+ if (!intf) { LogMsg("SendARP: No interface with InterfaceID %p found", InterfaceID); return; }
// 0x00 Destination address
for (i=0; i<6; i++) *ptr++ = EthAddr->b[i];
- // 0x06 Source address (we just use zero -- BPF will fill in real interface address)
- for (i=0; i<6; i++) *ptr++ = 0x0;
+ // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us)
+ for (i=0; i<6; i++) *ptr++ = intf->MAC.b[0];
// 0x0C Ethertype (0x0842)
*ptr++ = 0x08;
@@ -3821,7 +2767,10 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
DNSQuestion *const q = m->CurrentQuestion;
mDNSBool followcname = rr->resrec.RecordType != kDNSRecordTypePacketNegative && AddRecord &&
rr->resrec.rrtype == kDNSType_CNAME && q->qtype != kDNSType_CNAME;
- verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s", q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, CRDisplayString(m, rr));
+ verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s",
+ q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, CRDisplayString(m, rr));
+
+ if (QuerySuppressed(q)) return;
// Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue)
// may be called twice, once when the record is received, and again when it's time to notify local clients.
@@ -3831,9 +2780,10 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
if (AddRecord == QC_add && !q->DuplicateOf && rr->CRActiveQuestion != q)
{
if (!rr->CRActiveQuestion) m->rrcache_active++; // If not previously active, increment rrcache_active count
- debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr));
+ debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion from %p to %p for cache record %s, CurrentAnswer %d",
+ rr->CRActiveQuestion, q, CRDisplayString(m,rr), q->CurrentAnswers);
rr->CRActiveQuestion = q; // We know q is non-null
- SetNextCacheCheckTime(m, rr);
+ SetNextCacheCheckTimeForRecord(m, rr);
}
// If this is:
@@ -3868,7 +2818,7 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
if (q->qtype != kDNSType_NSEC && RRAssertsNonexistence(&rr->resrec, q->qtype))
{
CacheRecord neg;
- MakeNegativeCacheRecord(m, &neg, &q->qname, q->qnamehash, q->qtype, q->qclass, 1, rr->resrec.InterfaceID);
+ MakeNegativeCacheRecord(m, &neg, &q->qname, q->qnamehash, q->qtype, q->qclass, 1, rr->resrec.InterfaceID, q->qDNSServer);
q->QuestionCallback(m, q, &neg.resrec, AddRecord);
}
else
@@ -3878,27 +2828,135 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
// Note: Proceed with caution here because client callback function is allowed to do anything,
// including starting/stopping queries, registering/deregistering records, etc.
- if (followcname && m->CurrentQuestion == q && q->CNAMEReferrals < 10)
+ if (followcname && m->CurrentQuestion == q)
{
- const mDNSu32 c = q->CNAMEReferrals + 1;
- // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect,
- // and track CNAMEs coming and going, we should really create a subordinate query here,
- // which we would subsequently cancel and retract if the CNAME referral record were removed.
- // In reality this is such a corner case we'll ignore it until someone actually needs it.
- LogInfo("AnswerCurrentQuestionWithResourceRecord: following CNAME referral for %s", CRDisplayString(m, rr));
- mDNS_StopQuery_internal(m, q); // Stop old query
- AssignDomainName(&q->qname, &rr->resrec.rdata->u.name); // Update qname
- q->qnamehash = DomainNameHashValue(&q->qname); // and namehash
- mDNS_StartQuery_internal(m, q); // start new query
- q->CNAMEReferrals = c; // and keep count of how many times we've done this
+ const mDNSBool selfref = SameDomainName(&q->qname, &rr->resrec.rdata->u.name);
+ if (q->CNAMEReferrals >= 10 || selfref)
+ LogMsg("AnswerCurrentQuestionWithResourceRecord: %p %##s (%s) NOT following CNAME referral %d%s for %s",
+ q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, selfref ? " (Self-Referential)" : "", CRDisplayString(m, rr));
+ else
+ {
+ const mDNSu32 c = q->CNAMEReferrals + 1; // Stash a copy of the new q->CNAMEReferrals value
+
+ // The SameDomainName check above is to ignore bogus CNAME records that point right back at
+ // themselves. Without that check we can get into a case where we have two duplicate questions,
+ // A and B, and when we stop question A, UpdateQuestionDuplicates copies the value of CNAMEReferrals
+ // from A to B, and then A is re-appended to the end of the list as a duplicate of B (because
+ // the target name is still the same), and then when we stop question B, UpdateQuestionDuplicates
+ // copies the B's value of CNAMEReferrals back to A, and we end up not incrementing CNAMEReferrals
+ // for either of them. This is not a problem for CNAME loops of two or more records because in
+ // those cases the newly re-appended question A has a different target name and therefore cannot be
+ // a duplicate of any other question ('B') which was itself a duplicate of the previous question A.
+
+ // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect,
+ // and track CNAMEs coming and going, we should really create a subordinate query here,
+ // which we would subsequently cancel and retract if the CNAME referral record were removed.
+ // In reality this is such a corner case we'll ignore it until someone actually needs it.
+ LogInfo("AnswerCurrentQuestionWithResourceRecord: %p %##s (%s) following CNAME referral %d for %s",
+ q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, CRDisplayString(m, rr));
+
+ mDNS_StopQuery_internal(m, q); // Stop old query
+ AssignDomainName(&q->qname, &rr->resrec.rdata->u.name); // Update qname
+ q->qnamehash = DomainNameHashValue(&q->qname); // and namehash
+ // If a unicast query results in a CNAME that points to a .local, we need to re-try
+ // this as unicast. Setting the mDNSInterface_Unicast tells mDNS_StartQuery_internal
+ // to try this as unicast query even though it is a .local name
+ if (!mDNSOpaque16IsZero(q->TargetQID) && IsLocalDomain(&q->qname))
+ {
+ LogInfo("AnswerCurrentQuestionWithResourceRecord: Resolving a .local CNAME %p %##s (%s) CacheRecord %s",
+ q, q->qname.c, DNSTypeName(q->qtype), CRDisplayString(m, rr));
+ q->InterfaceID = mDNSInterface_Unicast;
+ }
+ mDNS_StartQuery_internal(m, q); // start new query
+ // Record how many times we've done this. We need to do this *after* mDNS_StartQuery_internal,
+ // because mDNS_StartQuery_internal re-initializes CNAMEReferrals to zero
+ q->CNAMEReferrals = c;
+ }
}
}
+// New Questions are answered through AnswerNewQuestion. But there may not have been any
+// matching cache records for the questions when it is called. There are two possibilities.
+//
+// 1) There are no cache records
+// 2) There are cache records but the DNSServers between question and cache record don't match.
+//
+// In the case of (1), where there are no cache records and later we add them when we get a response,
+// CacheRecordAdd/CacheRecordDeferredAdd will take care of adding the cache and delivering the ADD
+// events to the application. If we already have a cache entry, then no ADD events are delivered
+// unless the RDATA has changed
+//
+// In the case of (2) where we had the cache records and did not answer because of the DNSServer mismatch,
+// we need to answer them whenever we change the DNSServer. But we can't do it at the instant the DNSServer
+// changes because when we do the callback, the question can get deleted and the calling function would not
+// know how to handle it. So, we run this function from mDNS_Execute to handle DNSServer changes on the
+// question
+
+mDNSlocal void AnswerQuestionsForDNSServerChanges(mDNS *const m)
+ {
+ DNSQuestion *q;
+ DNSQuestion *qnext;
+ CacheRecord *rr;
+ mDNSu32 slot;
+ CacheGroup *cg;
+
+ if (m->CurrentQuestion)
+ LogMsg("AnswerQuestionsForDNSServerChanges: ERROR m->CurrentQuestion already set: %##s (%s)",
+ m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+
+ for (q = m->Questions; q && q != m->NewQuestions; q = qnext)
+ {
+ qnext = q->next;
+
+ // multicast or DNSServers did not change.
+ if (mDNSOpaque16IsZero(q->TargetQID)) continue;
+ if (!q->deliverAddEvents) continue;
+
+ // We are going to look through the cache for this question since it changed
+ // its DNSserver last time. Reset it so that we don't call them again. Calling
+ // them again will deliver duplicate events to the application
+ q->deliverAddEvents = mDNSfalse;
+ if (QuerySuppressed(q)) continue;
+ m->CurrentQuestion = q;
+ slot = HashSlot(&q->qname);
+ cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+ {
+ if (SameNameRecordAnswersQuestion(&rr->resrec, q))
+ {
+ LogInfo("AnswerQuestionsForDNSServerChanges: Calling AnswerCurrentQuestionWithResourceRecord for question %p %##s using resource record %s",
+ q, q->qname.c, CRDisplayString(m, rr));
+ // When this question penalizes a DNS server and has no more DNS servers to pick, we normally
+ // deliver a negative cache response and suspend the question for 60 seconds (see uDNS_CheckCurrentQuestion).
+ // But sometimes we may already find the negative cache entry and deliver that here as the process
+ // of changing DNS servers. When the cache entry is about to expire, we will resend the question and
+ // that time, we need to make sure that we have a valid DNS server. Otherwise, we will deliver
+ // a negative cache response without trying the server.
+ if (!q->qDNSServer && !q->DuplicateOf && rr->resrec.RecordType == kDNSRecordTypePacketNegative)
+ {
+ DNSQuestion *qptr;
+ SetValidDNSServers(m, q);
+ q->qDNSServer = GetServerForQuestion(m, q);
+ for (qptr = q->next ; qptr; qptr = qptr->next)
+ if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; }
+ }
+ q->CurrentAnswers++;
+ if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
+ if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
+ AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
+ if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
+ }
+ }
+ }
+ m->CurrentQuestion = mDNSNULL;
+ }
+
mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
{
- rr->DelayDelivery = 0; // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
+ rr->DelayDelivery = 0;
if (m->CurrentQuestion)
- LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+ LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)",
+ m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
m->CurrentQuestion = m->Questions;
while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
{
@@ -3926,7 +2984,7 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *c
else return(0);
}
-// CacheRecordAdd is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
+// CacheRecordAdd is only called from CreateNewCacheEntry, *never* directly as a result of a client API call.
// If new questions are created as a result of invoking client callbacks, they will be added to
// the end of the question list, and m->NewQuestions will be set to indicate the first new question.
// rr is a new CacheRecord just received into our cache
@@ -3963,8 +3021,10 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
SetNextQueryTime(m,q);
}
}
- verbosedebugf("CacheRecordAdd %p %##s (%s) %lu",
- rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl);
+ verbosedebugf("CacheRecordAdd %p %##s (%s) %lu %#a:%d question %p", rr, rr->resrec.name->c,
+ DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl, rr->resrec.rDNSServer ?
+ &rr->resrec.rDNSServer->addr : mDNSNULL, mDNSVal16(rr->resrec.rDNSServer ?
+ rr->resrec.rDNSServer->port : zeroIPPort), q);
q->CurrentAnswers++;
q->unansweredQueries = 0;
if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
@@ -3997,7 +3057,7 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
m->CurrentQuestion = mDNSNULL;
}
- SetNextCacheCheckTime(m, rr);
+ SetNextCacheCheckTimeForRecord(m, rr);
}
// NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
@@ -4041,7 +3101,8 @@ mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
{
if (m->CurrentQuestion)
- LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+ LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)",
+ m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
m->CurrentQuestion = m->Questions;
// We stop when we get to NewQuestions -- for new questions their CurrentAnswers/LargeAnswers/UniqueAnswers counters
@@ -4049,14 +3110,31 @@ mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
{
DNSQuestion *q = m->CurrentQuestion;
- if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+ // When a question enters suppressed state, we generate RMV events and generate a negative
+ // response. A cache may be present that answers this question e.g., cache entry generated
+ // before the question became suppressed. We need to skip the suppressed questions here as
+ // the RMV event has already been generated.
+ if (!QuerySuppressed(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
{
verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr));
q->FlappingInterface1 = mDNSNULL;
q->FlappingInterface2 = mDNSNULL;
+
+ // When a question changes DNS server, it is marked with deliverAddEvents if we find any
+ // cache entry corresponding to the new DNS server. Before we deliver the ADD event, the
+ // cache entry may be removed in which case CurrentAnswers can be zero.
+ if (q->deliverAddEvents && !q->CurrentAnswers)
+ {
+ LogInfo("CacheRecordRmv: Question %p %##s (%s) deliverAddEvents set, DNSServer %#a:%d",
+ q, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL,
+ mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort));
+ m->CurrentQuestion = q->next;
+ continue;
+ }
if (q->CurrentAnswers == 0)
- LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?",
- q, q->qname.c, DNSTypeName(q->qtype));
+ LogMsg("CacheRecordRmv ERROR!!: How can CurrentAnswers already be zero for %p %##s (%s) DNSServer %#a:%d",
+ q, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL,
+ mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort));
else
{
q->CurrentAnswers--;
@@ -4116,7 +3194,7 @@ mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r)
// Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering
// CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all
// callbacks for old records are delivered before callbacks for newer records.
-mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg)
+mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGroup *const cg)
{
CacheRecord **rp = &cg->members;
@@ -4130,10 +3208,24 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg)
if (m->timenow - event >= 0) // If expired, delete it
{
*rp = rr->next; // Cut it from the list
- verbosedebugf("CheckCacheExpiration: Deleting%7d %4d %p %s",
+ verbosedebugf("CheckCacheExpiration: Deleting%7d %7d %p %s",
m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr));
if (rr->CRActiveQuestion) // If this record has one or more active questions, tell them it's going away
{
+ DNSQuestion *q = rr->CRActiveQuestion;
+ // When a cache record is about to expire, we expect to do four queries at 80-82%, 85-87%, 90-92% and
+ // then 95-97% of the TTL. If the DNS server does not respond, then we will remove the cache entry
+ // before we pick a new DNS server. As the question interval is set to MaxQuestionInterval, we may
+ // not send out a query anytime soon. Hence, we need to reset the question interval. If this is
+ // a normal deferred ADD case, then AnswerCurrentQuestionWithResourceRecord will reset it to
+ // MaxQuestionInterval. If we have inactive questions referring to negative cache entries,
+ // don't ressurect them as they will deliver duplicate "No such Record" ADD events
+ if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && ActiveQuestion(q))
+ {
+ q->ThisQInterval = InitialQuestionInterval;
+ q->LastQTime = m->timenow - q->ThisQInterval;
+ SetNextQueryTime(m, q);
+ }
CacheRecordRmv(m, rr);
m->rrcache_active--;
}
@@ -4141,6 +3233,7 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg)
}
else // else, not expired; see if we need to query
{
+ // If waiting to delay delivery, do nothing until then
if (rr->DelayDelivery && rr->DelayDelivery - m->timenow > 0)
event = rr->DelayDelivery;
else
@@ -4149,13 +3242,13 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg)
if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
{
if (m->timenow - rr->NextRequiredQuery < 0) // If not yet time for next query
- event = rr->NextRequiredQuery; // then just record when we want the next query
+ event = NextCacheCheckEvent(rr); // then just record when we want the next query
else // else trigger our question to go out now
{
// Set NextScheduledQuery to timenow so that SendQueries() will run.
// SendQueries() will see that we have records close to expiration, and send FEQs for them.
m->NextScheduledQuery = m->timenow;
- // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(),
+ // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTimeForRecord(),
// which will correctly update m->NextCacheCheck for us.
event = m->timenow + 0x3FFFFFFF;
}
@@ -4163,8 +3256,8 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg)
}
verbosedebugf("CheckCacheExpiration:%6d %5d %s",
(event - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr));
- if (m->NextCacheCheck - (event + CacheCheckGracePeriod(rr)) > 0)
- m->NextCacheCheck = (event + CacheCheckGracePeriod(rr));
+ if (m->rrcache_nextcheck[slot] - event > 0)
+ m->rrcache_nextcheck[slot] = event;
rp = &rr->next;
}
}
@@ -4173,18 +3266,48 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg)
m->lock_rrcache = 0;
}
+// Caller should hold the lock
+mDNSlocal void AnswerSuppressUnusableQuestion(mDNS *const m, DNSQuestion *q)
+ {
+ LogInfo("AnswerSuppressUnusableQuestion: Generating negative response for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ if (!m->CurrentQuestion) LogMsg("AnswerSuppressUnusableQuestion: ERROR!! CurrentQuestion not set");
+
+ MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, mDNSNULL);
+ AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache);
+ if (m->CurrentQuestion == q) q->ThisQInterval = 0; // Deactivate this question
+ // Don't touch the question after this
+ m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
+ }
+
mDNSlocal void AnswerNewQuestion(mDNS *const m)
{
mDNSBool ShouldQueryImmediately = mDNStrue;
- DNSQuestion *q = m->NewQuestions; // Grab the question we're going to answer
+ DNSQuestion *const q = m->NewQuestions; // Grab the question we're going to answer
const mDNSu32 slot = HashSlot(&q->qname);
CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- if (cg) CheckCacheExpiration(m, cg);
- m->NewQuestions = q->next; // Advance NewQuestions to the next *after* calling CheckCacheExpiration();
-
+ if (cg) CheckCacheExpiration(m, slot, cg);
+ if (m->NewQuestions != q) { LogInfo("AnswerNewQuestion: Question deleted while doing CheckCacheExpiration"); goto exit; }
+ m->NewQuestions = q->next;
+ // Advance NewQuestions to the next *after* calling CheckCacheExpiration, because if we advance it first
+ // then CheckCacheExpiration may give this question add/remove callbacks, and it's not yet ready for that.
+ //
+ // Also, CheckCacheExpiration() calls CacheRecordDeferredAdd() and CacheRecordRmv(), which invoke
+ // client callbacks, which may delete their own or any other question. Our mechanism for detecting
+ // whether our current m->NewQuestions question got deleted by one of these callbacks is to store the
+ // value of m->NewQuestions in 'q' before calling CheckCacheExpiration(), and then verify afterwards
+ // that they're still the same. If m->NewQuestions has changed (because mDNS_StopQuery_internal
+ // advanced it), that means the question was deleted, so we no longer need to worry about answering
+ // it (and indeed 'q' is now a dangling pointer, so dereferencing it at all would be bad, and the
+ // values we computed for slot and cg are now stale and relate to a question that no longer exists).
+ //
+ // We can't use the usual m->CurrentQuestion mechanism for this because CacheRecordDeferredAdd() and
+ // CacheRecordRmv() both use that themselves when walking the list of (non-new) questions generating callbacks.
+ // Fortunately mDNS_StopQuery_internal auto-advances both m->CurrentQuestion *AND* m->NewQuestions when
+ // deleting a question, so luckily we have an easy alternative way of detecting if our question got deleted.
+
if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!");
// This should be safe, because calling the client's question callback may cause the
// question list to be modified, but should not ever cause the rrcache list to be modified.
@@ -4192,21 +3315,23 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
// be advanced, and we'll exit out of the loop
m->lock_rrcache = 1;
if (m->CurrentQuestion)
- LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+ LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)",
+ m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted
if (q->NoAnswer == NoAnswer_Fail)
{
LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any);
+ MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, q->qDNSServer);
q->NoAnswer = NoAnswer_Normal; // Temporarily turn off answer suppression
AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache);
q->NoAnswer = NoAnswer_Fail; // Restore NoAnswer state
m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
}
+ if (m->CurrentQuestion != q) { LogInfo("AnswerNewQuestion: Question deleted while generating NoAnswer_Fail response"); goto exit; }
// If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records
- if (m->CurrentQuestion == q && q->InterfaceID == mDNSInterface_Any)
+ if (q->InterfaceID == mDNSInterface_Any)
{
if (m->CurrentRecord)
LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
@@ -4215,7 +3340,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
{
AuthRecord *rr = m->CurrentRecord;
m->CurrentRecord = rr->next;
- if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
+ if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->resrec.InterfaceID == mDNSInterface_P2P)
if (ResourceRecordAnswersQuestion(&rr->resrec, q))
{
AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, mDNStrue);
@@ -4224,10 +3349,12 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
}
m->CurrentRecord = mDNSNULL;
}
+ if (m->CurrentQuestion != q) { LogInfo("AnswerNewQuestion: Question deleted while while giving LocalOnly record answers"); goto exit; }
- if (m->CurrentQuestion != q) debugf("AnswerNewQuestion: question deleted while giving LocalOnly record answers");
-
- if (m->CurrentQuestion == q)
+ // If we are not supposed to answer this question, generate a negative response.
+ // Temporarily suspend the SuppressQuery so that AnswerCurrentQuestionWithResourceRecord can answer the question
+ if (QuerySuppressed(q)) { q->SuppressQuery = mDNSfalse; AnswerSuppressUnusableQuestion(m, q); q->SuppressQuery = mDNStrue; }
+ else
{
CacheRecord *rr;
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
@@ -4255,10 +3382,11 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
ShouldQueryImmediately = mDNSfalse;
}
+ // We don't use LogInfo for this "Question deleted" message because it happens so routinely that
+ // it's not remotely remarkable, and therefore unlikely to be of much help tracking down bugs.
+ if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving cache answers"); goto exit; }
- if (m->CurrentQuestion != q) debugf("AnswerNewQuestion: question deleted while giving cache answers");
-
- if (m->CurrentQuestion == q && ShouldQueryImmediately && ActiveQuestion(q))
+ if (ShouldQueryImmediately && ActiveQuestion(q))
{
debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
q->ThisQInterval = InitialQuestionInterval;
@@ -4270,11 +3398,16 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
m->RandomQueryDelay = (mDNSPlatformOneSecond + mDNSRandom(mDNSPlatformOneSecond*5) - 1) / 50 + 1;
q->LastQTime += m->RandomQueryDelay;
}
-
- if (m->NextScheduledQuery - (q->LastQTime + q->ThisQInterval) > 0)
- m->NextScheduledQuery = (q->LastQTime + q->ThisQInterval);
}
+ // IN ALL CASES make sure that m->NextScheduledQuery is set appropriately.
+ // In cases where m->NewQuestions->DelayAnswering is set, we may have delayed generating our
+ // answers for this question until *after* its scheduled transmission time, in which case
+ // m->NextScheduledQuery may now be set to 'never', and in that case -- even though we're *not* doing
+ // ShouldQueryImmediately -- we still need to make sure we set m->NextScheduledQuery correctly.
+ SetNextQueryTime(m,q);
+
+exit:
m->CurrentQuestion = mDNSNULL;
m->lock_rrcache = 0;
}
@@ -4289,7 +3422,8 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
if (m->CurrentQuestion)
- LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+ LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)",
+ m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted
if (m->CurrentRecord)
@@ -4452,7 +3586,7 @@ mDNSexport void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr)
rr->TimeRcvd = m->timenow - mDNSPlatformOneSecond * 60;
rr->UnansweredQueries = MaxUnansweredQueries;
rr->resrec.rroriginalttl = 0;
- SetNextCacheCheckTime(m, rr);
+ SetNextCacheCheckTimeForRecord(m, rr);
}
mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m)
@@ -4485,24 +3619,26 @@ mDNSlocal void CheckProxyRecords(mDNS *const m, AuthRecord *list)
while (m->CurrentRecord)
{
AuthRecord *rr = m->CurrentRecord;
- if (rr->WakeUp.HMAC.l[0])
+ if (rr->resrec.RecordType != kDNSRecordTypeDeregistering && rr->WakeUp.HMAC.l[0])
{
- if (m->timenow - rr->TimeExpire < 0) // If proxy record not expired yet, update m->NextScheduledSPS
+ // If m->SPSSocket is NULL that means we're not acting as a sleep proxy any more,
+ // so we need to cease proxying for *all* records we may have, expired or not.
+ if (m->SPSSocket && m->timenow - rr->TimeExpire < 0) // If proxy record not expired yet, update m->NextScheduledSPS
{
if (m->NextScheduledSPS - rr->TimeExpire > 0)
m->NextScheduledSPS = rr->TimeExpire;
}
- else // else proxy record expired, so remove it
+ else // else proxy record expired, so remove it
{
- LogSPS("mDNS_Execute: Removing %d H-MAC %.6a I-MAC %.6a %d %s",
+ LogSPS("CheckProxyRecords: Removing %d H-MAC %.6a I-MAC %.6a %d %s",
m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, ARDisplayString(m, rr));
SetSPSProxyListChanged(rr->resrec.InterfaceID);
mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
// Don't touch rr after this -- memory may have been free'd
}
}
- // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal,
- // because the list may have been changed in that call.
+ // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because
+ // new records could have been added to the end of the list as a result of that call.
if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
m->CurrentRecord = rr->next;
}
@@ -4515,10 +3651,16 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
if (m->timenow - m->NextScheduledEvent >= 0)
{
int i;
+ AuthRecord *head, *tail;
verbosedebugf("mDNS_Execute");
+
if (m->CurrentQuestion)
- LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+ LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)",
+ m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+
+ if (m->CurrentRecord)
+ LogMsg("mDNS_Execute: ERROR m->CurrentRecord already set: %s", ARDisplayString(m, m->CurrentRecord));
// 1. If we're past the probe suppression time, we can clear it
if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0;
@@ -4529,18 +3671,29 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
// 3. Purge our cache of stale old records
if (m->rrcache_size && m->timenow - m->NextCacheCheck >= 0)
{
- mDNSu32 slot;
+ mDNSu32 slot, numchecked = 0;
m->NextCacheCheck = m->timenow + 0x3FFFFFFF;
for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
{
- CacheGroup **cp = &m->rrcache_hash[slot];
- while (*cp)
+ if (m->timenow - m->rrcache_nextcheck[slot] >= 0)
{
- CheckCacheExpiration(m, *cp);
- if ((*cp)->members) cp=&(*cp)->next;
- else ReleaseCacheGroup(m, cp);
+ CacheGroup **cp = &m->rrcache_hash[slot];
+ m->rrcache_nextcheck[slot] = m->timenow + 0x3FFFFFFF;
+ while (*cp)
+ {
+ debugf("m->NextCacheCheck %4d Slot %3d %##s", numchecked, slot, *cp ? (*cp)->name : (domainname*)"\x04NULL");
+ numchecked++;
+ CheckCacheExpiration(m, slot, *cp);
+ if ((*cp)->members) cp=&(*cp)->next;
+ else ReleaseCacheGroup(m, cp);
+ }
}
+ // Even if we didn't need to actually check this slot yet, still need to
+ // factor its nextcheck time into our overall NextCacheCheck value
+ if (m->NextCacheCheck - m->rrcache_nextcheck[slot] > 0)
+ m->NextCacheCheck = m->rrcache_nextcheck[slot];
}
+ debugf("m->NextCacheCheck %4d checked, next in %d", numchecked, m->NextCacheCheck - m->timenow);
}
if (m->timenow - m->NextScheduledSPS >= 0)
@@ -4552,6 +3705,9 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
SetSPSProxyListChanged(mDNSNULL); // Perform any deferred BPF reconfiguration now
+ // Clear AnnounceOwner if necessary. (Do this *before* SendQueries() and SendResponses().)
+ if (m->AnnounceOwner && m->timenow - m->AnnounceOwner >= 0) m->AnnounceOwner = 0;
+
if (m->DelaySleep && m->timenow - m->DelaySleep >= 0)
{
m->DelaySleep = 0;
@@ -4569,19 +3725,89 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
AnswerNewQuestion(m);
}
if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit");
+
+ // Make sure we deliver *all* local RMV events, and clear the corresponding rr->AnsweredLocalQ flags, *before*
+ // we begin generating *any* new ADD events in the m->NewLocalOnlyQuestions and m->NewLocalRecords loops below.
+ for (i=0; i<1000 && m->LocalRemoveEvents; i++)
+ {
+ m->LocalRemoveEvents = mDNSfalse;
+ m->CurrentRecord = m->ResourceRecords;
+ while (m->CurrentRecord)
+ {
+ AuthRecord *rr = m->CurrentRecord;
+ if (rr->AnsweredLocalQ && rr->resrec.RecordType == kDNSRecordTypeDeregistering)
+ {
+ debugf("mDNS_Execute: Generating local RMV events for %s", ARDisplayString(m, rr));
+ rr->resrec.RecordType = kDNSRecordTypeShared;
+ AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse);
+ if (m->CurrentRecord == rr) // If rr still exists in list, restore its state now
+ {
+ rr->resrec.RecordType = kDNSRecordTypeDeregistering;
+ rr->AnsweredLocalQ = mDNSfalse;
+ }
+ }
+ if (m->CurrentRecord == rr) // If m->CurrentRecord was not auto-advanced, do it ourselves now
+ m->CurrentRecord = rr->next;
+ }
+ }
+ if (i >= 1000) LogMsg("mDNS_Execute: m->LocalRemoveEvents exceeded loop limit");
for (i=0; m->NewLocalOnlyQuestions && i<1000; i++) AnswerNewLocalOnlyQuestion(m);
if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit");
- for (i=0; i<1000 && m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords); i++)
+ head = tail = mDNSNULL;
+ for (i=0; i<1000 && m->NewLocalRecords && m->NewLocalRecords != head; i++)
{
AuthRecord *rr = m->NewLocalRecords;
m->NewLocalRecords = m->NewLocalRecords->next;
- AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue);
+ if (LocalRecordReady(rr))
+ {
+ debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr));
+ AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue);
+ }
+ else if (!rr->next)
+ {
+ // If we have just one record that is not ready, we don't have to unlink and
+ // reinsert. As the NewLocalRecords will be NULL for this case, the loop will
+ // terminate and set the NewLocalRecords to rr.
+ debugf("mDNS_Execute: Just one LocalAuthRecord %s, breaking out of the loop early", ARDisplayString(m, rr));
+ if (head != mDNSNULL || m->NewLocalRecords != mDNSNULL)
+ LogMsg("mDNS_Execute: ERROR!!: head %p, NewLocalRecords %p", head, m->NewLocalRecords);
+
+ head = rr;
+ }
+ else
+ {
+ AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records
+ debugf("mDNS_Execute: Skipping LocalAuthRecord %s", ARDisplayString(m, rr));
+ // if this is the first record we are skipping, move to the end of the list.
+ // if we have already skipped records before, append it at the end.
+ while (*p && *p != rr) p=&(*p)->next;
+ if (*p) *p = rr->next; // Cut this record from the list
+ else { LogMsg("mDNS_Execute: ERROR!! Cannot find record %s in ResourceRecords list", ARDisplayString(m, rr)); break; }
+ if (!head)
+ {
+ while (*p) p=&(*p)->next;
+ *p = rr;
+ head = tail = rr;
+ }
+ else
+ {
+ tail->next = rr;
+ tail = rr;
+ }
+ rr->next = mDNSNULL;
+ }
}
- if (i >= 1000) LogMsg("mDNS_Execute: AnswerForNewLocalRecords exceeded loop limit");
+ m->NewLocalRecords = head;
+ debugf("mDNS_Execute: Setting NewLocalRecords to %s", (head ? ARDisplayString(m, head) : "NULL"));
- // 5. See what packets we need to send
+ if (i >= 1000) LogMsg("mDNS_Execute: m->NewLocalRecords exceeded loop limit");
+
+ // 5. Some questions may have picked a new DNS server and the cache may answer these questions now.
+ AnswerQuestionsForDNSServerChanges(m);
+
+ // 6. See what packets we need to send
if (m->mDNSPlatformStatus != mStatus_NoError || (m->SleepState == SleepState_Sleeping))
DiscardDeregistrations(m);
if (m->mDNSPlatformStatus == mStatus_NoError && (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0))
@@ -4594,7 +3820,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
// Finally, we send responses, including the previously mentioned records that just completed probing.
m->SuppressSending = 0;
- // 6. Send Query packets. This may cause some probing records to advance to announcing state
+ // 7. Send Query packets. This may cause some probing records to advance to announcing state
if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m);
if (m->timenow - m->NextScheduledQuery >= 0)
{
@@ -4603,7 +3829,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
m->timenow, m->NextScheduledQuery, m->timenow - m->NextScheduledQuery);
m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond;
for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
- if (ActiveQuestion(q) && q->LastQTime + q->ThisQInterval - m->timenow <= 0)
+ if (ActiveQuestion(q) && m->timenow - NextQSendTime(q) >= 0)
LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
}
if (m->timenow - m->NextScheduledProbe >= 0)
@@ -4613,7 +3839,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond;
}
- // 7. Send Response packets, including probing records just advanced to announcing state
+ // 8. Send Response packets, including probing records just advanced to announcing state
if (m->timenow - m->NextScheduledResponse >= 0) SendResponses(m);
if (m->timenow - m->NextScheduledResponse >= 0)
{
@@ -4625,6 +3851,12 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
// Clear RandomDelay values, ready to pick a new different value next time
m->RandomQueryDelay = 0;
m->RandomReconfirmDelay = 0;
+
+#ifndef UNICAST_DISABLED
+ if (m->NextSRVUpdate && m->timenow - m->NextSRVUpdate >= 0) UpdateAllSRVRecords(m);
+ if (m->timenow - m->NextScheduledNATOp >= 0) CheckNATMappings(m);
+ if (m->timenow - m->NextuDNSEvent >= 0) uDNS_Tasks(m);
+#endif
}
// Note about multi-threaded systems:
@@ -4647,9 +3879,6 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
// callback function should call mDNS_Execute() (and ignore the return value, which may already be stale
// by the time it gets to the timer callback function).
-#ifndef UNICAST_DISABLED
- uDNS_Execute(m);
-#endif
mDNS_Unlock(m); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
return(m->NextScheduledEvent);
}
@@ -4677,8 +3906,11 @@ mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question,
// Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the
// caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel.
// To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then
- // returns results for both at the same time.
- if (RRTypeIsAddressType(question->qtype) && question->AuthInfo && question->AuthInfo->AutoTunnel && question->QuestionCallback != AutoTunnelCallback)
+ // returns results for both at the same time. If we are looking for the _autotunnel6 record, then skip this logic
+ // as this would trigger looking up _autotunnel6._autotunnel6 and end up failing the original query.
+
+ if (RRTypeIsAddressType(question->qtype) && PrivateQuery(question) &&
+ !SameDomainLabel(question->qname.c, (const mDNSu8 *)"\x0c_autotunnel6")&& question->QuestionCallback != AutoTunnelCallback)
{
question->NoAnswer = NoAnswer_Suspended;
AddNewClientTunnel(m, question);
@@ -4689,7 +3921,8 @@ mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question,
if (!question->DuplicateOf)
{
debugf("ActivateUnicastQuery: %##s %s%s%s",
- question->qname.c, DNSTypeName(question->qtype), question->AuthInfo ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : "");
+ question->qname.c, DNSTypeName(question->qtype), PrivateQuery(question) ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : "");
+ question->CNAMEReferrals = 0;
if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
if (question->LongLived)
{
@@ -4714,13 +3947,14 @@ mDNSexport void mDNSCoreRestartQueries(mDNS *const m)
#ifndef UNICAST_DISABLED
// Retrigger all our uDNS questions
if (m->CurrentQuestion)
- LogMsg("mDNSCoreRestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+ LogMsg("mDNSCoreRestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)",
+ m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
m->CurrentQuestion = m->Questions;
while (m->CurrentQuestion)
{
q = m->CurrentQuestion;
m->CurrentQuestion = m->CurrentQuestion->next;
- if (!mDNSOpaque16IsZero(q->TargetQID)) ActivateUnicastQuery(m, q, mDNStrue);
+ if (!mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q)) ActivateUnicastQuery(m, q, mDNStrue);
}
#endif
@@ -4743,10 +3977,58 @@ mDNSexport void mDNSCoreRestartQueries(mDNS *const m)
#pragma mark - Power Management (Sleep/Wake)
#endif
+mDNSexport void mDNS_UpdateAllowSleep(mDNS *const m)
+ {
+#ifndef IDLESLEEPCONTROL_DISABLED
+ mDNSBool allowSleep = mDNStrue;
+
+ if (m->SystemSleepOnlyIfWakeOnLAN)
+ {
+ // Don't sleep if we are a proxy for any services
+ if (m->ProxyRecords)
+ {
+ allowSleep = mDNSfalse;
+ LogInfo("Sleep disabled because we are proxying %d records", m->ProxyRecords);
+ }
+
+ if (allowSleep && mDNSCoreHaveAdvertisedMulticastServices(m))
+ {
+ // Scan the list of active interfaces
+ NetworkInterfaceInfo *intf;
+ for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
+ {
+ if (intf->McastTxRx)
+ {
+ // Disallow sleep if this interface doesn't support NetWake
+ if (!intf->NetWake)
+ {
+ allowSleep = mDNSfalse;
+ LogInfo("Sleep disabled because %s does not support NetWake", intf->ifname);
+ break;
+ }
+
+ // Disallow sleep if there is no sleep proxy server
+ if (FindSPSInCache1(m, &intf->NetWakeBrowse, mDNSNULL, mDNSNULL) == mDNSNULL)
+ {
+ allowSleep = mDNSfalse;
+ LogInfo("Sleep disabled because %s has no sleep proxy", intf->ifname);
+ break;
+ }
+ }
+ }
+ }
+#endif /* !defined(IDLESLEEPCONTROL_DISABLED) */
+ }
+
+#if 0
+ // Call the platform code to enable/disable sleep
+ mDNSPlatformSetAllowSleep(m, allowSleep);
+#endif
+ }
+
mDNSlocal void SendSPSRegistration(mDNS *const m, NetworkInterfaceInfo *intf, const mDNSOpaque16 id)
{
- const int ownerspace = mDNSSameEthAddress(&m->PrimaryMAC, &intf->MAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space;
- const int optspace = DNSOpt_Header_Space + DNSOpt_LeaseData_Space + ownerspace;
+ const int optspace = DNSOpt_Header_Space + DNSOpt_LeaseData_Space + DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC);
const int sps = intf->NextSPSAttempt / 3;
AuthRecord *rr;
@@ -4818,6 +4100,9 @@ mDNSlocal void SendSPSRegistration(mDNS *const m, NetworkInterfaceInfo *intf, co
else
{
mStatus err;
+ // Once we've attempted to register, we need to include our OWNER option in our packets when we re-awaken
+ m->SentSleepProxyRegistration = mDNStrue;
+
LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf->ifname, intf->NextSPSAttempt, sps,
mDNSVal16(m->omsg.h.id), m->omsg.h.mDNS_numUpdates, p - m->omsg.data, &intf->SPSAddr[sps], mDNSVal16(intf->SPSPort[sps]));
// if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID; // For simulating packet loss
@@ -4870,18 +4155,19 @@ mDNSlocal void RetrySPSRegistrations(mDNS *const m)
mDNSlocal void NetWakeResolve(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
NetworkInterfaceInfo *intf = (NetworkInterfaceInfo *)question->QuestionContext;
- int sps = question - intf->NetWakeResolve;
+ int sps = (int)(question - intf->NetWakeResolve);
(void)m; // Unused
LogSPS("NetWakeResolve: SPS: %d Add: %d %s", sps, AddRecord, RRDisplayString(m, answer));
if (!AddRecord) return; // Don't care about REMOVE events
if (answer->rrtype != question->qtype) return; // Don't care about CNAMEs
- mDNS_StopQuery(m, question);
- question->ThisQInterval = -1;
+ // if (answer->rrtype == kDNSType_AAAA && sps == 0) return; // To test failing to resolve sleep proxy's address
if (answer->rrtype == kDNSType_SRV)
{
+ // 1. Got the SRV record; now look up the target host's IPv6 link-local address
+ mDNS_StopQuery(m, question);
intf->SPSPort[sps] = answer->rdata->u.srv.port;
AssignDomainName(&question->qname, &answer->rdata->u.srv.target);
question->qtype = kDNSType_AAAA;
@@ -4889,20 +4175,28 @@ mDNSlocal void NetWakeResolve(mDNS *const m, DNSQuestion *question, const Resour
}
else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == sizeof(mDNSv6Addr) && mDNSv6AddressIsLinkLocal(&answer->rdata->u.ipv6))
{
+ // 2. Got the target host's IPv6 link-local address; record address and initiate an SPS registration if appropriate
+ mDNS_StopQuery(m, question);
+ question->ThisQInterval = -1;
intf->SPSAddr[sps].type = mDNSAddrType_IPv6;
intf->SPSAddr[sps].ip.v6 = answer->rdata->u.ipv6;
mDNS_Lock(m);
if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID); // If we're ready for this result, use it now
mDNS_Unlock(m);
}
- else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == 0) // If negative answer for IPv6, look for IPv4 addresses instead
+ else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == 0)
{
+ // 3. Got negative response -- target host apparently has IPv6 disabled -- so try looking up the target host's IPv4 address(es) instead
+ mDNS_StopQuery(m, question);
LogSPS("NetWakeResolve: SPS %d %##s has no IPv6 address, will try IPv4 instead", sps, question->qname.c);
question->qtype = kDNSType_A;
mDNS_StartQuery(m, question);
}
else if (answer->rrtype == kDNSType_A && answer->rdlength == sizeof(mDNSv4Addr))
{
+ // 4. Got an IPv4 address for the target host; record address and initiate an SPS registration if appropriate
+ mDNS_StopQuery(m, question);
+ question->ThisQInterval = -1;
intf->SPSAddr[sps].type = mDNSAddrType_IPv4;
intf->SPSAddr[sps].ip.v4 = answer->rdata->u.ipv4;
mDNS_Lock(m);
@@ -4920,9 +4214,26 @@ mDNSexport mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m)
return mDNSfalse;
}
+mDNSlocal void SendSleepGoodbyes(mDNS *const m)
+ {
+ AuthRecord *rr;
+ m->SleepState = SleepState_Sleeping;
+
+#ifndef UNICAST_DISABLED
+ SleepRecordRegistrations(m); // If we have no SPS, need to deregister our uDNS records
+#endif /* UNICAST_DISABLED */
+
+ // Mark all the records we need to deregister and send them
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
+ rr->ImmedAnswer = mDNSInterfaceMark;
+ SendResponses(m);
+ }
+
// BeginSleepProcessing is called, with the lock held, from either mDNS_Execute or mDNSCoreMachineSleep
mDNSlocal void BeginSleepProcessing(mDNS *const m)
{
+ mDNSBool SendGoodbyes = mDNStrue;
const CacheRecord *sps[3] = { mDNSNULL };
m->NextScheduledSPRetry = m->timenow;
@@ -4935,13 +4246,25 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m)
for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
{
if (!intf->NetWake) LogSPS("BeginSleepProcessing: %-6s not capable of magic packet wakeup", intf->ifname);
+#if APPLE_OSX_mDNSResponder
+ else if (ActivateLocalProxy(m, intf->ifname) == mStatus_NoError)
+ {
+ SendGoodbyes = mDNSfalse;
+ LogSPS("BeginSleepProcessing: %-6s using local proxy", intf->ifname);
+ // This will leave m->SleepState set to SleepState_Transferring,
+ // which is okay because with no outstanding resolves, or updates in flight,
+ // mDNSCoreReadyForSleep() will conclude correctly that all the updates have already completed
+ }
+#endif // APPLE_OSX_mDNSResponder
else
{
FindSPSInCache(m, &intf->NetWakeBrowse, sps);
- if (!sps[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found %d", intf->ifname, &intf->ip, intf->NetWakeBrowse.ThisQInterval);
+ if (!sps[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found (Next Browse Q in %d, interval %d)",
+ intf->ifname, &intf->ip, NextQSendTime(&intf->NetWakeBrowse) - m->timenow, intf->NetWakeBrowse.ThisQInterval);
else
{
int i;
+ SendGoodbyes = mDNSfalse;
intf->NextSPSAttempt = 0;
intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond;
// Don't need to set m->NextScheduledSPRetry here because we already set "m->NextScheduledSPRetry = m->timenow" above
@@ -4969,22 +4292,10 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m)
}
}
- if (!sps[0]) // If we didn't find even one Sleep Proxy
+ if (SendGoodbyes) // If we didn't find even one Sleep Proxy
{
- AuthRecord *rr;
LogSPS("BeginSleepProcessing: Not registering with Sleep Proxy Server");
- m->SleepState = SleepState_Sleeping;
-
-#ifndef UNICAST_DISABLED
- SleepServiceRegistrations(m);
- SleepRecordRegistrations(m); // If we have no SPS, need to deregister our uDNS records
-#endif
-
- // Mark all the records we need to deregister and send them
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
- rr->ImmedAnswer = mDNSInterfaceMark;
- SendResponses(m);
+ SendSleepGoodbyes(m);
}
}
@@ -4995,12 +4306,11 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
{
AuthRecord *rr;
- mDNS_Lock(m);
-
LogSPS("%s (old state %d) at %ld", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow);
if (sleep && !m->SleepState) // Going to sleep
{
+ mDNS_Lock(m);
// If we're going to sleep, need to stop advertising that we're a Sleep Proxy Server
if (m->SPSSocket)
{
@@ -5016,20 +4326,25 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
{
// If we just woke up moments ago, allow ten seconds for networking to stabilize before going back to sleep
LogSPS("mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m->DelaySleep - m->timenow);
- m->SleepLimit = m->DelaySleep + mDNSPlatformOneSecond * 10;
+ m->SleepLimit = NonZeroTime(m->DelaySleep + mDNSPlatformOneSecond * 10);
}
else
{
m->DelaySleep = 0;
- m->SleepLimit = m->timenow + mDNSPlatformOneSecond * 10;
+ m->SleepLimit = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 10);
BeginSleepProcessing(m);
}
#ifndef UNICAST_DISABLED
SuspendLLQs(m);
#endif
+ mDNS_Unlock(m);
+ // RemoveAutoTunnel6Record needs to be called outside the lock, as it grabs the lock also.
+#if APPLE_OSX_mDNSResponder
+ RemoveAutoTunnel6Record(m);
+#endif
LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m->SleepState,
- m->SleepState == SleepState_Transferring ? "Transferring" :
+ m->SleepState == SleepState_Transferring ? "Transferring" :
m->SleepState == SleepState_Sleeping ? "Sleeping" : "?", m->SleepSeqNum);
}
else if (!sleep) // Waking up
@@ -5039,11 +4354,20 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
CacheRecord *cr;
NetworkInterfaceInfo *intf;
+ mDNS_Lock(m);
+ // Reset SleepLimit back to 0 now that we're awake again.
+ m->SleepLimit = 0;
+
// If we were previously sleeping, but now we're not, increment m->SleepSeqNum to indicate that we're entering a new period of wakefulness
if (m->SleepState != SleepState_Awake)
{
m->SleepState = SleepState_Awake;
m->SleepSeqNum++;
+ if (m->SentSleepProxyRegistration) // Include OWNER option in packets for 60 seconds after waking
+ {
+ m->SentSleepProxyRegistration = mDNSfalse;
+ m->AnnounceOwner = NonZeroTime(m->timenow + 60 * mDNSPlatformOneSecond);
+ }
// If the machine wakes and then immediately tries to sleep again (e.g. a maintenance wake)
// then we enforce a minimum delay of 16 seconds before we begin sleep processing.
// This is to allow time for the Ethernet link to come up, DHCP to get an address, mDNS to issue queries, etc.,
@@ -5053,10 +4377,8 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
if (m->SPSState == 3)
{
- mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here
m->SPSState = 0;
- mDNSCoreBeSleepProxyServer(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower);
- mDNS_ReclaimLockAfterCallback();
+ mDNSCoreBeSleepProxyServer_internal(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower);
}
// In case we gave up waiting and went to sleep before we got an ack from the Sleep Proxy,
@@ -5071,10 +4393,9 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
// and reactivtate service registrations
m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
- LogInfo("WakeServiceRegistrations %d %d", m->timenow, m->NextSRVUpdate);
+ LogInfo("mDNSCoreMachineSleep waking: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
// 2. Re-validate our cache records
- m->NextCacheCheck = m->timenow;
FORALL_CACHERECORDS(slot, cg, cr)
mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake);
@@ -5089,87 +4410,131 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
rr->AnnounceCount = InitialAnnounceCount;
+ rr->SendNSECNow = mDNSNULL;
InitializeLastAPTime(m, rr);
}
// 4. Refresh NAT mappings
// We don't want to have to assume that all hardware can necessarily keep accurate
// track of passage of time while asleep, so on wake we refresh our NAT mappings
+ // We typically wake up with no interfaces active, so there's no need to rush to try to find our external address.
+ // When we get a network configuration change, mDNSMacOSXNetworkChanged calls uDNS_SetupDNSConfig, which calls
+ // mDNS_SetPrimaryInterfaceInfo, which then sets m->retryGetAddr to immediately request our external address from the NAT gateway.
m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
- m->retryGetAddr = m->timenow;
+ m->retryGetAddr = m->timenow + mDNSPlatformOneSecond * 5;
+ LogInfo("mDNSCoreMachineSleep: retryGetAddr in %d %d", m->retryGetAddr - m->timenow, m->timenow);
RecreateNATMappings(m);
+ mDNS_Unlock(m);
}
-
- mDNS_Unlock(m);
}
-mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m)
+mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now)
{
DNSQuestion *q;
AuthRecord *rr;
- ServiceRecordSet *srs;
NetworkInterfaceInfo *intf;
mDNS_Lock(m);
- if (m->NextScheduledSPRetry - m->timenow > 0) goto notready;
+ if (m->DelaySleep) goto notready;
- m->NextScheduledSPRetry = m->timenow + 0x40000000UL;
+ // If we've not hit the sleep limit time, and it's not time for our next retry, we can skip these checks
+ if (m->SleepLimit - now > 0 && m->NextScheduledSPRetry - now > 0) goto notready;
- if (m->DelaySleep) goto notready;
+ m->NextScheduledSPRetry = now + 0x40000000UL;
// See if we might need to retransmit any lost Sleep Proxy Registrations
for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
if (intf->NextSPSAttempt >= 0)
{
- if (m->timenow - intf->NextSPSAttemptTime >= 0)
+ if (now - intf->NextSPSAttemptTime >= 0)
{
- LogSPS("ReadyForSleep retrying SPS %s %d", intf->ifname, intf->NextSPSAttempt);
+ LogSPS("mDNSCoreReadyForSleep: retrying for %s SPS %d try %d",
+ intf->ifname, intf->NextSPSAttempt/3, intf->NextSPSAttempt);
SendSPSRegistration(m, intf, zeroID);
+ // Don't need to "goto notready" here, because if we do still have record registrations
+ // that have not been acknowledged yet, we'll catch that in the record list scan below.
}
else
if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0)
m->NextScheduledSPRetry = intf->NextSPSAttemptTime;
}
- // Scan list of private LLQs, and make sure they've all completed their handshake with the server
- for (q = m->Questions; q; q = q->next)
- if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->ReqLease == 0 && q->tcp)
+ // Scan list of interfaces, and see if we're still waiting for any sleep proxy resolves to complete
+ for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
+ {
+ int sps = (intf->NextSPSAttempt == 0) ? 0 : (intf->NextSPSAttempt-1)/3;
+ if (intf->NetWakeResolve[sps].ThisQInterval >= 0)
{
- LogSPS("ReadyForSleep waiting for LLQ %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- goto notready;
+ LogSPS("mDNSCoreReadyForSleep: waiting for SPS Resolve %s %##s (%s)",
+ intf->ifname, intf->NetWakeResolve[sps].qname.c, DNSTypeName(intf->NetWakeResolve[sps].qtype));
+ goto spsnotready;
}
+ }
- // Scan list of interfaces
- for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
- if (intf->NetWakeResolve[0].ThisQInterval >= 0)
+ // Scan list of registered records
+ for (rr = m->ResourceRecords; rr; rr = rr->next)
+ if (!AuthRecord_uDNS(rr))
+ if (!mDNSOpaque16IsZero(rr->updateid))
+ { LogSPS("mDNSCoreReadyForSleep: waiting for SPS Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto spsnotready; }
+
+ // Scan list of private LLQs, and make sure they've all completed their handshake with the server
+ for (q = m->Questions; q; q = q->next)
+ if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->ReqLease == 0 && q->tcp)
{
- LogSPS("ReadyForSleep waiting for SPS Resolve %s %##s (%s)", intf->ifname, intf->NetWakeResolve[0].qname.c, DNSTypeName(intf->NetWakeResolve[0].qtype));
+ LogSPS("mDNSCoreReadyForSleep: waiting for LLQ %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
goto notready;
}
// Scan list of registered records
for (rr = m->ResourceRecords; rr; rr = rr->next)
- {
if (AuthRecord_uDNS(rr))
{
if (rr->state == regState_Refresh && rr->tcp)
- { LogSPS("ReadyForSleep waiting for Record Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; }
- }
- else
- {
- if (!mDNSOpaque16IsZero(rr->updateid))
- { LogSPS("ReadyForSleep waiting for SPS Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; }
+ { LogSPS("mDNSCoreReadyForSleep: waiting for Record Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; }
+ #if APPLE_OSX_mDNSResponder
+ if (!RecordReadyForSleep(m, rr)) { LogSPS("mDNSCoreReadyForSleep: waiting for %s", ARDisplayString(m, rr)); goto notready; }
+ #endif
}
- }
-
- // Scan list of registered services
- for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next)
- if (srs->state == regState_NoTarget && srs->tcp) goto notready;
mDNS_Unlock(m);
return mDNStrue;
+spsnotready:
+
+ // If we failed to complete sleep proxy registration within ten seconds, we give up on that
+ // and allow up to ten seconds more to complete wide-area deregistration instead
+ if (now - m->SleepLimit >= 0)
+ {
+ LogMsg("Failed to register with SPS, now sending goodbyes");
+
+ for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
+ if (intf->NetWakeBrowse.ThisQInterval >= 0)
+ {
+ LogSPS("ReadyForSleep mDNS_DeactivateNetWake %s %##s (%s)",
+ intf->ifname, intf->NetWakeResolve[0].qname.c, DNSTypeName(intf->NetWakeResolve[0].qtype));
+ mDNS_DeactivateNetWake_internal(m, intf);
+ }
+
+ for (rr = m->ResourceRecords; rr; rr = rr->next)
+ if (!AuthRecord_uDNS(rr))
+ if (!mDNSOpaque16IsZero(rr->updateid))
+ {
+ LogSPS("ReadyForSleep clearing updateid for %s", ARDisplayString(m, rr));
+ rr->updateid = zeroID;
+ }
+
+ // We'd really like to allow up to ten seconds more here,
+ // but if we don't respond to the sleep notification within 30 seconds
+ // we'll be put back to sleep forcibly without the chance to schedule the next maintenance wake.
+ // Right now we wait 16 sec after wake for all the interfaces to come up, then we wait up to 10 seconds
+ // more for SPS resolves and record registrations to complete, which puts us at 26 seconds.
+ // If we allow just one more second to send our goodbyes, that puts us at 27 seconds.
+ m->SleepLimit = now + mDNSPlatformOneSecond * 1;
+
+ SendSleepGoodbyes(m);
+ }
+
notready:
mDNS_Unlock(m);
return mDNSfalse;
@@ -5243,7 +4608,7 @@ mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const m
// ***
if (LegacyQuery)
{
- maxttl = 10;
+ maxttl = kStaticCacheTTL;
for (i=0; i<query->h.numQuestions; i++) // For each question...
{
DNSQuestion q;
@@ -5415,7 +4780,7 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q
{
ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
if (!ptr) break;
- if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
+ if (m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
{
FoundUpdate = mDNStrue;
if (PacketRRConflict(m, our, &m->rec.r))
@@ -5426,11 +4791,11 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q
if (result)
{
const char *const msg = (result < 0) ? "lost:" : (result > 0) ? "won: " : "tie: ";
- LogMsg("ResolveSimultaneousProbe: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
- LogMsg("ResolveSimultaneousProbe: Our Record %d %s %08lX %s", our->ProbeCount, msg, our->resrec.rdatahash, ARDisplayString(m, our));
+ LogMsg("ResolveSimultaneousProbe: %p Pkt Record: %08lX %s", q->InterfaceID, m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
+ LogMsg("ResolveSimultaneousProbe: %p Our Record %d %s %08lX %s", our->resrec.InterfaceID, our->ProbeCount, msg, our->resrec.rdatahash, ARDisplayString(m, our));
}
// If we lost the tie-break for simultaneous probes, we don't immediately give up, because we might be seeing stale packets on the network.
- // Instead we pause for one second, to give the other host (if real) a change to establish its name, and then try probing again.
+ // Instead we pause for one second, to give the other host (if real) a chance to establish its name, and then try probing again.
// If there really is another live host out there with the same name, it will answer our probes and we'll then rename.
if (result < 0)
{
@@ -5444,8 +4809,8 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q
#if 0
else
{
- LogMsg("ResolveSimultaneousProbe: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
- LogMsg("ResolveSimultaneousProbe: Our Record ign: %08lX %s", our->resrec.rdatahash, ARDisplayString(m, our));
+ LogMsg("ResolveSimultaneousProbe: %p Pkt Record: %08lX %s", q->InterfaceID, m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
+ LogMsg("ResolveSimultaneousProbe: %p Our Record %d ign: %08lX %s", our->resrec.InterfaceID, our->ProbeCount, our->resrec.rdatahash, ARDisplayString(m, our));
}
#endif
}
@@ -5462,14 +4827,47 @@ mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, const Res
mDNSu32 slot = HashSlot(pktrr->name);
CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr);
CacheRecord *rr;
+ mDNSBool match;
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
- if (pktrr->InterfaceID == rr->resrec.InterfaceID && IdenticalSameNameRecord(pktrr, &rr->resrec)) break;
+ {
+ match = !pktrr->InterfaceID ? pktrr->rDNSServer == rr->resrec.rDNSServer : pktrr->InterfaceID == rr->resrec.InterfaceID;
+ if (match && IdenticalSameNameRecord(pktrr, &rr->resrec)) break;
+ }
return(rr);
}
+// Called from mDNSCoreReceiveUpdate when we get a sleep proxy registration request,
+// to check our lists and discard any stale duplicates of this record we already have
+mDNSlocal void ClearIdenticalProxyRecords(mDNS *const m, const OwnerOptData *const owner, AuthRecord *const thelist)
+ {
+ if (m->CurrentRecord)
+ LogMsg("ClearIdenticalProxyRecords ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
+ m->CurrentRecord = thelist;
+ while (m->CurrentRecord)
+ {
+ AuthRecord *const rr = m->CurrentRecord;
+ if (m->rec.r.resrec.InterfaceID == rr->resrec.InterfaceID && mDNSSameEthAddress(&owner->HMAC, &rr->WakeUp.HMAC))
+ if (IdenticalResourceRecord(&rr->resrec, &m->rec.r.resrec))
+ {
+ LogSPS("ClearIdenticalProxyRecords: Removing %3d H-MAC %.6a I-MAC %.6a %d %d %s",
+ m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, owner->seq, ARDisplayString(m, rr));
+ rr->WakeUp.HMAC = zeroEthAddr; // Clear HMAC so that mDNS_Deregister_internal doesn't waste packets trying to wake this host
+ rr->RequireGoodbye = mDNSfalse; // and we don't want to send goodbye for it
+ mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
+ SetSPSProxyListChanged(m->rec.r.resrec.InterfaceID);
+ }
+ // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because
+ // new records could have been added to the end of the list as a result of that call.
+ if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
+ m->CurrentRecord = rr->next;
+ }
+ }
+
// Called from ProcessQuery when we get an mDNS packet with an owner record in it
mDNSlocal void ClearProxyRecords(mDNS *const m, const OwnerOptData *const owner, AuthRecord *const thelist)
{
+ if (m->CurrentRecord)
+ LogMsg("ClearProxyRecords ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
m->CurrentRecord = thelist;
while (m->CurrentRecord)
{
@@ -5477,13 +4875,28 @@ mDNSlocal void ClearProxyRecords(mDNS *const m, const OwnerOptData *const owner,
if (m->rec.r.resrec.InterfaceID == rr->resrec.InterfaceID && mDNSSameEthAddress(&owner->HMAC, &rr->WakeUp.HMAC))
if (owner->seq != rr->WakeUp.seq || m->timenow - rr->TimeRcvd > mDNSPlatformOneSecond * 60)
{
- LogSPS("ClearProxyRecords: Removing %3d H-MAC %.6a I-MAC %.6a %d %d %s",
- m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, owner->seq, ARDisplayString(m, rr));
+ if (rr->AddressProxy.type == mDNSAddrType_IPv6)
+ {
+ // We don't do this here because we know that the host is waking up at this point, so we don't send
+ // Unsolicited Neighbor Advertisements -- even Neighbor Advertisements agreeing with what the host should be
+ // saying itself -- because it can cause some IPv6 stacks to falsely conclude that there's an address conflict.
+ #if MDNS_USE_Unsolicited_Neighbor_Advertisements
+ LogSPS("NDP Announcement -- Releasing traffic for H-MAC %.6a I-MAC %.6a %s",
+ &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m,rr));
+ SendNDP(m, NDP_Adv, NDP_Override, rr, &rr->AddressProxy.ip.v6, &rr->WakeUp.IMAC, &AllHosts_v6, &AllHosts_v6_Eth);
+ #endif
+ }
+ LogSPS("ClearProxyRecords: Removing %3d AC %2d %02X H-MAC %.6a I-MAC %.6a %d %d %s",
+ m->ProxyRecords, rr->AnnounceCount, rr->resrec.RecordType,
+ &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, owner->seq, ARDisplayString(m, rr));
+ if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) rr->resrec.RecordType = kDNSRecordTypeShared;
+ rr->WakeUp.HMAC = zeroEthAddr; // Clear HMAC so that mDNS_Deregister_internal doesn't waste packets trying to wake this host
+ rr->RequireGoodbye = mDNSfalse; // and we don't want to send goodbye for it, since real host is now back and functional
mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
SetSPSProxyListChanged(m->rec.r.resrec.InterfaceID);
}
- // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal,
- // because the list may have been changed in that call.
+ // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because
+ // new records could have been added to the end of the list as a result of that call.
if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
m->CurrentRecord = rr->next;
}
@@ -5494,7 +4907,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast,
mDNSBool QueryWasLocalUnicast, DNSMessage *const response)
{
- mDNSBool FromLocalSubnet = srcaddr && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
+ mDNSBool FromLocalSubnet = srcaddr && mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr);
AuthRecord *ResponseRecords = mDNSNULL;
AuthRecord **nrp = &ResponseRecords;
CacheRecord *ExpectedAnswers = mDNSNULL; // Records in our cache we expect to see updated
@@ -5515,7 +4928,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
if (ptr)
{
ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAdd, &m->rec);
- if (m->rec.r.resrec.rrtype == kDNSType_OPT)
+ if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_OPT)
{
const rdataOPT *opt;
const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
@@ -5600,10 +5013,10 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
else if (!rr->NR_AnswerTo) rr->NR_AnswerTo = LegacyQuery ? ptr : (mDNSu8*)~1;
}
}
- else if (rr->resrec.RecordType == kDNSRecordTypeVerified)
+ else if ((rr->resrec.RecordType & kDNSRecordTypeActiveUniqueMask) && ResourceRecordIsValidAnswer(rr))
{
// If we don't have any answers for this question, but we do own another record with the same name,
- // then mark it to generate an NSEC record on this interface
+ // then we'll want to mark it to generate an NSEC record on this interface
if (!NSECAnswer) NSECAnswer = rr;
}
}
@@ -5698,70 +5111,72 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
CacheRecord *ourcacherr;
ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &m->rec);
if (!ptr) goto exit;
-
- // See if this Known-Answer suppresses any of our currently planned answers
- for (rr=ResponseRecords; rr; rr=rr->NextResponse)
- if (MustSendRecord(rr) && ShouldSuppressKnownAnswer(&m->rec.r, rr))
- { rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
-
- // See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression)
- for (rr=m->ResourceRecords; rr; rr=rr->next)
+ if (m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative)
{
- // If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression
- if (rr->ImmedAnswer == InterfaceID && ShouldSuppressKnownAnswer(&m->rec.r, rr))
+ // See if this Known-Answer suppresses any of our currently planned answers
+ for (rr=ResponseRecords; rr; rr=rr->NextResponse)
+ if (MustSendRecord(rr) && ShouldSuppressKnownAnswer(&m->rec.r, rr))
+ { rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
+
+ // See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression)
+ for (rr=m->ResourceRecords; rr; rr=rr->next)
{
- if (srcaddr->type == mDNSAddrType_IPv4)
- {
- if (mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = zerov4Addr;
- }
- else if (srcaddr->type == mDNSAddrType_IPv6)
- {
- if (mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = zerov6Addr;
- }
- if (mDNSIPv4AddressIsZero(rr->v4Requester) && mDNSIPv6AddressIsZero(rr->v6Requester))
+ // If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression
+ if (rr->ImmedAnswer == InterfaceID && ShouldSuppressKnownAnswer(&m->rec.r, rr))
{
- rr->ImmedAnswer = mDNSNULL;
- rr->ImmedUnicast = mDNSfalse;
-#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
- LogMsg("Suppressed after%4d: %s", m->timenow - rr->ImmedAnswerMarkTime, ARDisplayString(m, rr));
-#endif
+ if (srcaddr->type == mDNSAddrType_IPv4)
+ {
+ if (mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = zerov4Addr;
+ }
+ else if (srcaddr->type == mDNSAddrType_IPv6)
+ {
+ if (mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = zerov6Addr;
+ }
+ if (mDNSIPv4AddressIsZero(rr->v4Requester) && mDNSIPv6AddressIsZero(rr->v6Requester))
+ {
+ rr->ImmedAnswer = mDNSNULL;
+ rr->ImmedUnicast = mDNSfalse;
+ #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
+ LogMsg("Suppressed after%4d: %s", m->timenow - rr->ImmedAnswerMarkTime, ARDisplayString(m, rr));
+ #endif
+ }
}
}
- }
-
- ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec);
-
-#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
- // See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always,
- // even if the TC bit is not set (the TC bit will *not* be set in the *last* packet of a multi-packet KA list).
- if (ourcacherr && ourcacherr->MPExpectingKA && m->timenow - ourcacherr->MPLastUnansweredQT < mDNSPlatformOneSecond)
- {
- ourcacherr->MPUnansweredKA++;
- ourcacherr->MPExpectingKA = mDNSfalse;
- }
-#endif
-
- // Having built our ExpectedAnswers list from the questions in this packet, we then remove
- // any records that are suppressed by the Known Answer list in this packet.
- eap = &ExpectedAnswers;
- while (*eap)
- {
- CacheRecord *cr = *eap;
- if (cr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &cr->resrec))
- { *eap = cr->NextInKAList; cr->NextInKAList = mDNSNULL; }
- else eap = &cr->NextInKAList;
- }
-
- // See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query.
- if (!ourcacherr)
- {
- dqp = &DupQuestions;
- while (*dqp)
+
+ ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec);
+
+ #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
+ // See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always,
+ // even if the TC bit is not set (the TC bit will *not* be set in the *last* packet of a multi-packet KA list).
+ if (ourcacherr && ourcacherr->MPExpectingKA && m->timenow - ourcacherr->MPLastUnansweredQT < mDNSPlatformOneSecond)
+ {
+ ourcacherr->MPUnansweredKA++;
+ ourcacherr->MPExpectingKA = mDNSfalse;
+ }
+ #endif
+
+ // Having built our ExpectedAnswers list from the questions in this packet, we then remove
+ // any records that are suppressed by the Known Answer list in this packet.
+ eap = &ExpectedAnswers;
+ while (*eap)
+ {
+ CacheRecord *cr = *eap;
+ if (cr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &cr->resrec))
+ { *eap = cr->NextInKAList; cr->NextInKAList = mDNSNULL; }
+ else eap = &cr->NextInKAList;
+ }
+
+ // See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query.
+ if (!ourcacherr)
{
- DNSQuestion *q = *dqp;
- if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
- { *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; }
- else dqp = &q->NextInDQList;
+ dqp = &DupQuestions;
+ while (*dqp)
+ {
+ DNSQuestion *q = *dqp;
+ if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
+ { *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; }
+ else dqp = &q->NextInDQList;
+ }
}
}
m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
@@ -5912,7 +5327,7 @@ exit:
debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s",
cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
#endif
- SetNextCacheCheckTime(m, cr);
+ SetNextCacheCheckTimeForRecord(m, cr);
}
// If we've seen multiple unanswered queries for this record,
@@ -5980,27 +5395,27 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg,
{
mDNSu8 *responseend = mDNSNULL;
mDNSBool QueryWasLocalUnicast = srcaddr && dstaddr &&
- !mDNSAddrIsDNSMulticast(dstaddr) && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
+ !mDNSAddrIsDNSMulticast(dstaddr) && mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr);
if (!InterfaceID && dstaddr && mDNSAddrIsDNSMulticast(dstaddr))
{
LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
- "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)",
+ "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes (Multicast, but no InterfaceID)",
srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
- msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
- msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
+ msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
+ msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,",
- msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
+ msg->h.numAdditionals, msg->h.numAdditionals == 1 ? " " : "s", end - msg->data);
return;
}
verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
- "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
+ "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes",
srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
- msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
- msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
+ msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
+ msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,",
- msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
+ msg->h.numAdditionals, msg->h.numAdditionals == 1 ? " " : "s", end - msg->data);
responseend = ProcessQuery(m, msg, end, srcaddr, InterfaceID,
!mDNSSameIPPort(srcport, MulticastDNSPort), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg);
@@ -6033,50 +5448,70 @@ struct UDPSocket_struct
mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
};
-mDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSIPPort port, const mDNSOpaque16 id, const DNSQuestion *const question)
+mDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSIPPort port, const mDNSOpaque16 id, const DNSQuestion *const question, mDNSBool tcp)
{
DNSQuestion *q;
for (q = m->Questions; q; q=q->next)
- if (q->LocalSocket &&
- mDNSSameIPPort (q->LocalSocket->port, port) &&
+ {
+ if (!tcp && !q->LocalSocket) continue;
+ if (mDNSSameIPPort(tcp ? q->tcpSrcPort : q->LocalSocket->port, port) &&
mDNSSameOpaque16(q->TargetQID, id) &&
q->qtype == question->qtype &&
q->qclass == question->qclass &&
q->qnamehash == question->qnamehash &&
SameDomainName(&q->qname, &question->qname))
return(q);
+ }
return(mDNSNULL);
}
-mDNSlocal mDNSBool ExpectingUnicastResponseForRecord(mDNS *const m, const mDNSAddr *const srcaddr, const mDNSBool SrcLocal, const mDNSIPPort port, const mDNSOpaque16 id, const CacheRecord *const rr)
+mDNSlocal DNSQuestion *ExpectingUnicastResponseForRecord(mDNS *const m,
+ const mDNSAddr *const srcaddr, const mDNSBool SrcLocal, const mDNSIPPort port, const mDNSOpaque16 id, const CacheRecord *const rr, mDNSBool tcp)
{
DNSQuestion *q;
(void)id;
(void)srcaddr;
+
+ // Unicast records have zero as InterfaceID
+ if (rr->resrec.InterfaceID) return mDNSNULL;
+
for (q = m->Questions; q; q=q->next)
- if (!q->DuplicateOf && ResourceRecordAnswersQuestion(&rr->resrec, q))
+ {
+ if (!q->DuplicateOf && UnicastResourceRecordAnswersQuestion(&rr->resrec, q))
{
if (!mDNSOpaque16IsZero(q->TargetQID))
{
debugf("ExpectingUnicastResponseForRecord msg->h.id %d q->TargetQID %d for %s", mDNSVal16(id), mDNSVal16(q->TargetQID), CRDisplayString(m, rr));
+
if (mDNSSameOpaque16(q->TargetQID, id))
{
- if (q->LocalSocket && mDNSSameIPPort(q->LocalSocket->port, port)) return(mDNStrue);
+ mDNSIPPort srcp;
+ if (!tcp)
+ {
+ srcp = q->LocalSocket ? q->LocalSocket->port : zeroIPPort;
+ }
+ else
+ {
+ srcp = q->tcpSrcPort;
+ }
+ if (mDNSSameIPPort(srcp, port)) return(q);
+
// if (mDNSSameAddress(srcaddr, &q->Target)) return(mDNStrue);
// if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking
// if (TrustedSource(m, srcaddr)) return(mDNStrue);
LogInfo("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a:%d] from %#a:%d %s",
- q->qname.c, DNSTypeName(q->qtype), &q->Target, mDNSVal16(q->LocalSocket ? q->LocalSocket->port : zeroIPPort), srcaddr, mDNSVal16(port), CRDisplayString(m, rr));
- return(mDNSfalse);
+ q->qname.c, DNSTypeName(q->qtype), &q->Target, mDNSVal16(srcp), srcaddr, mDNSVal16(port), CRDisplayString(m, rr));
+ return(mDNSNULL);
}
}
else
{
if (SrcLocal && q->ExpectUnicastResp && (mDNSu32)(m->timenow - q->ExpectUnicastResp) < (mDNSu32)(mDNSPlatformOneSecond*2))
- return(mDNStrue);
+ return(q);
}
}
- return(mDNSfalse);
+ }
+ return(mDNSNULL);
}
// Certain data types need more space for in-memory storage than their in-packet rdlength would imply
@@ -6095,7 +5530,7 @@ mDNSlocal mDNSu16 GetRDLengthMem(const ResourceRecord *const rr)
}
}
-mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg)
+mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg, mDNSs32 delay)
{
CacheRecord *rr = mDNSNULL;
mDNSu16 RDLength = GetRDLengthMem(&m->rec.r.resrec);
@@ -6112,8 +5547,9 @@ mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, C
{
RData *saveptr = rr->resrec.rdata; // Save the rr->resrec.rdata pointer
*rr = m->rec.r; // Block copy the CacheRecord object
- rr->resrec.rdata = saveptr; // Restore rr->resrec.rdata after the structure assignment
- rr->resrec.name = cg->name; // And set rr->resrec.name to point into our CacheGroup header
+ rr->resrec.rdata = saveptr; // Restore rr->resrec.rdata after the structure assignment
+ rr->resrec.name = cg->name; // And set rr->resrec.name to point into our CacheGroup header
+ rr->DelayDelivery = delay;
// If this is an oversized record with external storage allocated, copy rdata to external storage
if (rr->resrec.rdata == (RData*)&rr->smallrdatastorage && RDLength > InlineCacheRDSize)
@@ -6126,15 +5562,8 @@ mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, C
rr->next = mDNSNULL; // Clear 'next' pointer
*(cg->rrcache_tail) = rr; // Append this record to tail of cache slot list
cg->rrcache_tail = &(rr->next); // Advance tail pointer
- if (rr->resrec.RecordType == kDNSRecordTypePacketNegative)
- rr->DelayDelivery = NonZeroTime(m->timenow);
- else if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask && // If marked unique,
- rr->resrec.rdata->MaxRDLength != 0) // and non-negative, assume we may have
- rr->DelayDelivery = NonZeroTime(m->timenow + mDNSPlatformOneSecond); // to delay delivery of this 'add' event
- else
- rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot);
- CacheRecordAdd(m, rr); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
+ CacheRecordAdd(m, rr); // CacheRecordAdd calls SetNextCacheCheckTimeForRecord(m, rr); for us
}
return(rr);
}
@@ -6149,7 +5578,7 @@ mDNSlocal void RefreshCacheRecord(mDNS *const m, CacheRecord *rr, mDNSu32 ttl)
rr->MPUnansweredKA = 0;
rr->MPExpectingKA = mDNSfalse;
#endif
- SetNextCacheCheckTime(m, rr);
+ SetNextCacheCheckTimeForRecord(m, rr);
}
mDNSexport void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease)
@@ -6177,8 +5606,8 @@ mDNSlocal mDNSu32 GetEffectiveTTL(const uDNS_LLQType LLQType, mDNSu32 ttl) // T
else // else not LLQ (standard uDNS response)
{
// The TTL is already capped to a maximum value in GetLargeResourceRecord, but just to be extra safe we
- // also do this check here to make sure we can't get integer overflow below
- if (ttl > 0x8000000UL) ttl = 0x8000000UL;
+ // also do this check here to make sure we can't get overflow below when we add a quarter to the TTL
+ if (ttl > 0x60000000UL / mDNSPlatformOneSecond) ttl = 0x60000000UL / mDNSPlatformOneSecond;
// Adjustment factor to avoid race condition:
// Suppose real record as TTL of 3600, and our local caching server has held it for 3500 seconds, so it returns an aged TTL of 100.
@@ -6193,7 +5622,14 @@ mDNSlocal mDNSu32 GetEffectiveTTL(const uDNS_LLQType LLQType, mDNSu32 ttl) // T
// For mDNS, TTL zero means "delete this record"
// For uDNS, TTL zero means: this data is true at this moment, but don't cache it.
// For the sake of network efficiency, we impose a minimum effective TTL of 15 seconds.
- // If we allow a TTL of less than 2 seconds things really break (e.g. we end up making a negative cache entry).
+ // This means that we'll do our 80, 85, 90, 95% queries at 12.00, 12.75, 13.50, 14.25 seconds
+ // respectively, and then if we get no response, delete the record from the cache at 15 seconds.
+ // This gives the server up to three seconds to respond between when we send our 80% query at 12 seconds
+ // and when we delete the record at 15 seconds. Allowing cache lifetimes less than 15 seconds would
+ // (with the current code) result in the server having even less than three seconds to respond
+ // before we deleted the record and reported a "remove" event to any active questions.
+ // Furthermore, with the current code, if we were to allow a TTL of less than 2 seconds
+ // then things really break (e.g. we end up making a negative cache entry).
// In the future we may want to revisit this and consider properly supporting non-cached (TTL=0) uDNS answers.
if (ttl < 15) ttl = 15;
}
@@ -6214,8 +5650,9 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
{
int i;
mDNSBool ResponseMCast = dstaddr && mDNSAddrIsDNSMulticast(dstaddr);
- mDNSBool ResponseSrcLocal = !srcaddr || AddressIsLocalSubnet(m, InterfaceID, srcaddr);
- uDNS_LLQType LLQType = uDNS_recvLLQResponse(m, response, end, srcaddr, srcport);
+ mDNSBool ResponseSrcLocal = !srcaddr || mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr);
+ DNSQuestion *llqMatch = mDNSNULL;
+ uDNS_LLQType LLQType = uDNS_recvLLQResponse(m, response, end, srcaddr, srcport, &llqMatch);
// "(CacheRecord*)1" is a special (non-zero) end-of-list marker
// We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
@@ -6230,14 +5667,15 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
int firstadditional = firstauthority + response->h.numAuthorities;
int totalrecords = firstadditional + response->h.numAdditionals;
const mDNSu8 *ptr = response->data;
+ DNSServer *uDNSServer = mDNSNULL;
debugf("Received Response from %#-15a addressed to %#-15a on %p with "
- "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s LLQType %d",
+ "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes LLQType %d",
srcaddr, dstaddr, InterfaceID,
- response->h.numQuestions, response->h.numQuestions == 1 ? ", " : "s,",
- response->h.numAnswers, response->h.numAnswers == 1 ? ", " : "s,",
+ response->h.numQuestions, response->h.numQuestions == 1 ? ", " : "s,",
+ response->h.numAnswers, response->h.numAnswers == 1 ? ", " : "s,",
response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,",
- response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s", LLQType);
+ response->h.numAdditionals, response->h.numAdditionals == 1 ? " " : "s", end - response->data, LLQType);
// According to RFC 2181 <http://www.ietf.org/rfc/rfc2181.txt>
// When a DNS client receives a reply with TC
@@ -6281,7 +5719,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
{
DNSQuestion q, *qptr = mDNSNULL;
ptr = getQuestion(response, ptr, end, InterfaceID, &q);
- if (ptr && (!dstaddr || (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q))))
+ if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr)))
{
if (!failure)
{
@@ -6289,7 +5727,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
const mDNSu32 slot = HashSlot(&q.qname);
CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname);
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
- if (q.InterfaceID == rr->resrec.InterfaceID && SameNameRecordAnswersQuestion(&rr->resrec, &q))
+ if (SameNameRecordAnswersQuestion(&rr->resrec, qptr))
{
debugf("uDNS marking %p %##s (%s) %p %s", q.InterfaceID, q.qname.c, DNSTypeName(q.qtype),
rr->resrec.InterfaceID, CRDisplayString(m, rr));
@@ -6302,8 +5740,8 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
{
if (qptr)
{
- LogInfo("Server %p responded with code %d to query %##s (%s)", qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype));
- PushDNSServerToEnd(m, qptr);
+ LogInfo("mDNSCoreReceiveResponse: Server %p responded with code %d to query %##s (%s)", qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype));
+ PenalizeDNSServer(m, qptr);
}
returnEarly = mDNStrue;
}
@@ -6334,11 +5772,34 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
(i < firstadditional) ? (mDNSu8)kDNSRecordTypePacketAuth : (mDNSu8)kDNSRecordTypePacketAdd;
ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, RecordType, &m->rec);
if (!ptr) goto exit; // Break out of the loop and clean up our CacheFlushRecords list before exiting
+ if (m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative) { m->rec.r.resrec.RecordType = 0; continue; }
// Don't want to cache OPT or TSIG pseudo-RRs
- if (m->rec.r.resrec.rrtype == kDNSType_OPT || m->rec.r.resrec.rrtype == kDNSType_TSIG)
- { m->rec.r.resrec.RecordType = 0; continue; }
-
+ if (m->rec.r.resrec.rrtype == kDNSType_TSIG) { m->rec.r.resrec.RecordType = 0; continue; }
+ if (m->rec.r.resrec.rrtype == kDNSType_OPT)
+ {
+ const rdataOPT *opt;
+ const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
+ // Find owner sub-option(s). We verify that the MAC is non-zero, otherwise we could inadvertently
+ // delete all our own AuthRecords (which are identified by having zero MAC tags on them).
+ for (opt = &m->rec.r.resrec.rdata->u.opt[0]; opt < e; opt++)
+ if (opt->opt == kDNSOpt_Owner && opt->u.owner.vers == 0 && opt->u.owner.HMAC.l[0])
+ {
+ ClearProxyRecords(m, &opt->u.owner, m->DuplicateRecords);
+ ClearProxyRecords(m, &opt->u.owner, m->ResourceRecords);
+ }
+ m->rec.r.resrec.RecordType = 0;
+ continue;
+ }
+
+ // if a CNAME record points to itself, then don't add it to the cache
+ if ((m->rec.r.resrec.rrtype == kDNSType_CNAME) && SameDomainName(m->rec.r.resrec.name, &m->rec.r.resrec.rdata->u.name))
+ {
+ LogInfo("mDNSCoreReceiveResponse: CNAME loop domain name %##s", m->rec.r.resrec.name->c);
+ m->rec.r.resrec.RecordType = 0;
+ continue;
+ }
+
// When we receive uDNS LLQ responses, we assume a long cache lifetime --
// In the case of active LLQs, we'll get remove events when the records actually do go away
// In the case of polling LLQs, we assume the record remains valid until the next poll
@@ -6347,7 +5808,57 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// If response was not sent via LL multicast,
// then see if it answers a recent query of ours, which would also make it acceptable for caching.
- if (!AcceptableResponse) AcceptableResponse = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, dstport, response->h.id, &m->rec.r);
+ if (!ResponseMCast)
+ {
+ if (LLQType)
+ {
+ // For Long Lived queries that are both sent over UDP and Private TCP, LLQType is set.
+ // Even though it is AcceptableResponse, we need a matching DNSServer pointer for the
+ // queries to get ADD/RMV events. To lookup the question, we can't use
+ // ExpectingUnicastResponseForRecord as the port numbers don't match. uDNS_recvLLQRespose
+ // has already matched the question using the 64 bit Id in the packet and we use that here.
+
+ if (llqMatch != mDNSNULL) m->rec.r.resrec.rDNSServer = uDNSServer = llqMatch->qDNSServer;
+ }
+ else if (!AcceptableResponse || !dstaddr)
+ {
+ // For responses that come over TCP (Responses that can't fit within UDP) or TLS (Private queries
+ // that are not long lived e.g., AAAA lookup in a Private domain), it is indicated by !dstaddr.
+ // Even though it is AcceptableResponse, we still need a DNSServer pointer for the resource records that
+ // we create.
+
+ DNSQuestion *q = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, dstport, response->h.id, &m->rec.r, !dstaddr);
+
+ // Intialize the DNS server on the resource record which will now filter what questions we answer with
+ // this record.
+ //
+ // We could potentially lookup the DNS server based on the source address, but that may not work always
+ // and that's why ExpectingUnicastResponseForRecord does not try to verify whether the response came
+ // from the DNS server that queried. We follow the same logic here. If we can find a matching quetion based
+ // on the "id" and "source port", then this response answers the question and assume the response
+ // came from the same DNS server that we sent the query to.
+
+ if (q != mDNSNULL)
+ {
+ AcceptableResponse = mDNStrue;
+ if (!InterfaceID)
+ {
+ debugf("mDNSCoreReceiveResponse: InterfaceID %p %##s (%s)", q->InterfaceID, q->qname.c, DNSTypeName(q->qtype));
+ m->rec.r.resrec.rDNSServer = uDNSServer = q->qDNSServer;
+ }
+ }
+ else
+ {
+ // If we can't find a matching question, we need to see whether we have seen records earlier that matched
+ // the question. The code below does that. So, make this record unacceptable for now
+ if (!InterfaceID)
+ {
+ debugf("mDNSCoreReceiveResponse: Can't find question for record name %##s", m->rec.r.resrec.name->c);
+ AcceptableResponse = mDNSfalse;
+ }
+ }
+ }
+ }
// 1. Check that this packet resource record does not conflict with any of ours
if (mDNSOpaque16IsZero(response->h.id) && m->rec.r.resrec.rrtype != kDNSType_NSEC)
@@ -6451,15 +5962,26 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
for (cr = CacheFlushRecords; cr != (CacheRecord*)1; cr = cr->NextInCFList)
{
domainname *target = GetRRDomainNameTarget(&cr->resrec);
+ // When we issue a query for A record, the response might contain both a CNAME and A records. Only the CNAME would
+ // match the question and we already created a cache entry in the previous pass of this loop. Now when we process
+ // the A record, it does not match the question because the record name here is the CNAME. Hence we try to
+ // match with the previous records to make it an AcceptableResponse. We have to be careful about setting the
+ // DNSServer value that we got in the previous pass. This can happen for other record types like SRV also.
+
if (target && cr->resrec.rdatahash == m->rec.r.resrec.namehash && SameDomainName(target, m->rec.r.resrec.name))
- { AcceptableResponse = mDNStrue; break; }
+ {
+ debugf("mDNSCoreReceiveResponse: Found a matching entry for %##s in the CacheFlushRecords", m->rec.r.resrec.name->c);
+ AcceptableResponse = mDNStrue;
+ m->rec.r.resrec.rDNSServer = uDNSServer;
+ break;
+ }
}
}
// 2. See if we want to add this packet resource record to our cache
// We only try to cache answers if we have a cache to put them in
// Also, we ignore any apparent attempts at cache poisoning unicast to us that do not answer any outstanding active query
- if (!AcceptableResponse) debugf("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m, &m->rec.r));
+ if (!AcceptableResponse) LogInfo("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m, &m->rec.r));
if (m->rrcache_size && AcceptableResponse)
{
const mDNSu32 slot = HashSlot(m->rec.r.resrec.name);
@@ -6469,13 +5991,13 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// 2a. Check if this packet resource record is already in our cache
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
{
+ mDNSBool match = !InterfaceID ? m->rec.r.resrec.rDNSServer == rr->resrec.rDNSServer : rr->resrec.InterfaceID == InterfaceID;
// If we found this exact resource record, refresh its TTL
- if (rr->resrec.InterfaceID == InterfaceID && IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec))
+ if (match && IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec))
{
if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
verbosedebugf("Found record size %5d interface %p already in cache: %s",
m->rec.r.resrec.rdlength, InterfaceID, CRDisplayString(m, &m->rec.r));
- rr->TimeRcvd = m->timenow;
if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask)
{
@@ -6492,20 +6014,54 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
}
}
- if (!mDNSPlatformMemSame(m->rec.r.resrec.rdata->u.data, rr->resrec.rdata->u.data, m->rec.r.resrec.rdlength))
+ if (!SameRDataBody(&m->rec.r.resrec, &rr->resrec.rdata->u, SameDomainNameCS))
{
// If the rdata of the packet record differs in name capitalization from the record in our cache
// then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get
// a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one.
+ // <rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
rr->resrec.rroriginalttl = 0;
+ rr->TimeRcvd = m->timenow;
rr->UnansweredQueries = MaxUnansweredQueries;
- SetNextCacheCheckTime(m, rr);
+ SetNextCacheCheckTimeForRecord(m, rr);
+ LogInfo("Discarding due to domainname case change old: %s", CRDisplayString(m,rr));
+ LogInfo("Discarding due to domainname case change new: %s", CRDisplayString(m,&m->rec.r));
+ LogInfo("Discarding due to domainname case change in %d slot %3d in %d %d",
+ NextCacheCheckEvent(rr) - m->timenow, slot, m->rrcache_nextcheck[slot] - m->timenow, m->NextCacheCheck - m->timenow);
// DO NOT break out here -- we want to continue as if we never found it
}
else if (m->rec.r.resrec.rroriginalttl > 0)
{
+ DNSQuestion *q;
//if (rr->resrec.rroriginalttl == 0) LogMsg("uDNS rescuing %s", CRDisplayString(m, rr));
RefreshCacheRecord(m, rr, m->rec.r.resrec.rroriginalttl);
+
+ // We have to reset the question interval to MaxQuestionInterval so that we don't keep
+ // polling the network once we get a valid response back. For the first time when a new
+ // cache entry is created, AnswerCurrentQuestionWithResourceRecord does that.
+ // Subsequently, if we reissue questions from within the mDNSResponder e.g., DNS server
+ // configuration changed, without flushing the cache, we reset the question interval here.
+ // Currently, we do this for for both multicast and unicast questions as long as the record
+ // type is unique. For unicast, resource record is always unique and for multicast it is
+ // true for records like A etc. but not for PTR.
+ if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)
+ {
+ for (q = m->Questions; q; q=q->next)
+ {
+ if (!q->DuplicateOf && !q->LongLived &&
+ ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
+ {
+ q->LastQTime = m->timenow;
+ q->LastQTxTime = m->timenow;
+ q->RecentAnswerPkts = 0;
+ q->ThisQInterval = MaxQuestionInterval;
+ q->RequestUnicast = mDNSfalse;
+ q->unansweredQueries = 0;
+ debugf("mDNSCoreReceiveResponse: Set MaxQuestionInterval for %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+ break; // Why break here? Aren't there other questions we might want to look at?-- SC July 2010
+ }
+ }
+ }
break;
}
else
@@ -6515,10 +6071,17 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries.
// Otherwise, we'll do final queries for this record at 80% and 90% of its apparent
// lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth.
+ // If record's current expiry time is more than a second from now, we set it to expire in one second.
+ // If the record is already going to expire in less than one second anyway, we leave it alone --
+ // we don't want to let the goodbye packet *extend* the record's lifetime in our cache.
debugf("DE for %s", CRDisplayString(m, rr));
- rr->resrec.rroriginalttl = 1;
- rr->UnansweredQueries = MaxUnansweredQueries;
- SetNextCacheCheckTime(m, rr);
+ if (RRExpireTime(rr) - m->timenow > mDNSPlatformOneSecond)
+ {
+ rr->resrec.rroriginalttl = 1;
+ rr->TimeRcvd = m->timenow;
+ rr->UnansweredQueries = MaxUnansweredQueries;
+ SetNextCacheCheckTimeForRecord(m, rr);
+ }
break;
}
}
@@ -6528,9 +6091,19 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// (unless it is just a deletion of a record we never had, in which case we don't care)
if (!rr && m->rec.r.resrec.rroriginalttl > 0)
{
- rr = CreateNewCacheEntry(m, slot, cg);
- if (rr && (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) && LLQType != uDNS_LLQ_Events)
- { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
+ const mDNSBool AddToCFList = (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && (LLQType != uDNS_LLQ_Events);
+ const mDNSs32 delay = AddToCFList ? NonZeroTime(m->timenow + mDNSPlatformOneSecond) :
+ CheckForSoonToExpireRecords(m, m->rec.r.resrec.name, m->rec.r.resrec.namehash, slot);
+ // If unique, assume we may have to delay delivery of this 'add' event.
+ // Below, where we walk the CacheFlushRecords list, we either call CacheRecordDeferredAdd()
+ // to immediately to generate answer callbacks, or we call ScheduleNextCacheCheckTime()
+ // to schedule an mDNS_Execute task at the appropriate time.
+ rr = CreateNewCacheEntry(m, slot, cg, delay);
+ if (rr)
+ {
+ if (AddToCFList) { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
+ else if (rr->DelayDelivery) ScheduleNextCacheCheckTime(m, slot, rr->DelayDelivery);
+ }
}
}
m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
@@ -6563,7 +6136,9 @@ exit:
// To avoid this, we need to ensure that the cache flushing operation will only act to
// *decrease* a record's remaining lifetime, never *increase* it.
for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next)
- if (r1->resrec.InterfaceID == r2->resrec.InterfaceID &&
+ // For Unicast (null InterfaceID) the DNSservers should also match
+ if ((r1->resrec.InterfaceID == r2->resrec.InterfaceID) &&
+ (r1->resrec.InterfaceID || (r1->resrec.rDNSServer == r2->resrec.rDNSServer)) &&
r1->resrec.rrtype == r2->resrec.rrtype &&
r1->resrec.rrclass == r2->resrec.rrclass)
{
@@ -6573,7 +6148,7 @@ exit:
{
// If we find mismatched TTLs in an RRSet, correct them.
// We only do this for records with a TTL of 2 or higher. It's possible to have a
- // goodbye announcement with the cache flush bit set (or a case change on record rdata,
+ // goodbye announcement with the cache flush bit set (or a case-change on record rdata,
// which we treat as a goodbye followed by an addition) and in that case it would be
// inappropriate to synchronize all the other records to a TTL of 0 (or 1).
// We suppress the message for the specific case of correcting from 240 to 60 for type TXT,
@@ -6594,7 +6169,8 @@ exit:
}
else // else, if record is old, mark it to be flushed
{
- verbosedebugf("Cache flush %p X %p %s", r1, r2, CRDisplayString(m, r2));
+ verbosedebugf("Cache flush new %p age %d expire in %d %s", r1, m->timenow - r1->TimeRcvd, RRExpireTime(r1) - m->timenow, CRDisplayString(m, r1));
+ verbosedebugf("Cache flush old %p age %d expire in %d %s", r2, m->timenow - r2->TimeRcvd, RRExpireTime(r2) - m->timenow, CRDisplayString(m, r2));
// We set stale records to expire in one second.
// This gives the owner a chance to rescue it if necessary.
// This is important in the case of multi-homing and bridged networks:
@@ -6611,12 +6187,13 @@ exit:
// If a record is deleted twice, first with an explicit DE record, then a second time by virtue of the cache
// flush bit on the new record replacing it, then we allow the record to be deleted immediately, without the usual
// one-second grace period. This improves responsiveness for mDNS_Update(), as used for things like iChat status updates.
- if (r2->TimeRcvd == m->timenow && r2->resrec.rroriginalttl <= 1 && r2->UnansweredQueries == MaxUnansweredQueries)
+ // <rdar://problem/5636422> Updating TXT records is too slow
+ // We check for "rroriginalttl == 1" because we want to include records tagged by the "packet TTL is zero" check above,
+ // which sets rroriginalttl to 1, but not records tagged by the rdata case-change check, which sets rroriginalttl to 0.
+ if (r2->TimeRcvd == m->timenow && r2->resrec.rroriginalttl == 1 && r2->UnansweredQueries == MaxUnansweredQueries)
{
- debugf("Cache flush for DE record %s", CRDisplayString(m, r2));
+ LogInfo("Cache flush for DE record %s", CRDisplayString(m, r2));
r2->resrec.rroriginalttl = 0;
- m->NextCacheCheck = m->timenow;
- m->NextScheduledEvent = m->timenow;
}
else if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
{
@@ -6629,13 +6206,15 @@ exit:
// that we marked for deletion via an explicit DE record
}
}
- SetNextCacheCheckTime(m, r2);
+ SetNextCacheCheckTimeForRecord(m, r2);
}
+
if (r1->DelayDelivery) // If we were planning to delay delivery of this record, see if we still need to
{
- // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, slot);
+ // If no longer delaying, deliver answer now, else schedule delivery for the appropriate time
if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1);
+ else ScheduleNextCacheCheckTime(m, slot, r1->DelayDelivery);
}
}
@@ -6644,8 +6223,9 @@ exit:
for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++)
{
DNSQuestion q;
+ DNSQuestion *qptr = mDNSNULL;
ptr = getQuestion(response, ptr, end, InterfaceID, &q);
- if (ptr && (!dstaddr || ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q)))
+ if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr)))
{
// When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft
// Active Directory sites) we don't want to waste memory making negative cache entries for all the unicast answers.
@@ -6658,17 +6238,17 @@ exit:
// in conflict with the mDNS spec, because that spec says, "Multicast DNS Zones have no SOA record," so it's okay to cache
// negative answers for "local. SOA" from a uDNS server, because the mDNS spec already says that such records do not exist :-)
if (!InterfaceID && q.qtype != kDNSType_SOA && IsLocalDomain(&q.qname))
- LogInfo("Not generating negative cache entry for %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
+ LogInfo("Skipping check to see if we need to generate a negative cache entry for %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
else
{
CacheRecord *rr, *neg = mDNSNULL;
mDNSu32 slot = HashSlot(&q.qname);
CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname);
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
- if (SameNameRecordAnswersQuestion(&rr->resrec, &q))
+ if (SameNameRecordAnswersQuestion(&rr->resrec, qptr))
{
// 1. If we got a fresh answer to this query, then don't need to generate a negative entry
- if (rr->TimeRcvd + TicksTTL(rr) - m->timenow > 0) break;
+ if (RRExpireTime(rr) - m->timenow > 0) break;
// 2. If we already had a negative entry, keep track of it so we can resurrect it instead of creating a new one
if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) neg = rr;
}
@@ -6694,7 +6274,7 @@ exit:
if (response->h.numAuthorities && (ptr = LocateAuthorities(response, end)) != mDNSNULL)
{
ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
- if (ptr && m->rec.r.resrec.rrtype == kDNSType_SOA)
+ if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_SOA)
{
const rdataSOA *const soa = (const rdataSOA *)m->rec.r.resrec.rdata->u.data;
mDNSu32 ttl_s = soa->min;
@@ -6746,8 +6326,8 @@ exit:
else while (1)
{
debugf("mDNSCoreReceiveResponse making negative cache entry TTL %d for %##s (%s)", negttl, name->c, DNSTypeName(q.qtype));
- MakeNegativeCacheRecord(m, &m->rec.r, name, hash, q.qtype, q.qclass, negttl, mDNSInterface_Any);
- CreateNewCacheEntry(m, slot, cg);
+ MakeNegativeCacheRecord(m, &m->rec.r, name, hash, q.qtype, q.qclass, negttl, mDNSInterface_Any, qptr->qDNSServer);
+ CreateNewCacheEntry(m, slot, cg, 0); // We never need any delivery delay for these generated negative cache records
m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
if (!repeat) break;
repeat--;
@@ -6762,6 +6342,20 @@ exit:
}
}
+mDNSlocal void ScheduleWakeupForList(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *e, AuthRecord *const thelist)
+ {
+ AuthRecord *rr;
+ for (rr = thelist; rr; rr=rr->next)
+ if (rr->resrec.InterfaceID == InterfaceID && rr->resrec.RecordType != kDNSRecordTypeDeregistering && mDNSSameEthAddress(&rr->WakeUp.HMAC, e))
+ mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
+ }
+
+mDNSlocal void ScheduleWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *e)
+ {
+ ScheduleWakeupForList(m, InterfaceID, e, m->DuplicateRecords);
+ ScheduleWakeupForList(m, InterfaceID, e, m->ResourceRecords);
+ }
+
mDNSlocal void SPSRecordCallback(mDNS *const m, AuthRecord *const ar, mStatus result)
{
if (result && result != mStatus_MemFree)
@@ -6769,14 +6363,15 @@ mDNSlocal void SPSRecordCallback(mDNS *const m, AuthRecord *const ar, mStatus re
if (result == mStatus_NameConflict)
{
- LogMsg("Received Conflicting mDNS -- waking %s %.6a %s",
- InterfaceNameForID(m, ar->resrec.InterfaceID), &ar->WakeUp.HMAC, ARDisplayString(m, ar));
+ LogMsg("Received Conflicting mDNS -- waking %s %.6a %s", InterfaceNameForID(m, ar->resrec.InterfaceID), &ar->WakeUp.HMAC, ARDisplayString(m, ar));
SendWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.IMAC, &ar->WakeUp.password);
+ ScheduleWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.HMAC);
}
else if (result == mStatus_MemFree)
{
m->ProxyRecords--;
mDNSPlatformMemFree(ar);
+ mDNS_UpdateAllowSleep(m);
}
}
@@ -6788,17 +6383,17 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
int i;
AuthRecord opt;
mDNSu8 *p = m->omsg.data;
- OwnerOptData owner;
+ OwnerOptData owner = zeroOwner; // Need to zero this, so we'll know if this Update packet was missing its Owner option
mDNSu32 updatelease = 0;
const mDNSu8 *ptr;
LogSPS("Received Update from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
- "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
+ "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes",
srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
- msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
- msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
+ msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
+ msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,",
- msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
+ msg->h.numAdditionals, msg->h.numAdditionals == 1 ? " " : "s", end - msg->data);
if (!InterfaceID || !m->SPSSocket || !mDNSSameIPPort(dstport, m->SPSSocket->port)) return;
@@ -6809,7 +6404,7 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
if (ptr)
{
ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
- if (ptr && m->rec.r.resrec.rrtype == kDNSType_OPT)
+ if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_OPT)
{
const rdataOPT *o;
const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
@@ -6860,7 +6455,7 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
for (i = 0; i < msg->h.mDNS_numUpdates && ptr && ptr < end; i++)
{
ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
- if (ptr)
+ if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative)
{
mDNSu16 RDLengthMem = GetRDLengthMem(&m->rec.r.resrec);
AuthRecord *ar = mDNSPlatformMemAllocate(sizeof(AuthRecord) - sizeof(RDataBody) + RDLengthMem);
@@ -6869,12 +6464,15 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
{
mDNSu8 RecordType = m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask ? kDNSRecordTypeUnique : kDNSRecordTypeShared;
m->rec.r.resrec.rrclass &= ~kDNSClass_UniqueRRSet;
+ ClearIdenticalProxyRecords(m, &owner, m->DuplicateRecords); // Make sure we don't have any old stale duplicates of this record
+ ClearIdenticalProxyRecords(m, &owner, m->ResourceRecords);
mDNS_SetupResourceRecord(ar, mDNSNULL, InterfaceID, m->rec.r.resrec.rrtype, m->rec.r.resrec.rroriginalttl, RecordType, SPSRecordCallback, ar);
AssignDomainName(&ar->namestorage, m->rec.r.resrec.name);
ar->resrec.rdlength = GetRDLength(&m->rec.r.resrec, mDNSfalse);
ar->resrec.rdata->MaxRDLength = RDLengthMem;
mDNSPlatformMemCopy(ar->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, RDLengthMem);
- ar->WakeUp = owner;
+ ar->ForceMCast = mDNStrue;
+ ar->WakeUp = owner;
if (m->rec.r.resrec.rrtype == kDNSType_PTR)
{
mDNSs32 t = ReverseMapDomainType(m->rec.r.resrec.name);
@@ -6888,9 +6486,15 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
if (m->NextScheduledSPS - ar->TimeExpire > 0)
m->NextScheduledSPS = ar->TimeExpire;
mDNS_Register_internal(m, ar);
- // For now, since we don't get IPv6 ND or data packets, we don't advertise AAAA records for our SPS clients
- if (ar->resrec.rrtype == kDNSType_AAAA) ar->resrec.rroriginalttl = 0;
+ // Unsolicited Neighbor Advertisements (RFC 2461 Section 7.2.6) give us fast address cache updating,
+ // but some older IPv6 clients get confused by them, so for now we don't send them. Without Unsolicited
+ // Neighbor Advertisements we have to rely on Neighbor Unreachability Detection instead, which is slower.
+ // Given this, we'll do our best to wake for existing IPv6 connections, but we don't want to encourage
+ // new ones for sleeping clients, so we'll we send deletions for our SPS clients' AAAA records.
+ if (m->KnownBugs & mDNS_KnownBug_LimitedIPv6)
+ if (ar->resrec.rrtype == kDNSType_AAAA) ar->resrec.rroriginalttl = 0;
m->ProxyRecords++;
+ mDNS_UpdateAllowSleep(m);
LogSPS("SPS Registered %4d %X %s", m->ProxyRecords, RecordType, ARDisplayString(m,ar));
}
}
@@ -6928,7 +6532,7 @@ mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg
if (ptr)
{
ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
- if (ptr && m->rec.r.resrec.rrtype == kDNSType_OPT)
+ if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_OPT)
{
const rdataOPT *o;
const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
@@ -6958,7 +6562,7 @@ mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg
}
mDNSexport void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr,
- const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds, mDNSInterfaceID InterfaceID)
+ const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds, mDNSInterfaceID InterfaceID, DNSServer *dnsserver)
{
if (cr == &m->rec.r && m->rec.r.resrec.RecordType)
{
@@ -6971,6 +6575,7 @@ mDNSexport void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr,
// Create empty resource record
cr->resrec.RecordType = kDNSRecordTypePacketNegative;
cr->resrec.InterfaceID = InterfaceID;
+ cr->resrec.rDNSServer = dnsserver;
cr->resrec.name = name; // Will be updated to point to cg->name when we call CreateNewCacheEntry
cr->resrec.rrtype = rrtype;
cr->resrec.rrclass = rrclass;
@@ -7039,7 +6644,11 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co
#endif
#endif
- if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) { LogMsg("DNS Message too short"); return; }
+ if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader))
+ {
+ LogMsg("DNS Message from %#a:%d to %#a:%d length %d too short", srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end - (mDNSu8 *)pkt);
+ return;
+ }
QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
// Read the integer parts which are in IETF byte-order (MSB first, LSB second)
ptr = (mDNSu8 *)&msg->h.numQuestions;
@@ -7074,15 +6683,15 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co
else
{
LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d length %d on %p (ignored)",
- msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end-(mDNSu8 *)pkt, InterfaceID);
+ msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end - (mDNSu8 *)pkt, InterfaceID);
if (mDNS_LoggingEnabled)
{
int i = 0;
- while (i<end-(mDNSu8 *)pkt)
+ while (i<end - (mDNSu8 *)pkt)
{
char buffer[128];
char *p = buffer + mDNS_snprintf(buffer, sizeof(buffer), "%04X", i);
- do if (i<end-(mDNSu8 *)pkt) p += mDNS_snprintf(p, sizeof(buffer), " %02X", ((mDNSu8 *)pkt)[i]); while (++i & 15);
+ do if (i<end - (mDNSu8 *)pkt) p += mDNS_snprintf(p, sizeof(buffer), " %02X", ((mDNSu8 *)pkt)[i]); while (++i & 15);
LogInfo("%s", buffer);
}
}
@@ -7112,6 +6721,14 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co
// and we have a key for company.com, so we try to locate the private query server for company.com, which necessarily entails
// doing a standard DNS query for the _dns-query-tls._tcp SRV record for company.com. If we make the latter (public) query
// a duplicate of the former (private) query, then it will block forever waiting for an answer that will never come.
+//
+// We keep SuppressUnusable questions separate so that we can return a quick response to them and not get blocked behind
+// the queries that are not marked SuppressUnusable. But if the query is not suppressed, they are treated the same as
+// non-SuppressUnusable questions. This should be fine as the goal of SuppressUnusable is to return quickly only if it
+// is suppressed. If it is not suppressed, we do try all the DNS servers for valid answers like any other question.
+// The main reason for this design is that cache entries point to a *single* question and that question is responsible
+// for keeping the cache fresh as long as it is active. Having multiple active question for a single cache entry
+// breaks this design principle.
// If IsLLQ(Q) is true, it means the question is both:
// (a) long-lived and
@@ -7133,6 +6750,7 @@ mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuest
q->qclass == question->qclass && // class,
IsLLQ(q) == IsLLQ(question) && // and long-lived status matches
(!q->AuthInfo || question->AuthInfo) && // to avoid deadlock, don't make public query dup of a private one
+ (q->SuppressQuery == question->SuppressQuery) && // Questions that are suppressed/not suppressed
q->qnamehash == question->qnamehash &&
SameDomainName(&q->qname, &question->qname)) // and name
return(q);
@@ -7161,7 +6779,10 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi
q->servAddr = question->servAddr;
q->servPort = question->servPort;
q->qDNSServer = question->qDNSServer;
+ q->validDNSServers = question->validDNSServers;
q->unansweredQueries = question->unansweredQueries;
+ q->noServerResponse = question->noServerResponse;
+ q->triedAllServersOnce = question->triedAllServersOnce;
q->TargetQID = question->TargetQID;
q->LocalSocket = question->LocalSocket;
@@ -7199,22 +6820,232 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi
}
}
-// Look up a DNS Server, matching by name in split-dns configurations.
-mDNSexport DNSServer *GetServerForName(mDNS *m, const domainname *name)
+mDNSinline mDNSs32 PenaltyTimeForServer(mDNS *m, DNSServer *server)
+ {
+ mDNSs32 ptime = 0;
+ if (server->penaltyTime != 0)
+ {
+ ptime = server->penaltyTime - m->timenow;
+ if (ptime < 0)
+ {
+ // This should always be a positive value between 0 and DNSSERVER_PENALTY_TIME
+ // If it does not get reset in ResetDNSServerPenalties for some reason, we do it
+ // here
+ LogMsg("PenaltyTimeForServer: PenaltyTime negative %d, (server penaltyTime %d, timenow %d) resetting the penalty",
+ ptime, server->penaltyTime, m->timenow);
+ server->penaltyTime = 0;
+ ptime = 0;
+ }
+ }
+ return ptime;
+ }
+
+//Checks to see whether the newname is a better match for the name, given the best one we have
+//seen so far (given in bestcount).
+//Returns -1 if the newname is not a better match
+//Returns 0 if the newname is the same as the old match
+//Returns 1 if the newname is a better match
+mDNSlocal int BetterMatchForName(const domainname *name, int namecount, const domainname *newname, int newcount,
+ int bestcount)
+ {
+ // If the name contains fewer labels than the new server's domain or the new name
+ // contains fewer labels than the current best, then it can't possibly be a better match
+ if (namecount < newcount || newcount < bestcount) return -1;
+
+ // If there is no match, return -1 and the caller will skip this newname for
+ // selection
+ //
+ // If we find a match and the number of labels is the same as bestcount, then
+ // we return 0 so that the caller can do additional logic to pick one of
+ // the best based on some other factors e.g., penaltyTime
+ //
+ // If we find a match and the number of labels is more than bestcount, then we
+ // return 1 so that the caller can pick this over the old one.
+ //
+ // Note: newcount can either be equal or greater than bestcount beause of the
+ // check above.
+
+ if (SameDomainName(SkipLeadingLabels(name, namecount - newcount), newname))
+ return bestcount == newcount ? 0 : 1;
+ else
+ return -1;
+ }
+
+// Sets all the Valid DNS servers for a question
+mDNSexport void SetValidDNSServers(mDNS *m, DNSQuestion *question)
+ {
+ DNSServer *curmatch = mDNSNULL;
+ int bestmatchlen = -1, namecount = CountLabels(&question->qname);
+ DNSServer *curr;
+ int bettermatch, currcount;
+ int index = 0;
+
+ question->validDNSServers = zeroOpaque64;
+ for (curr = m->DNSServers; curr; curr = curr->next)
+ {
+ debugf("SetValidDNSServers: Parsing DNS server Address %#a (Domain %##s), Scope: %d", &curr->addr, curr->domain.c, curr->scoped);
+ // skip servers that will soon be deleted
+ if (curr->flags & DNSServer_FlagDelete)
+ { debugf("SetValidDNSServers: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scoped); continue; }
+
+ currcount = CountLabels(&curr->domain);
+ if ((!curr->scoped && (!question->InterfaceID || (question->InterfaceID == mDNSInterface_Unicast))) || (curr->interface == question->InterfaceID))
+ {
+ bettermatch = BetterMatchForName(&question->qname, namecount, &curr->domain, currcount, bestmatchlen);
+
+ // If we found a better match (bettermatch == 1) then clear all the bits
+ // corresponding to the old DNSServers that we have may set before and start fresh.
+ // If we find an equal match, then include that DNSServer also by setting the corresponding
+ // bit
+ if ((bettermatch == 1) || (bettermatch == 0))
+ {
+ curmatch = curr;
+ bestmatchlen = currcount;
+ if (bettermatch) { debugf("SetValidDNSServers: Resetting all the bits"); question->validDNSServers = zeroOpaque64; }
+ debugf("SetValidDNSServers: Setting the bit for DNS server Address %#a (Domain %##s), Scoped:%d index %d", &curr->addr, curr->domain.c, curr->scoped, index);
+ bit_set_opaque64(question->validDNSServers, index);
+ }
+ }
+ index++;
+ }
+ question->noServerResponse = 0;
+ debugf("SetValidDNSServers: ValidDNSServer bits 0x%x%x for question %p %##s (%s)",
+ question->validDNSServers.l[1], question->validDNSServers.l[0], question, question->qname.c, DNSTypeName(question->qtype));
+ }
+
+// Get the Best server that matches a name. If you find penalized servers, look for the one
+// that will come out of the penalty box soon
+mDNSlocal DNSServer *GetBestServer(mDNS *m, const domainname *name, mDNSInterfaceID InterfaceID, mDNSOpaque64 validBits, int *selected, mDNSBool nameMatch)
+ {
+ DNSServer *curmatch = mDNSNULL;
+ int bestmatchlen = -1, namecount = name ? CountLabels(name) : 0;
+ DNSServer *curr;
+ mDNSs32 bestPenaltyTime, currPenaltyTime;
+ int bettermatch, currcount;
+ int index = 0;
+ int currindex = -1;
+
+ debugf("GetBestServer: ValidDNSServer bits 0x%x%x", validBits.l[1], validBits.l[0]);
+ bestPenaltyTime = DNSSERVER_PENALTY_TIME + 1;
+ for (curr = m->DNSServers; curr; curr = curr->next)
+ {
+ // skip servers that will soon be deleted
+ if (curr->flags & DNSServer_FlagDelete)
+ { debugf("GetBestServer: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scoped); continue; }
+
+ // Check if this is a valid DNSServer
+ if (!bit_get_opaque64(validBits, index)) { debugf("GetBestServer: continuing for index %d", index); index++; continue; }
+
+ currcount = CountLabels(&curr->domain);
+ currPenaltyTime = PenaltyTimeForServer(m, curr);
+
+ debugf("GetBestServer: Address %#a (Domain %##s), PenaltyTime(abs) %d, PenaltyTime(rel) %d",
+ &curr->addr, curr->domain.c, curr->penaltyTime, currPenaltyTime);
+
+ // If there are multiple best servers for a given question, we will pick the first one
+ // if none of them are penalized. If some of them are penalized in that list, we pick
+ // the least penalized one. BetterMatchForName walks through all best matches and
+ // "currPenaltyTime < bestPenaltyTime" check lets us either pick the first best server
+ // in the list when there are no penalized servers and least one among them
+ // when there are some penalized servers
+ //
+ // Notes on InterfaceID matching:
+ //
+ // 1) A DNSServer entry may have an InterfaceID but the scoped flag may not be set. This
+ // is the old way of specifying an InterfaceID option for DNSServer. We recoginize these
+ // entries by "scoped" being false. These are like any other unscoped entries except that
+ // if it is picked e.g., domain match, when the packet is sent out later, the packet will
+ // be sent out on that interface. Theese entries can be matched by either specifying a
+ // zero InterfaceID or non-zero InterfaceID on the question. Specifying an InterfaceID on
+ // the question will cause an extra check on matching the InterfaceID on the question
+ // against the DNSServer.
+ //
+ // 2) A DNSServer may also have both scoped set and InterfaceID non-NULL. This
+ // is the new way of specifying an InterfaceID option for DNSServer. These will be considered
+ // only when the question has non-zero interfaceID.
+
+ if ((!curr->scoped && !InterfaceID) || (curr->interface == InterfaceID))
+ {
+
+ // If we know that all the names are already equally good matches, then skip calling BetterMatchForName.
+ // This happens when we initially walk all the DNS servers and set the validity bit on the question.
+ // Actually we just need PenaltyTime match, but for the sake of readability we just skip the expensive
+ // part and still do some redundant steps e.g., InterfaceID match
+
+ if (nameMatch) bettermatch = BetterMatchForName(name, namecount, &curr->domain, currcount, bestmatchlen);
+ else bettermatch = 0;
+
+ // If we found a better match (bettermatch == 1) then we don't need to
+ // compare penalty times. But if we found an equal match, then we compare
+ // the penalty times to pick a better match
+
+ if ((bettermatch == 1) || ((bettermatch == 0) && currPenaltyTime < bestPenaltyTime))
+ { currindex = index; curmatch = curr; bestmatchlen = currcount; bestPenaltyTime = currPenaltyTime; }
+ }
+ index++;
+ }
+ if (selected) *selected = currindex;
+ return curmatch;
+ }
+
+// Look up a DNS Server, matching by name and InterfaceID
+mDNSexport DNSServer *GetServerForName(mDNS *m, const domainname *name, mDNSInterfaceID InterfaceID)
+ {
+ DNSServer *curmatch = mDNSNULL;
+ char *ifname = mDNSNULL; // for logging purposes only
+ mDNSOpaque64 allValid;
+
+ if ((InterfaceID == mDNSInterface_Unicast) || (InterfaceID == mDNSInterface_LocalOnly))
+ InterfaceID = mDNSNULL;
+
+ if (InterfaceID) ifname = InterfaceNameForID(m, InterfaceID);
+
+ // By passing in all ones, we make sure that every DNS server is considered
+ allValid.l[0] = allValid.l[1] = 0xFFFFFFFF;
+
+ curmatch = GetBestServer(m, name, InterfaceID, allValid, mDNSNULL, mDNStrue);
+
+ if (curmatch != mDNSNULL)
+ LogInfo("GetServerForName: DNS server %#a:%d (Penalty Time Left %d) (Scope %s:%p) found for name %##s", &curmatch->addr,
+ mDNSVal16(curmatch->port), (curmatch->penaltyTime ? (curmatch->penaltyTime - m->timenow) : 0), ifname ? ifname : "None",
+ InterfaceID, name);
+ else
+ LogInfo("GetServerForName: no DNS server (Scope %s:%p) found for name %##s", ifname ? ifname : "None", InterfaceID, name);
+
+ return(curmatch);
+ }
+
+// Look up a DNS Server for a question within its valid DNSServer bits
+mDNSexport DNSServer *GetServerForQuestion(mDNS *m, DNSQuestion *question)
{
- DNSServer *curmatch = mDNSNULL, *p;
- int curmatchlen = -1, ncount = name ? CountLabels(name) : 0;
+ DNSServer *curmatch = mDNSNULL;
+ char *ifname = mDNSNULL; // for logging purposes only
+ mDNSInterfaceID InterfaceID = question->InterfaceID;
+ const domainname *name = &question->qname;
+ int currindex;
- for (p = m->DNSServers; p; p = p->next)
+ if ((InterfaceID == mDNSInterface_Unicast) || (InterfaceID == mDNSInterface_LocalOnly))
+ InterfaceID = mDNSNULL;
+
+ if (InterfaceID) ifname = InterfaceNameForID(m, InterfaceID);
+
+ if (!mDNSOpaque64IsZero(&question->validDNSServers))
{
- int scount = CountLabels(&p->domain);
- if (!(p->flags & DNSServer_FlagDelete) && ncount >= scount && scount > curmatchlen)
- if (SameDomainName(SkipLeadingLabels(name, ncount - scount), &p->domain))
- { curmatch = p; curmatchlen = scount; }
+ curmatch = GetBestServer(m, name, InterfaceID, question->validDNSServers, &currindex, mDNSfalse);
+ if (currindex != -1) bit_clr_opaque64(question->validDNSServers, currindex);
}
+
+ if (curmatch != mDNSNULL)
+ LogInfo("GetServerForQuestion: %p DNS server %#a:%d (Penalty Time Left %d) (Scope %s:%p) found for name %##s (%s)", question, &curmatch->addr,
+ mDNSVal16(curmatch->port), (curmatch->penaltyTime ? (curmatch->penaltyTime - m->timenow) : 0), ifname ? ifname : "None",
+ InterfaceID, name, DNSTypeName(question->qtype));
+ else
+ LogInfo("GetServerForQuestion: %p no DNS server (Scope %s:%p) found for name %##s (%s)", question, ifname ? ifname : "None", InterfaceID, name, DNSTypeName(question->qtype));
+
return(curmatch);
}
+
#define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
(mDNSSameIPPort((Q)->TargetPort, UnicastDNSPort) || mDNSSameIPPort((Q)->TargetPort, MulticastDNSPort)))
@@ -7224,7 +7055,7 @@ mDNSlocal void LLQNATCallback(mDNS *m, NATTraversalInfo *n)
DNSQuestion *q;
(void)n; // Unused
mDNS_Lock(m);
- LogInfo("LLQNATCallback external address:port %.4a:%u", &n->ExternalAddress, mDNSVal16(n->ExternalPort));
+ LogInfo("LLQNATCallback external address:port %.4a:%u, NAT result %d", &n->ExternalAddress, mDNSVal16(n->ExternalPort), n->Result);
for (q = m->Questions; q; q=q->next)
if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived)
startLLQHandshake(m, q); // If ExternalPort is zero, will do StartLLQPolling instead
@@ -7234,6 +7065,212 @@ mDNSlocal void LLQNATCallback(mDNS *m, NATTraversalInfo *n)
mDNS_Unlock(m);
}
+mDNSlocal mDNSBool ShouldSuppressQuery(mDNS *const m, domainname *qname, mDNSu16 qtype, mDNSInterfaceID InterfaceID)
+ {
+ NetworkInterfaceInfo *i;
+ mDNSs32 iptype;
+ DomainAuthInfo *AuthInfo;
+
+ if (qtype == kDNSType_A) iptype = mDNSAddrType_IPv4;
+ else if (qtype == kDNSType_AAAA) iptype = mDNSAddrType_IPv6;
+ else { LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, not A/AAAA type", qname, DNSTypeName(qtype)); return mDNSfalse; }
+
+ // We still want the ability to be able to listen to the local services and hence
+ // don't fail .local requests. We always have a loopback interface which we don't
+ // check here.
+ if (InterfaceID != mDNSInterface_Unicast && IsLocalDomain(qname)) { LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, Local question", qname, DNSTypeName(qtype)); return mDNSfalse; }
+
+ // Skip Private domains as we have special addresses to get the hosts in the Private domain
+ AuthInfo = GetAuthInfoForName_internal(m, qname);
+ if (AuthInfo && !AuthInfo->deltime && AuthInfo->AutoTunnel)
+ { LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, Private Domain", qname, DNSTypeName(qtype)); return mDNSfalse; }
+
+ // Match on Type, Address and InterfaceID
+ //
+ // Check whether we are looking for a name that ends in .local, then presence of a link-local
+ // address on the interface is sufficient.
+ for (i = m->HostInterfaces; i; i = i->next)
+ {
+ if (i->ip.type != iptype) continue;
+
+ if (!InterfaceID || (InterfaceID == mDNSInterface_LocalOnly) || (InterfaceID == mDNSInterface_P2P) ||
+ (InterfaceID == mDNSInterface_Unicast) || (i->InterfaceID == InterfaceID))
+ {
+ if (iptype == mDNSAddrType_IPv4 && !mDNSv4AddressIsLoopback(&i->ip.ip.v4) && !mDNSv4AddressIsLinkLocal(&i->ip.ip.v4))
+ {
+ LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, Local Address %.4a found", qname, DNSTypeName(qtype),
+ &i->ip.ip.v4);
+ return mDNSfalse;
+ }
+ else if (iptype == mDNSAddrType_IPv6 &&
+ !mDNSv6AddressIsLoopback(&i->ip.ip.v6) &&
+ !mDNSv6AddressIsLinkLocal(&i->ip.ip.v6) &&
+ !mDNSSameIPv6Address(i->ip.ip.v6, m->AutoTunnelHostAddr) &&
+ !mDNSSameIPv6Address(i->ip.ip.v6, m->AutoTunnelRelayAddr))
+ {
+ LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, Local Address %.16a found", qname, DNSTypeName(qtype),
+ &i->ip.ip.v6);
+ return mDNSfalse;
+ }
+ }
+ }
+ LogInfo("ShouldSuppressQuery: Query suppressed for %##s, qtype %s, because no matching interface found", qname, DNSTypeName(qtype));
+ return mDNStrue;
+ }
+
+mDNSlocal void CheckSuppressedCurrentQuestion(mDNS *const m, DNSQuestion *q)
+ {
+ CacheRecord *rr;
+ mDNSu32 slot;
+ CacheGroup *cg;
+
+ // Temporarily turn off suppression so that AnswerCurrentQuestionWithResourceRecord
+ // can answer the question
+ q->SuppressQuery = mDNSfalse;
+ slot = HashSlot(&q->qname);
+ cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+ {
+ // Don't deliver RMV events for negative records
+ if (rr->resrec.RecordType == kDNSRecordTypePacketNegative)
+ {
+ LogInfo("CheckSuppressedCurrentQuestion: CacheRecord %s Suppressing RMV events for question %p %##s (%s), CRActiveQuestion %p, CurrentAnswers %d",
+ CRDisplayString(m, rr), q, q->qname.c, DNSTypeName(q->qtype), rr->CRActiveQuestion, q->CurrentAnswers);
+ continue;
+ }
+
+ if (SameNameRecordAnswersQuestion(&rr->resrec, q))
+ {
+ LogInfo("CheckSuppressedCurrentQuestion: Calling AnswerCurrentQuestionWithResourceRecord (RMV) for question %##s using resource record %s",
+ q->qname.c, CRDisplayString(m, rr));
+
+ q->CurrentAnswers--;
+ if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
+ if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
+
+ if (rr->CRActiveQuestion == q)
+ {
+ DNSQuestion *qptr;
+ // If this was the active question for this cache entry, it was the one that was
+ // responsible for keeping the cache entry fresh when the cache entry was reaching
+ // its expiry. We need to handover the responsibility to someone else. Otherwise,
+ // when the cache entry is about to expire, we won't find an active question
+ // (pointed by CRActiveQuestion) to refresh the cache.
+ for (qptr = m->Questions; qptr; qptr=qptr->next)
+ if (ActiveQuestion(qptr) && ResourceRecordAnswersQuestion(&rr->resrec, qptr))
+ break;
+
+ if (qptr)
+ LogInfo("CheckSuppressedCurrentQuestion: Updating CRActiveQuestion to %p for cache record %s, "
+ "Original question CurrentAnswers %d, new question CurrentAnswers %d, SuppressUnusable %d, SuppressQuery %d",
+ qptr, CRDisplayString(m,rr), q->CurrentAnswers, qptr->CurrentAnswers, qptr->SuppressUnusable, qptr->SuppressQuery);
+
+ rr->CRActiveQuestion = qptr; // Question used to be active; new value may or may not be null
+ if (!qptr) m->rrcache_active--; // If no longer active, decrement rrcache_active count
+ }
+ AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv);
+ if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
+ }
+ }
+ if (m->CurrentQuestion == q) q->SuppressQuery = mDNStrue;
+ }
+
+mDNSlocal mDNSBool IsQuestionNew(mDNS *const m, DNSQuestion *question)
+ {
+ DNSQuestion *q;
+ for (q = m->NewQuestions; q; q = q->next)
+ if (q == question) return mDNStrue;
+ return mDNSfalse;
+ }
+
+// The caller should hold the lock
+mDNSexport void CheckSuppressUnusableQuestions(mDNS *const m)
+ {
+ DNSQuestion *q, *qnext;
+ DNSQuestion *restart = mDNSNULL;
+
+ // We look through all questions including new questions. During network change events,
+ // we potentially restart questions here in this function that ends up as new questions,
+ // which may be suppressed at this instance. Before it is handled we get another network
+ // event that changes the status e.g., address becomes available. If we did not process
+ // new questions, we would never change its SuppressQuery status.
+ for (q = m->Questions; q ; q = qnext)
+ {
+ qnext = q->next;
+ if (!mDNSOpaque16IsZero(q->TargetQID) && q->SuppressUnusable)
+ {
+ mDNSBool old = q->SuppressQuery;
+ q->SuppressQuery = ShouldSuppressQuery(m, &q->qname, q->qtype, q->InterfaceID);
+ if (q->SuppressQuery != old)
+ {
+ if (q->SuppressQuery)
+ {
+ // Previously it was not suppressed, Generate RMV events for the ADDs that we might have delivered before
+ // followed by a negative cache response
+ if (m->CurrentQuestion)
+ LogMsg("CheckSuppressUnusableQuestions: ERROR m->CurrentQuestion already set: %##s (%s)",
+ m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+
+ // If it is a new question, we have not delivered any ADD events yet. So, don't deliver RMV events.
+ if (!IsQuestionNew(m, q))
+ {
+ m->CurrentQuestion = q;
+ CheckSuppressedCurrentQuestion(m, q);
+ if (m->CurrentQuestion != q)
+ {
+ m->CurrentQuestion = mDNSNULL;
+ LogInfo("CheckSuppressUnusableQuestions: Question deleted while giving RMV events");
+ continue;
+ }
+ m->CurrentQuestion = mDNSNULL;
+ }
+ else { debugf("CheckSuppressUnusableQuestion: Question %p %##s (%s) is a new question", q, q->qname.c, DNSTypeName(q->qtype)); }
+ }
+
+ // There are two cases here.
+ //
+ // 1. Previously it was suppressed and now it is not suppressed, restart the question so
+ // that it will start as a new question. Note that we can't just call ActivateUnicastQuery
+ // because when we get the response, if we had entries in the cache already, it will not answer
+ // this question if the cache entry did not change. Hence, we need to restart
+ // the query so that it can be answered from the cache.
+ //
+ // 2. Previously it was not suppressed and now it is suppressed. We need to restart the questions
+ // so that we redo the duplicate checks in mDNS_StartQuery_internal. A SuppressUnusable question
+ // is a duplicate of non-SuppressUnusable question if it is not suppressed (SuppressQuery is false).
+ // A SuppressUnusable question is not a duplicate of non-SuppressUnusable question if it is suppressed
+ // (SuppressQuery is true). The reason for this is that when a question is suppressed, we want an
+ // immediate response and not want to be blocked behind a question that is querying DNS servers.
+ // When the question is not suppressed, we don't want two active questions sending packets on the wire.
+ // This affects both efficiency and also the current design where there is only one active question
+ // pointed to from a cache entry.
+ //
+ // We restart queries in a two step process by first calling stop and build a temporary list which we
+ // will restart at the end. The main reason for the two step process is to handle duplicate questions.
+ // If there are duplicate questions, calling stop inherits the values from another question on the list (which
+ // will soon become the real question) including q->ThisQInterval which might be zero if it was
+ // suppressed before. At the end when we have restarted all questions, none of them is active as each
+ // inherits from one another and we need to reactivate one of the questions here which is a little hacky.
+ //
+ // It is much cleaner and less error prone to build a list of questions and restart at the end.
+
+ LogInfo("CheckSuppressUnusableQuestions: Stop question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+ mDNS_StopQuery_internal(m, q);
+ q->next = restart;
+ restart = q;
+ }
+ }
+ }
+ while (restart)
+ {
+ q = restart;
+ restart = restart->next;
+ q->next = mDNSNULL;
+ LogInfo("CheckSuppressUnusableQuestions: Start question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+ mDNS_StartQuery_internal(m, q);
+ }
+ }
+
mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question)
{
if (question->Target.type && !ValidQuestionTarget(question))
@@ -7243,13 +7280,11 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
question->Target.type = mDNSAddrType_None;
}
- if (!question->Target.type) question->TargetPort = zeroIPPort; // If question->Target specified clear TargetPort
+ if (!question->Target.type) question->TargetPort = zeroIPPort; // If no question->Target specified clear TargetPort
question->TargetQID =
#ifndef UNICAST_DISABLED
- (question->Target.type || (question->InterfaceID == mDNSInterface_Unicast) ||
- (question->InterfaceID != mDNSInterface_LocalOnly && !question->ForceMCast && !IsLocalDomain(&question->qname)))
- ? mDNS_NewMessageID(m) :
+ (question->Target.type || Question_uDNS(question)) ? mDNS_NewMessageID(m) :
#endif // UNICAST_DISABLED
zeroID;
@@ -7270,7 +7305,7 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
// Note: It important that new questions are appended at the *end* of the list, not prepended at the start
q = &m->Questions;
- if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
+ if (question->InterfaceID == mDNSInterface_LocalOnly || question->InterfaceID == mDNSInterface_P2P) q = &m->LocalOnlyQuestions;
while (*q && *q != question) q=&(*q)->next;
if (*q)
@@ -7283,7 +7318,7 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
*q = question;
// If this question is referencing a specific interface, verify it exists
- if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly && question->InterfaceID != mDNSInterface_Unicast)
+ if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly && question->InterfaceID != mDNSInterface_Unicast && question->InterfaceID != mDNSInterface_P2P)
{
NetworkInterfaceInfo *intf = FirstInterfaceForID(m, question->InterfaceID);
if (!intf)
@@ -7309,7 +7344,12 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
question->UniqueAnswers = 0;
question->FlappingInterface1 = mDNSNULL;
question->FlappingInterface2 = mDNSNULL;
- question->AuthInfo = GetAuthInfoForQuestion(m, question); // Must do this before calling FindDuplicateQuestion()
+ // Must do AuthInfo and SuppressQuery before calling FindDuplicateQuestion()
+ question->AuthInfo = GetAuthInfoForQuestion(m, question);
+ if (question->SuppressUnusable)
+ question->SuppressQuery = ShouldSuppressQuery(m, &question->qname, question->qtype, question->InterfaceID);
+ else
+ question->SuppressQuery = 0;
question->DuplicateOf = FindDuplicateQuestion(m, question);
question->NextInDQList = mDNSNULL;
question->SendQNow = mDNSNULL;
@@ -7323,6 +7363,7 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
// We also don't need one for LLQs because (when we're using NAT) we want them all to share a single
// NAT mapping for receiving inbound add/remove events.
question->LocalSocket = mDNSNULL;
+ question->deliverAddEvents = mDNSfalse;
question->qDNSServer = mDNSNULL;
question->unansweredQueries = 0;
question->nta = mDNSNULL;
@@ -7336,6 +7377,9 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
question->expire = 0;
question->ntries = 0;
question->id = zeroOpaque64;
+ question->validDNSServers = zeroOpaque64;
+ question->triedAllServersOnce = 0;
+ question->noServerResponse = 0;
if (question->DuplicateOf) question->AuthInfo = question->DuplicateOf->AuthInfo;
@@ -7344,11 +7388,15 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
debugf("mDNS_StartQuery: Question %##s (%s) Interface %p Now %d Send in %d Answer in %d (%p) %s (%p)",
question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, m->timenow,
- question->LastQTime + question->ThisQInterval - m->timenow,
+ NextQSendTime(question) - m->timenow,
question->DelayAnswering ? question->DelayAnswering - m->timenow : 0,
question, question->DuplicateOf ? "duplicate of" : "not duplicate", question->DuplicateOf);
- if (question->InterfaceID == mDNSInterface_LocalOnly)
+ if (question->DelayAnswering)
+ LogInfo("mDNS_StartQuery_internal: Delaying answering for %d ticks while cache stabilizes for %##s (%s)",
+ question->DelayAnswering - m->timenow, question->qname.c, DNSTypeName(question->qtype));
+
+ if (question->InterfaceID == mDNSInterface_LocalOnly || question->InterfaceID == mDNSInterface_P2P)
{
if (!m->NewLocalOnlyQuestions) m->NewLocalOnlyQuestions = question;
}
@@ -7364,7 +7412,27 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
// this routine with the question list data structures in an inconsistent state.
if (!mDNSOpaque16IsZero(question->TargetQID))
{
- question->qDNSServer = GetServerForName(m, &question->qname);
+ // Duplicate questions should have the same DNSServers so that when we find
+ // a matching resource record, all of them get the answers. Calling GetServerForQuestion
+ // for the duplicate question may get a different DNS server from the original question
+ if (question->DuplicateOf)
+ {
+ question->validDNSServers = question->DuplicateOf->validDNSServers;
+ question->qDNSServer = question->DuplicateOf->qDNSServer;
+ LogInfo("mDNS_StartQuery_internal: Duplicate question %p (%p) %##s (%s), DNS Server %#a:%d",
+ question, question->DuplicateOf, question->qname.c, DNSTypeName(question->qtype),
+ question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
+ mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
+ }
+ else
+ {
+ SetValidDNSServers(m, question);
+ question->qDNSServer = GetServerForQuestion(m, question);
+ LogInfo("mDNS_StartQuery_internal: question %p %##s (%s), DNS Server %#a:%d",
+ question, question->qname.c, DNSTypeName(question->qtype),
+ question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
+ mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
+ }
ActivateUnicastQuery(m, question, mDNSfalse);
// If long-lived query, and we don't have our NAT mapping active, start it now
@@ -7395,7 +7463,15 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
mDNSexport void CancelGetZoneData(mDNS *const m, ZoneData *nta)
{
debugf("CancelGetZoneData %##s (%s)", nta->question.qname.c, DNSTypeName(nta->question.qtype));
- mDNS_StopQuery_internal(m, &nta->question);
+ // This function may be called anytime to free the zone information.The question may or may not have stopped.
+ // If it was already stopped, mDNS_StopQuery_internal would have set q->ThisQInterval to -1 and should not
+ // call it again
+ if (nta->question.ThisQInterval != -1)
+ {
+ mDNS_StopQuery_internal(m, &nta->question);
+ if (nta->question.ThisQInterval != -1)
+ LogMsg("CancelGetZoneData: Question %##s (%s) ThisQInterval %d not -1", nta->question.qname.c, DNSTypeName(nta->question.qtype), nta->question.ThisQInterval);
+ }
mDNSPlatformMemFree(nta);
}
@@ -7408,7 +7484,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
//LogInfo("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
- if (question->InterfaceID == mDNSInterface_LocalOnly) qp = &m->LocalOnlyQuestions;
+ if (question->InterfaceID == mDNSInterface_LocalOnly || question->InterfaceID == mDNSInterface_P2P) qp = &m->LocalOnlyQuestions;
while (*qp && *qp != question) qp=&(*qp)->next;
if (*qp) *qp = (*qp)->next;
else
@@ -7436,10 +7512,14 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
if (rr->CRActiveQuestion == question)
{
DNSQuestion *q;
+ // Checking for ActiveQuestion filters questions that are suppressed also
+ // as suppressed questions are not active
for (q = m->Questions; q; q=q->next) // Scan our list of questions
if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
break;
- debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr));
+ if (q)
+ debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s, Original question CurrentAnswers %d, new question "
+ "CurrentAnswers %d, SuppressQuery %d", q, CRDisplayString(m,rr), question->CurrentAnswers, q->CurrentAnswers, q->SuppressQuery);
rr->CRActiveQuestion = q; // Question used to be active; new value may or may not be null
if (!q) m->rrcache_active--; // If no longer active, decrement rrcache_active count
}
@@ -7473,7 +7553,6 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
// so if we delete it earlier in this routine, we could find that our "question->next" pointer above is already
// invalid before we even use it. By making sure that we update m->CurrentQuestion and m->NewQuestions if necessary
// *first*, then they're all ready to be updated a second time if necessary when we cancel our GetZoneData query.
- if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; }
if (question->LocalSocket) { mDNSPlatformUDPClose(question->LocalSocket); question->LocalSocket = mDNSNULL; }
if (!mDNSOpaque16IsZero(question->TargetQID) && question->LongLived)
@@ -7513,6 +7592,8 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
UpdateAutoTunnelDomainStatuses(m);
#endif
}
+ // wait until we send the refresh above which needs the nta
+ if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
return(mStatus_NoError);
}
@@ -7598,22 +7679,15 @@ mDNSlocal mStatus mDNS_StartBrowse_internal(mDNS *const m, DNSQuestion *const qu
question->Target = zeroAddr;
question->qtype = kDNSType_PTR;
question->qclass = kDNSClass_IN;
- question->LongLived = mDNSfalse;
+ question->LongLived = mDNStrue;
question->ExpectUnique = mDNSfalse;
question->ForceMCast = ForceMCast;
question->ReturnIntermed = mDNSfalse;
+ question->SuppressUnusable = mDNSfalse;
question->QuestionCallback = Callback;
question->QuestionContext = Context;
if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain)) return(mStatus_BadParamErr);
-#ifndef UNICAST_DISABLED
- if (Question_uDNS(question))
- {
- question->LongLived = mDNStrue;
- question->ThisQInterval = InitialQuestionInterval;
- question->LastQTime = m->timenow - question->ThisQInterval;
- }
-#endif // UNICAST_DISABLED
return(mDNS_StartQuery_internal(m, question));
}
@@ -7782,6 +7856,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
query->qSRV.ExpectUnique = mDNStrue;
query->qSRV.ForceMCast = mDNSfalse;
query->qSRV.ReturnIntermed = mDNSfalse;
+ query->qSRV.SuppressUnusable = mDNSfalse;
query->qSRV.QuestionCallback = FoundServiceInfoSRV;
query->qSRV.QuestionContext = query;
@@ -7795,6 +7870,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
query->qTXT.ExpectUnique = mDNStrue;
query->qTXT.ForceMCast = mDNSfalse;
query->qTXT.ReturnIntermed = mDNSfalse;
+ query->qTXT.SuppressUnusable = mDNSfalse;
query->qTXT.QuestionCallback = FoundServiceInfoTXT;
query->qTXT.QuestionContext = query;
@@ -7808,6 +7884,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
query->qAv4.ExpectUnique = mDNStrue;
query->qAv4.ForceMCast = mDNSfalse;
query->qAv4.ReturnIntermed = mDNSfalse;
+ query->qAv4.SuppressUnusable = mDNSfalse;
query->qAv4.QuestionCallback = FoundServiceInfo;
query->qAv4.QuestionContext = query;
@@ -7821,6 +7898,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
query->qAv6.ExpectUnique = mDNStrue;
query->qAv6.ForceMCast = mDNSfalse;
query->qAv6.ReturnIntermed = mDNSfalse;
+ query->qAv6.SuppressUnusable = mDNSfalse;
query->qAv6.QuestionCallback = FoundServiceInfo;
query->qAv6.QuestionContext = query;
@@ -7870,6 +7948,7 @@ mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, m
question->ExpectUnique = mDNSfalse;
question->ForceMCast = mDNSfalse;
question->ReturnIntermed = mDNSfalse;
+ question->SuppressUnusable = mDNSfalse;
question->QuestionCallback = Callback;
question->QuestionContext = Context;
if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr);
@@ -7897,12 +7976,6 @@ mDNSexport mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr)
mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newttl,
const mDNSu16 newrdlength, RData *const newrdata, mDNSRecordUpdateCallback *Callback)
{
-#ifndef UNICAST_DISABLED
- mDNSBool unicast = !(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(rr->resrec.name));
-#else
- mDNSBool unicast = mDNSfalse;
-#endif
-
if (!ValidateRData(rr->resrec.rrtype, newrdlength, newrdata))
{
LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer));
@@ -7914,37 +7987,36 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt
// If TTL is unspecified, leave TTL unchanged
if (newttl == 0) newttl = rr->resrec.rroriginalttl;
- // If we already have an update queued up which has not gone through yet,
- // give the client a chance to free that memory
- if (!unicast && rr->NewRData)
+ // If we already have an update queued up which has not gone through yet, give the client a chance to free that memory
+ if (rr->NewRData)
{
RData *n = rr->NewRData;
- rr->NewRData = mDNSNULL; // Clear the NewRData pointer ...
+ rr->NewRData = mDNSNULL; // Clear the NewRData pointer ...
if (rr->UpdateCallback)
- rr->UpdateCallback(m, rr, n); // ...and let the client free this memory, if necessary
+ rr->UpdateCallback(m, rr, n, rr->newrdlength); // ...and let the client free this memory, if necessary
}
rr->NewRData = newrdata;
rr->newrdlength = newrdlength;
rr->UpdateCallback = Callback;
- if (unicast) { mStatus status = uDNS_UpdateRecord(m, rr); mDNS_Unlock(m); return(status); }
+#ifndef UNICAST_DISABLED
+ if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly && rr->resrec.InterfaceID != mDNSInterface_P2P && !IsLocalDomain(rr->resrec.name))
+ {
+ mStatus status = uDNS_UpdateRecord(m, rr);
+ // The caller frees the memory on error, don't retain stale pointers
+ if (status != mStatus_NoError) { rr->NewRData = mDNSNULL; rr->newrdlength = 0; }
+ mDNS_Unlock(m);
+ return(status);
+ }
+#endif
if (rr->resrec.rroriginalttl == newttl &&
rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength))
CompleteRDataUpdate(m, rr);
else
{
- domainlabel name;
- domainname type, domain;
- DeconstructServiceName(rr->resrec.name, &name, &type, &domain);
rr->AnnounceCount = InitialAnnounceCount;
- // iChat often does suprious record updates where no data has changed. For the _presence service type, using
- // name/value pairs, the mDNSPlatformMemSame() check above catches this and correctly suppresses the wasteful
- // update. For the _ichat service type, the XML encoding introduces spurious noise differences into the data
- // even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us.
- // To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement.
- if (SameDomainLabel(type.c, (mDNSu8*)"\x6_ichat")) rr->AnnounceCount = 1;
InitializeLastAPTime(m, rr);
while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
if (!rr->UpdateBlocked && rr->UpdateCredits) rr->UpdateCredits--;
@@ -8176,22 +8248,16 @@ mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *act
mDNSlocal void RestartRecordGetZoneData(mDNS * const m)
{
AuthRecord *rr;
- ServiceRecordSet *s;
-
+ LogInfo("RestartRecordGetZoneData: ResourceRecords");
for (rr = m->ResourceRecords; rr; rr=rr->next)
- if (AuthRecord_uDNS(rr))
+ if (AuthRecord_uDNS(rr) && rr->state != regState_NoTarget)
{
debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", rr->resrec.name->c);
- if (rr->nta) CancelGetZoneData(m, rr->nta);
+ // Zero out the updateid so that if we have a pending response from the server, it won't
+ // be accepted as a valid response. If we accept the response, we might free the new "nta"
+ if (rr->nta) { rr->updateid = zeroID; CancelGetZoneData(m, rr->nta); }
rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationGotZoneData, rr);
}
-
- for (s = m->ServiceRegistrations; s; s = s->uDNS_next)
- {
- debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", s->RR_SRV.resrec.name->c);
- if (s->srs_nta) CancelGetZoneData(m, s->srs_nta);
- s->srs_nta = StartGetZoneData(m, s->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, s);
- }
}
mDNSlocal void InitializeNetWakeState(mDNS *const m, NetworkInterfaceInfo *set)
@@ -8236,7 +8302,12 @@ mDNSexport void mDNS_DeactivateNetWake_internal(mDNS *const m, NetworkInterfaceI
for (i=0; i<3; i++) if (set->NetWakeResolve[i].ThisQInterval >= 0) mDNS_StopQuery_internal(m, &set->NetWakeResolve[i]);
// Make special call to the browse callback to let it know it can to remove all records for this interface
- if (m->SPSBrowseCallback) m->SPSBrowseCallback(m, &set->NetWakeBrowse, mDNSNULL, mDNSfalse);
+ if (m->SPSBrowseCallback)
+ {
+ mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
+ m->SPSBrowseCallback(m, &set->NetWakeBrowse, mDNSNULL, mDNSfalse);
+ mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
+ }
// Reset our variables back to initial state, so we're ready for when NetWake is turned back on
// (includes resetting NetWakeBrowse.ThisQInterval back to -1)
@@ -8260,8 +8331,8 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
// Assume this interface will be active now, unless we find a duplicate already in the list
set->InterfaceActive = mDNStrue;
- set->IPv4Available = (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx);
- set->IPv6Available = (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx);
+ set->IPv4Available = (mDNSu8)(set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx);
+ set->IPv6Available = (mDNSu8)(set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx);
InitializeNetWakeState(m, set);
@@ -8307,37 +8378,40 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
if (set->McastTxRx && ((m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) || FirstOfType || set->InterfaceActive))
{
DNSQuestion *q;
- // If flapping, delay between first and second queries is eight seconds instead of one
- mDNSs32 delay = flapping ? mDNSPlatformOneSecond * 5 : 0;
- mDNSu8 announce = flapping ? (mDNSu8)1 : InitialAnnounceCount;
- mDNSs32 newSS = 0;
+ // Normally, after an interface comes up, we pause half a second before beginning probing.
+ // This is to guard against cases where there's rapid interface changes, where we could be confused by
+ // seeing packets we ourselves sent just moments ago (perhaps when this interface had a different address)
+ // which are then echoed back after a short delay by some Ethernet switches and some 802.11 base stations.
+ // We don't want to do a probe, and then see a stale echo of an announcement we ourselves sent,
+ // and think it's a conflicting answer to our probe.
+ // In the case of a flapping interface, we pause for five seconds, and reduce the announcement count to one packet.
+ const mDNSs32 probedelay = flapping ? mDNSPlatformOneSecond * 5 : mDNSPlatformOneSecond / 2;
+ const mDNSu8 numannounce = flapping ? (mDNSu8)1 : InitialAnnounceCount;
// Use a small amount of randomness:
// In the case of a network administrator turning on an Ethernet hub so that all the
// connected machines establish link at exactly the same time, we don't want them all
// to go and hit the network with identical queries at exactly the same moment.
- newSS = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
-#if APPLE_OSX_mDNSResponder
- // We set this to at least 2 seconds, because the MacOSX platform layer typically gets lots
- // of network change notifications in a row, and we don't know when we're done getting notified.
- // Note that this will not be set if the interface doesn't do multicast (set->McastTxRx).
- newSS += mDNSPlatformOneSecond * 2;
-#endif
- if (!m->SuppressSending || newSS - m->SuppressSending < 0) m->SuppressSending = newSS;
-
- if (flapping)
- {
- LogMsg("Note: RegisterInterface: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect",
- set->ifname, &set->ip);
- if (!m->SuppressProbes ||
- m->SuppressProbes - (m->timenow + delay) < 0)
- m->SuppressProbes = (m->timenow + delay);
- }
+ // We set a random delay of up to InitialQuestionInterval (1/3 second).
+ // We must *never* set m->SuppressSending to more than that (or set it repeatedly in a way
+ // that causes mDNSResponder to remain in a prolonged state of SuppressSending, because
+ // suppressing packet sending for more than about 1/3 second can cause protocol correctness
+ // to start to break down (e.g. we don't answer probes fast enough, and get name conflicts).
+ // See <rdar://problem/4073853> mDNS: m->SuppressSending set too enthusiastically
+ if (!m->SuppressSending) m->SuppressSending = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
+
+ if (flapping) LogMsg("RegisterInterface: Frequent transitions for interface %s (%#a)", set->ifname, &set->ip);
+
+ LogInfo("RegisterInterface: %s (%#a) probedelay %d", set->ifname, &set->ip, probedelay);
+ if (m->SuppressProbes == 0 ||
+ m->SuppressProbes - NonZeroTime(m->timenow + probedelay) < 0)
+ m->SuppressProbes = NonZeroTime(m->timenow + probedelay);
for (q = m->Questions; q; q=q->next) // Scan our list of questions
if (mDNSOpaque16IsZero(q->TargetQID))
if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) // If non-specific Q, or Q on this specific interface,
{ // then reactivate this question
+ // If flapping, delay between first and second queries is nine seconds instead of one second
mDNSBool dodelay = flapping && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID);
mDNSs32 initial = dodelay ? InitialQuestionInterval * QuestionIntervalStep2 : InitialQuestionInterval;
mDNSs32 qdelay = dodelay ? mDNSPlatformOneSecond * 5 : 0;
@@ -8361,13 +8435,18 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
{
if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
- if (rr->AnnounceCount < announce) rr->AnnounceCount = announce;
+ if (rr->AnnounceCount < numannounce) rr->AnnounceCount = numannounce;
+ rr->SendNSECNow = mDNSNULL;
InitializeLastAPTime(m, rr);
}
}
RestartRecordGetZoneData(m);
+ CheckSuppressUnusableQuestions(m);
+
+ mDNS_UpdateAllowSleep(m);
+
mDNS_Unlock(m);
return(mStatus_NoError);
}
@@ -8437,9 +8516,8 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
LogInfo("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;"
" marking questions etc. dormant", set->InterfaceID, set->ifname, &set->ip);
- if (flapping)
- LogMsg("Note: DeregisterInterface: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect",
- set->ifname, &set->ip);
+ if (set->McastTxRx && flapping)
+ LogMsg("DeregisterInterface: Frequent transitions for interface %s (%#a)", set->ifname, &set->ip);
// 1. Deactivate any questions specific to this interface, and tag appropriate questions
// so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
@@ -8460,15 +8538,16 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
{
// If this interface is deemed flapping,
// postpone deleting the cache records in case the interface comes back again
- if (!flapping) mDNS_PurgeCacheResourceRecord(m, rr);
- else
+ if (set->McastTxRx && flapping)
{
- // We want these record to go away in 30 seconds
+ // For a flapping interface we want these record to go away after 30 seconds
+ mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
// We set UnansweredQueries = MaxUnansweredQueries so we don't waste time doing any queries for them --
// if the interface does come back, any relevant questions will be reactivated anyway
- mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
rr->UnansweredQueries = MaxUnansweredQueries;
}
+ else
+ mDNS_PurgeCacheResourceRecord(m, rr);
}
// 3. Any DNS servers specific to this interface are now unusable
@@ -8493,12 +8572,15 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
mDNSu32 slot;
CacheGroup *cg;
CacheRecord *rr;
- m->NextCacheCheck = m->timenow;
FORALL_CACHERECORDS(slot, cg, rr)
if (rr->resrec.InterfaceID == set->InterfaceID)
mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
}
+ CheckSuppressUnusableQuestions(m);
+
+ mDNS_UpdateAllowSleep(m);
+
mDNS_Unlock(m);
}
@@ -8534,24 +8616,27 @@ mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus resu
// are still in the process of deregistering, don't pass on the NameConflict/MemFree message until
// every record is finished cleaning up.
mDNSu32 i;
+ ExtraResourceRecord *e = sr->Extras;
+
if (sr->RR_SRV.resrec.RecordType != kDNSRecordTypeUnregistered) return;
if (sr->RR_TXT.resrec.RecordType != kDNSRecordTypeUnregistered) return;
if (sr->RR_PTR.resrec.RecordType != kDNSRecordTypeUnregistered) return;
if (sr->RR_ADV.resrec.RecordType != kDNSRecordTypeUnregistered) return;
for (i=0; i<sr->NumSubTypes; i++) if (sr->SubTypes[i].resrec.RecordType != kDNSRecordTypeUnregistered) return;
+ while (e)
+ {
+ if (e->r.resrec.RecordType != kDNSRecordTypeUnregistered) return;
+ e = e->next;
+ }
+
// If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse,
// then we can now report the NameConflict to the client
if (sr->Conflict) result = mStatus_NameConflict;
- if (sr->srs_nta)
- {
- LogMsg("ServiceCallback ERROR Got mStatus_MemFree with srs_nta still set for %s", ARDisplayString(m, &sr->RR_SRV));
- CancelGetZoneData(m, sr->srs_nta);
- sr->srs_nta = mDNSNULL;
- }
}
+ LogInfo("ServiceCallback: All records %s for %##s", (result == mStatus_MemFree ? "Unregistered": "Registered"), sr->RR_PTR.resrec.name->c);
// CAUTION: MUST NOT do anything more with sr after calling sr->Callback(), because the client's callback
// function is allowed to do anything, including deregistering this service and freeing its memory.
if (sr->ServiceCallback)
@@ -8565,47 +8650,6 @@ mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
sr->ServiceCallback(m, sr, result);
}
-#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
-mDNSlocal mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
- {
- mDNSu32 i;
- ServiceRecordSet **p = &m->ServiceRegistrations;
- while (*p && *p != srs) p=&(*p)->uDNS_next;
- if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name->c); return(mStatus_AlreadyRegistered); }
-
- srs->uDNS_next = mDNSNULL;
- *p = srs;
-
- srs->RR_SRV.resrec.rroriginalttl = kHostNameTTL;
- srs->RR_TXT.resrec.rroriginalttl = kStandardTTL;
- srs->RR_PTR.resrec.rroriginalttl = kStandardTTL;
- for (i = 0; i < srs->NumSubTypes;i++) srs->SubTypes[i].resrec.rroriginalttl = kStandardTTL;
-
- srs->srs_uselease = mDNStrue;
-
- if (srs->RR_SRV.AutoTarget)
- {
- // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other
- // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate,
- // with the port number in our advertised SRV record automatically tracking the external mapped port.
- DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name);
- if (!AuthInfo || !AuthInfo->AutoTunnel) srs->RR_SRV.AutoTarget = Target_AutoHostAndNATMAP;
- }
-
- if (!GetServiceTarget(m, &srs->RR_SRV))
- {
- // defer registration until we've got a target
- LogInfo("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c);
- srs->state = regState_NoTarget;
- return mStatus_NoError;
- }
-
- ActivateUnicastRegistration(m, &srs->RR_SRV);
- srs->state = regState_FetchingZoneData;
- return mStatus_NoError;
- }
-#endif
-
// Note:
// Name is first label of domain name (any dots in the name are actual dots, not label separators)
// Type is service type (e.g. "_ipp._tcp.")
@@ -8624,22 +8668,6 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
mStatus err;
mDNSu32 i;
- sr->state = regState_Zero;
- sr->srs_uselease = 0;
- sr->TestForSelfConflict = 0;
- sr->Private = 0;
- sr->id = zeroID;
- sr->zone.c[0] = 0;
- sr->SRSUpdateServer = zeroAddr;
- sr->SRSUpdatePort = zeroIPPort;
- mDNSPlatformMemZero(&sr->NATinfo, sizeof(sr->NATinfo));
- sr->NATinfo.IntPort = port; // Record originally-requested port
- sr->ClientCallbackDeferred = 0;
- sr->DeferredStatus = 0;
- sr->SRVUpdateDeferred = 0;
- sr->SRVChanged = 0;
- sr->tcp = mDNSNULL;
-
sr->ServiceCallback = Callback;
sr->ServiceContext = Context;
sr->Conflict = mDNSfalse;
@@ -8678,6 +8706,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
// 2. Set up the PTR record rdata to point to our service name
// We set up two additionals, so when a client asks for this PTR we automatically send the SRV and the TXT too
+ // Note: uDNS registration code assumes that Additional1 points to the SRV record
AssignDomainName(&sr->RR_PTR.resrec.rdata->u.name, sr->RR_SRV.resrec.name);
sr->RR_PTR.Additional1 = &sr->RR_SRV;
sr->RR_PTR.Additional2 = &sr->RR_TXT;
@@ -8709,6 +8738,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
// 4. Set up the TXT record rdata,
// and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us
+ // Note: uDNS registration code assumes that DependentOn points to the SRV record
if (txtinfo == mDNSNULL) sr->RR_TXT.resrec.rdlength = 0;
else if (txtinfo != sr->RR_TXT.resrec.rdata->u.txt.c)
{
@@ -8718,28 +8748,10 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
}
sr->RR_TXT.DependentOn = &sr->RR_SRV;
- sr->srs_nta = mDNSNULL;
-
-#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
- // If the client has specified an explicit InterfaceID,
- // then we do a multicast registration on that interface, even for unicast domains.
- if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&sr->RR_SRV.namestorage)))
- {
- mStatus status;
- mDNS_Lock(m);
- // 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.
- // (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck)
- if (!sr->RR_TXT.resrec.rdlength) { sr->RR_TXT.resrec.rdlength = 1; sr->RR_TXT.resrec.rdata->u.txt.c[0] = 0; }
-
- status = uDNS_RegisterService(m, sr);
- mDNS_Unlock(m);
- return(status);
- }
-#endif
-
mDNS_Lock(m);
+ // It is important that we register SRV first. uDNS assumes that SRV is registered first so
+ // that if the SRV cannot find a target, rest of the records that belong to this service
+ // will not be activated.
err = mDNS_Register_internal(m, &sr->RR_SRV);
if (!err) err = mDNS_Register_internal(m, &sr->RR_TXT);
// We register the RR_PTR last, because we want to be sure that in the event of a forced call to
@@ -8757,14 +8769,6 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
return(err);
}
-mDNSlocal void DummyCallback(mDNS *const m, AuthRecord *rr, mStatus result)
- {
- (void)m; // Unused
- (void)rr; // Unused
- (void)result; // Unused
- LogInfo("DummyCallback %d %s", result, ARDisplayString(m, rr));
- }
-
mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl)
{
@@ -8788,18 +8792,7 @@ mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
extra->r.resrec.name->c, DNSTypeName(extra->r.resrec.rrtype), extra->r.resrec.rdlength);
status = mDNS_Register_internal(m, &extra->r);
- if (status == mStatus_NoError)
- {
- *e = extra;
-#ifndef UNICAST_DISABLED
- if (AuthRecord_uDNS(&sr->RR_SRV))
- {
- extra->r.resrec.RecordType = kDNSRecordTypeShared; // don't want it to conflict with the service name (???)
- extra->r.RecordCallback = DummyCallback; // don't generate callbacks for extra RRs for unicast services (WHY NOT????)
- if (sr->state != regState_Registered && sr->state != regState_Refresh) extra->r.state = regState_ExtraQueued;
- }
-#endif
- }
+ if (status == mStatus_NoError) *e = extra;
mDNS_Unlock(m);
return(status);
@@ -8874,21 +8867,11 @@ mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordS
// Note: mDNS_DeregisterService calls mDNS_Deregister_internal which can call a user callback,
// which may change the record list and/or question list.
// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
-mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
+mDNSexport mStatus mDNS_DeregisterService_drt(mDNS *const m, ServiceRecordSet *sr, mDNS_Dereg_type drt)
{
// If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService()
if (mDNSIPPortIsZero(sr->RR_SRV.resrec.rdata->u.srv.port)) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV));
-#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
- if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
- {
- mStatus status;
- mDNS_Lock(m);
- status = uDNS_DeregisterService(m, sr);
- mDNS_Unlock(m);
- return(status);
- }
-#endif
if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeUnregistered)
{
debugf("Service set for %##s already deregistered", sr->RR_SRV.resrec.name->c);
@@ -8896,7 +8879,7 @@ mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
}
else if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeDeregistering)
{
- debugf("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name->c);
+ LogInfo("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name->c);
// Avoid race condition:
// If a service gets a conflict, then we set the Conflict flag to tell us to generate
// an mStatus_NameConflict message when we get the mStatus_MemFree for our PTR record.
@@ -8924,7 +8907,7 @@ mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
mDNS_Deregister_internal(m, &sr->RR_SRV, mDNS_Dereg_repeat);
mDNS_Deregister_internal(m, &sr->RR_TXT, mDNS_Dereg_repeat);
- mDNS_Deregister_internal(m, &sr->RR_ADV, mDNS_Dereg_normal);
+ mDNS_Deregister_internal(m, &sr->RR_ADV, drt);
// We deregister all of the extra records, but we leave the sr->Extras list intact
// in case the client wants to do a RenameAndReregister and reinstate the registration
@@ -8935,14 +8918,9 @@ mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
}
for (i=0; i<sr->NumSubTypes; i++)
- mDNS_Deregister_internal(m, &sr->SubTypes[i], mDNS_Dereg_normal);
-
- // Be sure to deregister the PTR last!
- // Deregistering this record is what triggers the mStatus_MemFree callback to ServiceCallback,
- // which in turn passes on the mStatus_MemFree (or mStatus_NameConflict) back to the client callback,
- // which is then at liberty to free the ServiceRecordSet memory at will. We need to make sure
- // we've deregistered all our records and done any other necessary cleanup before that happens.
- status = mDNS_Deregister_internal(m, &sr->RR_PTR, mDNS_Dereg_normal);
+ mDNS_Deregister_internal(m, &sr->SubTypes[i], drt);
+
+ status = mDNS_Deregister_internal(m, &sr->RR_PTR, drt);
mDNS_Unlock(m);
return(status);
}
@@ -8978,20 +8956,33 @@ mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr,
return(mDNS_Register(m, rr));
}
+mDNSlocal mDNSBool mDNS_IdUsedInResourceRecordsList(mDNS * const m, mDNSOpaque16 id)
+ {
+ AuthRecord *r;
+ for (r = m->ResourceRecords; r; r=r->next) if (mDNSSameOpaque16(id, r->updateid)) return mDNStrue;
+ return mDNSfalse;
+ }
+
+mDNSlocal mDNSBool mDNS_IdUsedInQuestionsList(mDNS * const m, mDNSOpaque16 id)
+ {
+ DNSQuestion *q;
+ for (q = m->Questions; q; q=q->next) if (mDNSSameOpaque16(id, q->TargetQID)) return mDNStrue;
+ return mDNSfalse;
+ }
+
mDNSexport mDNSOpaque16 mDNS_NewMessageID(mDNS * const m)
{
mDNSOpaque16 id;
int i;
+
for (i=0; i<10; i++)
{
- AuthRecord *r;
- DNSQuestion *q;
- id = mDNSOpaque16fromIntVal(1 + mDNSRandom(0xFFFE));
- for (r = m->ResourceRecords; r; r=r->next) if (mDNSSameOpaque16(id, r->updateid )) continue;
- for (q = m->Questions; q; q=q->next) if (mDNSSameOpaque16(id, q->TargetQID)) continue;
- break;
+ id = mDNSOpaque16fromIntVal(1 + (mDNSu16)mDNSRandom(0xFFFE));
+ if (!mDNS_IdUsedInResourceRecordsList(m, id) && !mDNS_IdUsedInQuestionsList(m, id)) break;
}
+
debugf("mDNS_NewMessageID: %5d", mDNSVal16(id));
+
return id;
}
@@ -9001,202 +8992,363 @@ mDNSexport mDNSOpaque16 mDNS_NewMessageID(mDNS * const m)
#pragma mark - Sleep Proxy Server
#endif
-mDNSlocal void RestartProbing(mDNS *const m, AuthRecord *const rr)
- {
- // We reset ProbeCount, so we'll suppress our own answers for a while, to avoid generating ARP conflicts with a waking machine.
- // If the machine does wake properly then we'll discard our records when we see the first new mDNS probe from that machine.
- // If it does not wake (perhaps we just picked up a stray delayed packet sent before it went to sleep)
- // then we'll transition out of probing state and start answering ARPs again.
+mDNSlocal void RestartARPProbing(mDNS *const m, AuthRecord *const rr)
+ {
+ // If we see an ARP from a machine we think is sleeping, then either
+ // (i) the machine has woken, or
+ // (ii) it's just a stray old packet from before the machine slept
+ // To handle the second case, we reset ProbeCount, so we'll suppress our own answers for a while, to avoid
+ // generating ARP conflicts with a waking machine, and set rr->LastAPTime so we'll start probing again in 10 seconds.
+ // If the machine has just woken then we'll discard our records when we see the first new mDNS probe from that machine.
+ // If it was a stray old packet, then after 10 seconds we'll probe again and then start answering ARPs again. In this case we *do*
+ // need to send new ARP Announcements, because the owner's ARP broadcasts will have updated neighboring ARP caches, so we need to
+ // re-assert our (temporary) ownership of that IP address in order to receive subsequent packets addressed to that IPv4 address.
+
rr->resrec.RecordType = kDNSRecordTypeUnique;
rr->ProbeCount = DefaultProbeCountForTypeUnique;
- rr->AnnounceCount = InitialAnnounceCount;
- InitializeLastAPTime(m, rr);
+
+ // If we haven't started announcing yet (and we're not already in ten-second-delay mode) the machine is probably
+ // still going to sleep, so we just reset rr->ProbeCount so we'll continue probing until it stops responding.
+ // If we *have* started announcing, the machine is probably in the process of waking back up, so in that case
+ // we're more cautious and we wait ten seconds before probing it again. We do this because while waking from
+ // sleep, some network interfaces tend to lose or delay inbound packets, and without this delay, if the waking machine
+ // didn't answer our three probes within three seconds then we'd announce and cause it an unnecessary address conflict.
+ if (rr->AnnounceCount == InitialAnnounceCount && m->timenow - rr->LastAPTime >= 0)
+ InitializeLastAPTime(m, rr);
+ else
+ {
+ rr->AnnounceCount = InitialAnnounceCount;
+ rr->ThisAPInterval = mDNSPlatformOneSecond;
+ rr->LastAPTime = m->timenow + mDNSPlatformOneSecond * 9; // Send first packet at rr->LastAPTime + rr->ThisAPInterval, i.e. 10 seconds from now
+ SetNextAnnounceProbeTime(m, rr);
+ }
}
-mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID)
+mDNSlocal void mDNSCoreReceiveRawARP(mDNS *const m, const ARP_EthIP *const arp, const mDNSInterfaceID InterfaceID)
{
- static const mDNSOpaque16 Ethertype_IP = { { 0x08, 0x00 } };
- static const mDNSOpaque32 ARP_EthIP_h0 = { { 0x08, 0x06, 0x00, 0x01 } }; // Ethertype (ARP = 0x0806), Hardware address space (Ethernet = 1)
- static const mDNSOpaque32 ARP_EthIP_h1 = { { 0x08, 0x00, 0x06, 0x04 } }; // Protocol address space (IP = 0x0800), hlen, plen
static const mDNSOpaque16 ARP_op_request = { { 0, 1 } };
- const EthernetHeader *const eth = (const EthernetHeader *)p;
- const ARP_EthIP *const arp = (const ARP_EthIP *)(eth+1);
- const IPv4Header *const v4 = (const IPv4Header *)(eth+1);
- const IPv6Header *const v6 = (const IPv6Header *)(eth+1);
- if (end >= p+42 && *(mDNSu32*)(p+12) == ARP_EthIP_h0.NotAnInteger && *(mDNSu32*)(p+16) == ARP_EthIP_h1.NotAnInteger)
- {
- AuthRecord *rr;
- NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
- if (!intf) return;
+ AuthRecord *rr;
+ NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
+ if (!intf) return;
- debugf("Got ARP from %.4a/%.6a for %.4a", &arp->spa, &arp->sha, &arp->tpa);
+ mDNS_Lock(m);
- mDNS_Lock(m);
+ // Pass 1:
+ // Process ARP Requests and Probes (but not Announcements), and generate an ARP Reply if necessary.
+ // We also process ARPs from our own kernel (and 'answer' them by injecting a local ARP table entry)
+ // We ignore ARP Announcements here -- Announcements are not questions, they're assertions, so we don't need to answer them.
+ // The times we might need to react to an ARP Announcement are:
+ // (i) as an indication that the host in question has not gone to sleep yet (so we should delay beginning to proxy for it) or
+ // (ii) if it's a conflicting Announcement from another host
+ // -- and we check for these in Pass 2 below.
+ if (mDNSSameOpaque16(arp->op, ARP_op_request) && !mDNSSameIPv4Address(arp->spa, arp->tpa))
+ {
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ if (rr->resrec.InterfaceID == InterfaceID && rr->resrec.RecordType != kDNSRecordTypeDeregistering &&
+ rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->tpa))
+ {
+ static const char msg1[] = "ARP Req from owner -- re-probing";
+ static const char msg2[] = "Ignoring ARP Request from ";
+ static const char msg3[] = "Creating Local ARP Cache entry ";
+ static const char msg4[] = "Answering ARP Request from ";
+ const char *const msg = mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC) ? msg1 :
+ (rr->AnnounceCount == InitialAnnounceCount) ? msg2 :
+ mDNSSameEthAddress(&arp->sha, &intf->MAC) ? msg3 : msg4;
+ LogSPS("%-7s %s %.6a %.4a for %.4a -- H-MAC %.6a I-MAC %.6a %s",
+ intf->ifname, msg, &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
+ if (msg == msg1) RestartARPProbing(m, rr);
+ else if (msg == msg3) mDNSPlatformSetLocalAddressCacheEntry(m, &rr->AddressProxy, &rr->WakeUp.IMAC, InterfaceID);
+ else if (msg == msg4) SendARP(m, 2, rr, &arp->tpa, &arp->sha, &arp->spa, &arp->sha);
+ }
+ }
- // Pass 1:
- // Process ARP Requests and Probes (but not Announcements), and generate an ARP Reply if necessary.
- // We also process and answer ARPs from our own kernel (no special treatment for localhost).
- // We ignore ARP Announcements here -- Announcements are not questions, they're assertions, so we don't need to answer them.
- // The only time we might need to respond to an ARP Announcement is if it's a conflict -- and we check for that in Pass 2 below.
- if (mDNSSameOpaque16(arp->op, ARP_op_request) && !mDNSSameIPv4Address(arp->spa, arp->tpa))
+ // Pass 2:
+ // For all types of ARP packet we check the Sender IP address to make sure it doesn't conflict with any AddressProxy record we're holding.
+ // (Strictly speaking we're only checking Announcement/Request/Reply packets, since ARP Probes have zero Sender IP address,
+ // so by definition (and by design) they can never conflict with any real (i.e. non-zero) IP address).
+ // We ignore ARPs we sent ourselves (Sender MAC address is our MAC address) because our own proxy ARPs do not constitute a conflict that we need to handle.
+ // If we see an apparently conflicting ARP, we check the sender hardware address:
+ // If the sender hardware address is the original owner this is benign, so we just suppress our own proxy answering for a while longer.
+ // If the sender hardware address is *not* the original owner, then this is a conflict, and we need to wake the sleeping machine to handle it.
+ if (mDNSSameEthAddress(&arp->sha, &intf->MAC))
+ debugf("ARP from self for %.4a", &arp->tpa);
+ else
+ {
+ if (!mDNSSameIPv4Address(arp->spa, zerov4Addr))
for (rr = m->ResourceRecords; rr; rr=rr->next)
- if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->tpa))
+ if (rr->resrec.InterfaceID == InterfaceID && rr->resrec.RecordType != kDNSRecordTypeDeregistering &&
+ rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->spa))
{
- static const char msg1[] = "ARP Req from owner -- re-probing";
- static const char msg2[] = "Ignoring ARP Request from ";
- static const char msg3[] = "Creating Local ARP Cache entry ";
- static const char msg4[] = "Answering ARP Request from ";
- const char *const msg = mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC) ? msg1 :
- (rr->AnnounceCount == InitialAnnounceCount) ? msg2 :
- mDNSSameEthAddress(&arp->sha, &intf->MAC) ? msg3 : msg4;
- LogSPS("%-7s %s %.6a %.4a for %.4a -- H-MAC %.6a I-MAC %.6a %s",
- InterfaceNameForID(m, InterfaceID), msg, &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
- if (msg == msg1) RestartProbing(m, rr);
- else if (msg == msg3) mDNSPlatformSetLocalARP(&arp->tpa, &rr->WakeUp.IMAC, InterfaceID);
- else if (msg == msg4) SendARP(m, 2, rr, arp->tpa.b, arp->sha.b, arp->spa.b, arp->sha.b);
- }
-
- // Pass 2:
- // For all types of ARP packet we check the Sender IP address to make sure it doesn't conflict with any AddressProxy record we're holding.
- // (Strictly speaking we're only checking Announcement/Request/Reply packets, since ARP Probes have zero Sender IP address,
- // so by definition (and by design) they can never conflict with any real (i.e. non-zero) IP address).
- // We ignore ARPs we sent ourselves (Sender MAC address is our MAC address) because our own proxy ARPs do not constitute a conflict that we need to handle.
- // If we see an apparently conflicting ARP, we check the sender hardware address:
- // If the sender hardware address is the original owner this is benign, so we just suppress our own proxy answering for a while longer.
- // If the sender hardware address is *not* the original owner, then this is a conflict, and we need to wake the sleeping machine to handle it.
- if (mDNSSameEthAddress(&arp->sha, &intf->MAC))
- debugf("ARP from self for %.4a", &arp->tpa);
- else
- {
- if (!mDNSSameIPv4Address(arp->spa, zerov4Addr))
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->spa))
+ RestartARPProbing(m, rr);
+ if (mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC))
+ LogSPS("%-7s ARP %s from owner %.6a %.4a for %-15.4a -- re-starting probing for %s", intf->ifname,
+ mDNSSameIPv4Address(arp->spa, arp->tpa) ? "Announcement " : mDNSSameOpaque16(arp->op, ARP_op_request) ? "Request " : "Response ",
+ &arp->sha, &arp->spa, &arp->tpa, ARDisplayString(m, rr));
+ else
{
- RestartProbing(m, rr);
- if (mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC))
- LogSPS("%-7s ARP %s from owner %.6a %.4a for %-15.4a -- re-starting probing for %s",
- InterfaceNameForID(m, InterfaceID),
- mDNSSameIPv4Address(arp->spa, arp->tpa) ? "Announcement" : mDNSSameOpaque16(arp->op, ARP_op_request) ? "Request " : "Response ",
- &arp->sha, &arp->spa, &arp->tpa, ARDisplayString(m, rr));
- else
- {
- LogMsg("%-7s Conflicting ARP from %.6a %.4a for %.4a -- waking H-MAC %.6a I-MAC %.6a %s",
- InterfaceNameForID(m, InterfaceID), &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
- SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password);
- }
+ LogMsg("%-7s Conflicting ARP from %.6a %.4a for %.4a -- waking H-MAC %.6a I-MAC %.6a %s", intf->ifname,
+ &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
+ ScheduleWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.HMAC);
}
- }
-
- mDNS_Unlock(m);
+ }
}
- else if (end >= p+34 && mDNSSameOpaque16(eth->ethertype, Ethertype_IP) && (v4->flagsfrags.b[0] & 0x1F) == 0 && v4->flagsfrags.b[1] == 0)
+
+ mDNS_Unlock(m);
+ }
+
+/*
+// Option 1 is Source Link Layer Address Option
+// Option 2 is Target Link Layer Address Option
+mDNSlocal const mDNSEthAddr *GetLinkLayerAddressOption(const IPv6NDP *const ndp, const mDNSu8 *const end, mDNSu8 op)
+ {
+ const mDNSu8 *options = (mDNSu8 *)(ndp+1);
+ while (options < end)
{
- const mDNSu8 *const trans = p + 14 + (v4->vlen & 0xF) * 4;
- const mDNSu8 *const required = trans + (v4->protocol == 1 ? 4 : v4->protocol == 6 ? 20 : v4->protocol == 17 ? 8 : 0);
- debugf("Got IPv4 from %.4a to %.4a", &v4->src, &v4->dst);
- if (end >= required)
- {
- #define SSH_AsNumber 22
- #define ARD_AsNumber 3283
- #define IPSEC_AsNumber 4500
- static const mDNSIPPort SSH = { { SSH_AsNumber >> 8, SSH_AsNumber & 0xFF } };
- static const mDNSIPPort ARD = { { ARD_AsNumber >> 8, ARD_AsNumber & 0xFF } };
- static const mDNSIPPort IPSEC = { { IPSEC_AsNumber >> 8, IPSEC_AsNumber & 0xFF } };
+ debugf("NDP Option %02X len %2d %d", options[0], options[1], end - options);
+ if (options[0] == op && options[1] == 1) return (const mDNSEthAddr*)(options+2);
+ options += options[1] * 8;
+ }
+ return mDNSNULL;
+ }
+*/
- mDNSBool wake = mDNSfalse;
- mDNSIPPort port = zeroIPPort;
-
- switch (v4->protocol)
+mDNSlocal void mDNSCoreReceiveRawND(mDNS *const m, const mDNSEthAddr *const sha, const mDNSv6Addr *spa,
+ const IPv6NDP *const ndp, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID)
+ {
+ AuthRecord *rr;
+ NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
+ if (!intf) return;
+
+ mDNS_Lock(m);
+
+ // Pass 1: Process Neighbor Solicitations, and generate a Neighbor Advertisement if necessary.
+ if (ndp->type == NDP_Sol)
+ {
+ //const mDNSEthAddr *const sha = GetLinkLayerAddressOption(ndp, end, NDP_SrcLL);
+ (void)end;
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ if (rr->resrec.InterfaceID == InterfaceID && rr->resrec.RecordType != kDNSRecordTypeDeregistering &&
+ rr->AddressProxy.type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->AddressProxy.ip.v6, ndp->target))
{
- #define XX wake ? "Received" : "Ignoring", end-p
- case 1: LogSPS("%s %d-byte ICMP from %.4a to %.4a", XX, &v4->src, &v4->dst);
- break;
-
- case 6: {
- const TCPHeader *const tcp = (const TCPHeader *)trans;
- port = tcp->dst;
-
- // Plan to wake if
- // (a) RST is not set, AND
- // (b) packet is SYN, SYN+FIN, or plain data packet (no SYN or FIN). We won't wake for FIN alone.
- wake = (!(tcp->flags & 4) && (tcp->flags & 3) != 1);
-
- // For now, to reduce spurious wakeups, we wake only for TCP SYN,
- // except for ssh connections, where we'll wake for plain data packets too
- if (!mDNSSameIPPort(port, SSH) && !(tcp->flags & 2)) wake = mDNSfalse;
-
- LogSPS("%s %d-byte TCP from %.4a:%d to %.4a:%d%s%s%s", XX,
- &v4->src, mDNSVal16(tcp->src), &v4->dst, mDNSVal16(port),
- (tcp->flags & 2) ? " SYN" : "",
- (tcp->flags & 1) ? " FIN" : "",
- (tcp->flags & 4) ? " RST" : "");
- }
- break;
+ static const char msg1[] = "NDP Req from owner -- re-probing";
+ static const char msg2[] = "Ignoring NDP Request from ";
+ static const char msg3[] = "Creating Local NDP Cache entry ";
+ static const char msg4[] = "Answering NDP Request from ";
+ static const char msg5[] = "Answering NDP Probe from ";
+ const char *const msg = sha && mDNSSameEthAddress(sha, &rr->WakeUp.IMAC) ? msg1 :
+ (rr->AnnounceCount == InitialAnnounceCount) ? msg2 :
+ sha && mDNSSameEthAddress(sha, &intf->MAC) ? msg3 :
+ spa && mDNSIPv6AddressIsZero(*spa) ? msg4 : msg5;
+ LogSPS("%-7s %s %.6a %.16a for %.16a -- H-MAC %.6a I-MAC %.6a %s",
+ intf->ifname, msg, sha, spa, &ndp->target, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
+ if (msg == msg1) RestartARPProbing(m, rr);
+ else if (msg == msg3)
+ {
+ if (!(m->KnownBugs & mDNS_KnownBug_LimitedIPv6))
+ mDNSPlatformSetLocalAddressCacheEntry(m, &rr->AddressProxy, &rr->WakeUp.IMAC, InterfaceID);
+ }
+ else if (msg == msg4) SendNDP(m, NDP_Adv, NDP_Solicited, rr, &ndp->target, mDNSNULL, spa, sha );
+ else if (msg == msg5) SendNDP(m, NDP_Adv, 0, rr, &ndp->target, mDNSNULL, &AllHosts_v6, &AllHosts_v6_Eth);
+ }
+ }
+
+ // Pass 2: For all types of NDP packet we check the Sender IP address to make sure it doesn't conflict with any AddressProxy record we're holding.
+ if (mDNSSameEthAddress(sha, &intf->MAC))
+ debugf("NDP from self for %.16a", &ndp->target);
+ else
+ {
+ // For Neighbor Advertisements we check the Target address field, not the actual IPv6 source address.
+ // When a machine has both link-local and routable IPv6 addresses, it may send NDP packets making assertions
+ // about its routable IPv6 address, using its link-local address as the source address for all NDP packets.
+ // Hence it is the NDP target address we care about, not the actual packet source address.
+ if (ndp->type == NDP_Adv) spa = &ndp->target;
+ if (!mDNSSameIPv6Address(*spa, zerov6Addr))
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ if (rr->resrec.InterfaceID == InterfaceID && rr->resrec.RecordType != kDNSRecordTypeDeregistering &&
+ rr->AddressProxy.type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->AddressProxy.ip.v6, *spa))
+ {
+ RestartARPProbing(m, rr);
+ if (mDNSSameEthAddress(sha, &rr->WakeUp.IMAC))
+ LogSPS("%-7s NDP %s from owner %.6a %.16a for %.16a -- re-starting probing for %s", intf->ifname,
+ ndp->type == NDP_Sol ? "Solicitation " : "Advertisement", sha, spa, &ndp->target, ARDisplayString(m, rr));
+ else
+ {
+ LogMsg("%-7s Conflicting NDP from %.6a %.16a for %.16a -- waking H-MAC %.6a I-MAC %.6a %s", intf->ifname,
+ sha, spa, &ndp->target, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
+ ScheduleWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.HMAC);
+ }
+ }
+ }
- case 17: {
- const UDPHeader *const udp = (const UDPHeader *)trans;
- mDNSu16 len = (mDNSu16)((mDNSu16)trans[4] << 8 | trans[5]);
- port = udp->dst;
- wake = mDNStrue;
+ mDNS_Unlock(m);
+ }
- // For Back to My Mac UDP port 4500 (IPSEC) packets, we specially ignore NAT keepalive packets
- if (mDNSSameIPPort(port, IPSEC)) wake = (len != 9 || end < trans + 9 || trans[8] != 0xFF);
+mDNSlocal void mDNSCoreReceiveRawTransportPacket(mDNS *const m, const mDNSEthAddr *const sha, const mDNSAddr *const src, const mDNSAddr *const dst, const mDNSu8 protocol,
+ const mDNSu8 *const p, const TransportLayerPacket *const t, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID, const mDNSu16 len)
+ {
+ const mDNSIPPort port = (protocol == 0x06) ? t->tcp.dst : (protocol == 0x11) ? t->udp.dst : zeroIPPort;
+ mDNSBool wake = mDNSfalse;
- // For now, because we haven't yet worked out a clean elegant way to do this, we just special-case the
- // Apple Remote Desktop port number -- we ignore all packets to UDP 3283 (the "Net Assistant" port),
- // except for Apple Remote Desktop's explicit manual wakeup packet, which looks like this:
- // UDP header (8 bytes) 13 88 00 6a 41 4e 41 20 (8 bytes) ffffffffffff (6 bytes) 16xMAC (96 bytes) = 118 bytes total
- if (mDNSSameIPPort(port, ARD)) wake = (len >= 118 && end >= trans+10 && trans[8] == 0x13 && trans[9] == 0x88);
+ switch (protocol)
+ {
+ #define XX wake ? "Received" : "Ignoring", end-p
+ case 0x01: LogSPS("Ignoring %d-byte ICMP from %#a to %#a", end-p, src, dst);
+ break;
- LogSPS("%s %d-byte UDP from %.4a:%d to %.4a:%d", XX, &v4->src, mDNSVal16(udp->src), &v4->dst, mDNSVal16(port));
- }
- break;
+ case 0x06: {
+ #define SSH_AsNumber 22
+ static const mDNSIPPort SSH = { { SSH_AsNumber >> 8, SSH_AsNumber & 0xFF } };
- default: LogSPS("%s %d-byte IP packet unknown protocol %d from %.4a to %.4a", XX, v4->protocol, &v4->src, &v4->dst);
- break;
- }
-
- if (wake)
- {
- AuthRecord *rr, *r2;
+ // Plan to wake if
+ // (a) RST is not set, AND
+ // (b) packet is SYN, SYN+FIN, or plain data packet (no SYN or FIN). We won't wake for FIN alone.
+ wake = (!(t->tcp.flags & 4) && (t->tcp.flags & 3) != 1);
- mDNS_Lock(m);
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- if (rr->resrec.InterfaceID == InterfaceID &&
- rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, v4->dst))
+ // For now, to reduce spurious wakeups, we wake only for TCP SYN,
+ // except for ssh connections, where we'll wake for plain data packets too
+ if (!mDNSSameIPPort(port, SSH) && !(t->tcp.flags & 2)) wake = mDNSfalse;
+
+ LogSPS("%s %d-byte TCP from %#a:%d to %#a:%d%s%s%s", XX,
+ src, mDNSVal16(t->tcp.src), dst, mDNSVal16(port),
+ (t->tcp.flags & 2) ? " SYN" : "",
+ (t->tcp.flags & 1) ? " FIN" : "",
+ (t->tcp.flags & 4) ? " RST" : "");
+ }
+ break;
+
+ case 0x11: {
+ #define ARD_AsNumber 3283
+ static const mDNSIPPort ARD = { { ARD_AsNumber >> 8, ARD_AsNumber & 0xFF } };
+ const mDNSu16 udplen = (mDNSu16)((mDNSu16)t->bytes[4] << 8 | t->bytes[5]); // Length *including* 8-byte UDP header
+ if (udplen >= sizeof(UDPHeader))
{
- const mDNSu8 *const tp = (v4->protocol == 6) ? (mDNSu8 *)"\x4_tcp" : (mDNSu8 *)"\x4_udp";
- for (r2 = m->ResourceRecords; r2; r2=r2->next)
- if (r2->resrec.InterfaceID == InterfaceID && mDNSSameEthAddress(&r2->WakeUp.HMAC, &rr->WakeUp.HMAC) &&
- r2->resrec.rrtype == kDNSType_SRV && mDNSSameIPPort(r2->resrec.rdata->u.srv.port, port) &&
- SameDomainLabel(SkipLeadingLabels(r2->resrec.name, 2)->c, tp))
- break;
- if (!r2 && mDNSSameIPPort(port, IPSEC)) r2 = rr; // So that we wake for BTMM IPSEC packets, even without a matching SRV record
- if (r2)
+ const mDNSu16 datalen = udplen - sizeof(UDPHeader);
+ wake = mDNStrue;
+
+ // For Back to My Mac UDP port 4500 (IPSEC) packets, we do some special handling
+ if (mDNSSameIPPort(port, IPSECPort))
{
- rr->AnnounceCount = 0;
- LogMsg("Waking host at %s %.4a H-MAC %.6a I-MAC %.6a for %s",
- InterfaceNameForID(m, rr->resrec.InterfaceID), &v4->dst, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, r2));
- SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password);
+ // Specifically ignore NAT keepalive packets
+ if (datalen == 1 && end >= &t->bytes[9] && t->bytes[8] == 0xFF) wake = mDNSfalse;
+ else
+ {
+ // Skip over the Non-ESP Marker if present
+ const mDNSBool NonESP = (end >= &t->bytes[12] && t->bytes[8] == 0 && t->bytes[9] == 0 && t->bytes[10] == 0 && t->bytes[11] == 0);
+ const IKEHeader *const ike = (IKEHeader *)(t + (NonESP ? 12 : 8));
+ const mDNSu16 ikelen = datalen - (NonESP ? 4 : 0);
+ if (ikelen >= sizeof(IKEHeader) && end >= ((mDNSu8 *)ike) + sizeof(IKEHeader))
+ if ((ike->Version & 0x10) == 0x10)
+ {
+ // ExchangeType == 5 means 'Informational' <http://www.ietf.org/rfc/rfc2408.txt>
+ // ExchangeType == 34 means 'IKE_SA_INIT' <http://www.iana.org/assignments/ikev2-parameters>
+ if (ike->ExchangeType == 5 || ike->ExchangeType == 34) wake = mDNSfalse;
+ LogSPS("%s %d-byte IKE ExchangeType %d", XX, ike->ExchangeType);
+ }
+ }
}
- else
- LogSPS("Sleeping host at %s %.4a %.6a has no service on %#s %d",
- InterfaceNameForID(m, rr->resrec.InterfaceID), &v4->dst, &rr->WakeUp.HMAC, tp, mDNSVal16(port));
+
+ // For now, because we haven't yet worked out a clean elegant way to do this, we just special-case the
+ // Apple Remote Desktop port number -- we ignore all packets to UDP 3283 (the "Net Assistant" port),
+ // except for Apple Remote Desktop's explicit manual wakeup packet, which looks like this:
+ // UDP header (8 bytes)
+ // Payload: 13 88 00 6a 41 4e 41 20 (8 bytes) ffffffffffff (6 bytes) 16xMAC (96 bytes) = 110 bytes total
+ if (mDNSSameIPPort(port, ARD)) wake = (datalen >= 110 && end >= &t->bytes[10] && t->bytes[8] == 0x13 && t->bytes[9] == 0x88);
+
+ LogSPS("%s %d-byte UDP from %#a:%d to %#a:%d", XX, src, mDNSVal16(t->udp.src), dst, mDNSVal16(port));
}
- mDNS_Unlock(m);
- }
- }
+ }
+ break;
+
+ case 0x3A: if (&t->bytes[len] <= end)
+ {
+ mDNSu16 checksum = IPv6CheckSum(&src->ip.v6, &dst->ip.v6, protocol, t->bytes, len);
+ if (!checksum) mDNSCoreReceiveRawND(m, sha, &src->ip.v6, &t->ndp, &t->bytes[len], InterfaceID);
+ else LogInfo("IPv6CheckSum bad %04X %02X%02X from %#a to %#a", checksum, t->bytes[2], t->bytes[3], src, dst);
+ }
+ break;
+
+ default: LogSPS("Ignoring %d-byte IP packet unknown protocol %d from %#a to %#a", end-p, protocol, src, dst);
+ break;
}
- else if (end >= p+34 && mDNSSameOpaque16(eth->ethertype, Ethertype_IP) && (v4->flagsfrags.b[0] & 0x1F) == 0 && v4->flagsfrags.b[1] == 0)
+
+ if (wake)
{
- debugf("Got IPv6 from %.16a to %.16a", &v4->src, &v6->dst);
- (void)v6;
+ AuthRecord *rr, *r2;
+
+ mDNS_Lock(m);
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ if (rr->resrec.InterfaceID == InterfaceID &&
+ rr->resrec.RecordType != kDNSRecordTypeDeregistering &&
+ rr->AddressProxy.type && mDNSSameAddress(&rr->AddressProxy, dst))
+ {
+ const mDNSu8 *const tp = (protocol == 6) ? (const mDNSu8 *)"\x4_tcp" : (const mDNSu8 *)"\x4_udp";
+ for (r2 = m->ResourceRecords; r2; r2=r2->next)
+ if (r2->resrec.InterfaceID == InterfaceID && mDNSSameEthAddress(&r2->WakeUp.HMAC, &rr->WakeUp.HMAC) &&
+ r2->resrec.RecordType != kDNSRecordTypeDeregistering &&
+ r2->resrec.rrtype == kDNSType_SRV && mDNSSameIPPort(r2->resrec.rdata->u.srv.port, port) &&
+ SameDomainLabel(ThirdLabel(r2->resrec.name)->c, tp))
+ break;
+ if (!r2 && mDNSSameIPPort(port, IPSECPort)) r2 = rr; // So that we wake for BTMM IPSEC packets, even without a matching SRV record
+ if (r2)
+ {
+ LogMsg("Waking host at %s %#a H-MAC %.6a I-MAC %.6a for %s",
+ InterfaceNameForID(m, rr->resrec.InterfaceID), dst, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, r2));
+ ScheduleWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.HMAC);
+ }
+ else
+ LogSPS("Sleeping host at %s %#a %.6a has no service on %#s %d",
+ InterfaceNameForID(m, rr->resrec.InterfaceID), dst, &rr->WakeUp.HMAC, tp, mDNSVal16(port));
+ }
+ mDNS_Unlock(m);
+ }
+ }
+
+mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID)
+ {
+ static const mDNSOpaque16 Ethertype_ARP = { { 0x08, 0x06 } }; // Ethertype 0x0806 = ARP
+ static const mDNSOpaque16 Ethertype_IPv4 = { { 0x08, 0x00 } }; // Ethertype 0x0800 = IPv4
+ static const mDNSOpaque16 Ethertype_IPv6 = { { 0x86, 0xDD } }; // Ethertype 0x86DD = IPv6
+ static const mDNSOpaque16 ARP_hrd_eth = { { 0x00, 0x01 } }; // Hardware address space (Ethernet = 1)
+ static const mDNSOpaque16 ARP_pro_ip = { { 0x08, 0x00 } }; // Protocol address space (IP = 0x0800)
+
+ // Note: BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
+ // In other words, we can safely assume that pkt below (ARP, IPv4 or IPv6) is properly word aligned,
+ // but if pkt is 4-byte aligned, that necessarily means that eth CANNOT also be 4-byte aligned
+ // since it points to a an address 14 bytes before pkt.
+ const EthernetHeader *const eth = (const EthernetHeader *)p;
+ const NetworkLayerPacket *const pkt = (const NetworkLayerPacket *)(eth+1);
+ mDNSAddr src, dst;
+ #define RequiredCapLen(P) ((P)==0x01 ? 4 : (P)==0x06 ? 20 : (P)==0x11 ? 8 : (P)==0x3A ? 24 : 0)
+
+ // Is ARP? Length must be at least 14 + 28 = 42 bytes
+ if (end >= p+42 && mDNSSameOpaque16(eth->ethertype, Ethertype_ARP) && mDNSSameOpaque16(pkt->arp.hrd, ARP_hrd_eth) && mDNSSameOpaque16(pkt->arp.pro, ARP_pro_ip))
+ mDNSCoreReceiveRawARP(m, &pkt->arp, InterfaceID);
+ // Is IPv4 with zero fragmentation offset? Length must be at least 14 + 20 = 34 bytes
+ else if (end >= p+34 && mDNSSameOpaque16(eth->ethertype, Ethertype_IPv4) && (pkt->v4.flagsfrags.b[0] & 0x1F) == 0 && pkt->v4.flagsfrags.b[1] == 0)
+ {
+ const mDNSu8 *const trans = p + 14 + (pkt->v4.vlen & 0xF) * 4;
+ debugf("Got IPv4 %02X from %.4a to %.4a", pkt->v4.protocol, &pkt->v4.src, &pkt->v4.dst);
+ src.type = mDNSAddrType_IPv4; src.ip.v4 = pkt->v4.src;
+ dst.type = mDNSAddrType_IPv4; dst.ip.v4 = pkt->v4.dst;
+ if (end >= trans + RequiredCapLen(pkt->v4.protocol))
+ mDNSCoreReceiveRawTransportPacket(m, &eth->src, &src, &dst, pkt->v4.protocol, p, (TransportLayerPacket*)trans, end, InterfaceID, 0);
+ }
+ // Is IPv6? Length must be at least 14 + 28 = 42 bytes
+ else if (end >= p+54 && mDNSSameOpaque16(eth->ethertype, Ethertype_IPv6))
+ {
+ const mDNSu8 *const trans = p + 54;
+ debugf("Got IPv6 %02X from %.16a to %.16a", pkt->v6.pro, &pkt->v6.src, &pkt->v6.dst);
+ src.type = mDNSAddrType_IPv6; src.ip.v6 = pkt->v6.src;
+ dst.type = mDNSAddrType_IPv6; dst.ip.v6 = pkt->v6.dst;
+ if (end >= trans + RequiredCapLen(pkt->v6.pro))
+ mDNSCoreReceiveRawTransportPacket(m, &eth->src, &src, &dst, pkt->v6.pro, p, (TransportLayerPacket*)trans, end, InterfaceID,
+ (mDNSu16)pkt->bytes[4] << 8 | pkt->bytes[5]);
}
}
mDNSlocal void ConstructSleepProxyServerName(mDNS *const m, domainlabel *name)
{
- name->c[0] = mDNS_snprintf((char*)name->c+1, 62, "%d-%d-%d-%d %#s",
+ name->c[0] = (mDNSu8)mDNS_snprintf((char*)name->c+1, 62, "%d-%d-%d-%d %#s",
m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower, &m->nicelabel);
}
@@ -9210,7 +9362,7 @@ mDNSlocal void SleepProxyServerCallback(mDNS *const m, ServiceRecordSet *const s
m->SPSState = 3;
else
{
- m->SPSState = (m->SPSSocket != mDNSNULL);
+ m->SPSState = (mDNSu8)(m->SPSSocket != mDNSNULL);
if (m->SPSState)
{
domainlabel name;
@@ -9228,15 +9380,19 @@ mDNSlocal void SleepProxyServerCallback(mDNS *const m, ServiceRecordSet *const s
}
}
-mDNSexport void mDNSCoreBeSleepProxyServer(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower)
+// Called with lock held
+mDNSexport void mDNSCoreBeSleepProxyServer_internal(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower)
{
+ // This routine uses mDNS_DeregisterService and calls SleepProxyServerCallback, so we execute in user callback context
+ mDNS_DropLockBeforeCallback();
+
// If turning off SPS, close our socket
// (Do this first, BEFORE calling mDNS_DeregisterService below)
if (!sps && m->SPSSocket) { mDNSPlatformUDPClose(m->SPSSocket); m->SPSSocket = mDNSNULL; }
// If turning off, or changing type, deregister old name
if (m->SPSState == 1 && sps != m->SPSType)
- { m->SPSState = 2; mDNS_DeregisterService(m, &m->SPSRecords); }
+ { m->SPSState = 2; mDNS_DeregisterService_drt(m, &m->SPSRecords, sps ? mDNS_Dereg_rapid : mDNS_Dereg_normal); }
// Record our new SPS parameters
m->SPSType = sps;
@@ -9250,10 +9406,17 @@ mDNSexport void mDNSCoreBeSleepProxyServer(mDNS *const m, mDNSu8 sps, mDNSu8 por
if (!m->SPSSocket)
{
m->SPSSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
- if (!m->SPSSocket) { LogMsg("mDNSCoreBeSleepProxyServer: Failed to allocate SPSSocket"); return; }
+ if (!m->SPSSocket) { LogMsg("mDNSCoreBeSleepProxyServer: Failed to allocate SPSSocket"); goto fail; }
}
if (m->SPSState == 0) SleepProxyServerCallback(m, &m->SPSRecords, mStatus_MemFree);
}
+ else if (m->SPSState)
+ {
+ LogSPS("mDNSCoreBeSleepProxyServer turning off from state %d; will wake clients", m->SPSState);
+ m->NextScheduledSPS = m->timenow;
+ }
+fail:
+ mDNS_ReclaimLockAfterCallback();
}
// ***************************************************************************
@@ -9332,9 +9495,12 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
m->RandomQueryDelay = 0;
m->RandomReconfirmDelay = 0;
m->PktNum = 0;
+ m->LocalRemoveEvents = mDNSfalse;
m->SleepState = SleepState_Awake;
m->SleepSeqNum = 0;
m->SystemWakeOnLANEnabled = mDNSfalse;
+ m->SentSleepProxyRegistration = mDNSfalse;
+ m->AnnounceOwner = NonZeroTime(timenow + 60 * mDNSPlatformOneSecond);
m->DelaySleep = 0;
m->SleepLimit = 0;
@@ -9350,7 +9516,11 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
m->rrcache_report = 10;
m->rrcache_free = mDNSNULL;
- for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) m->rrcache_hash[slot] = mDNSNULL;
+ for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
+ {
+ m->rrcache_hash[slot] = mDNSNULL;
+ m->rrcache_nextcheck[slot] = timenow + 0x78000000;;
+ }
mDNS_GrowCache_internal(m, rrcachestorage, rrcachesize);
@@ -9372,9 +9542,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
#ifndef UNICAST_DISABLED
m->NextuDNSEvent = timenow + 0x78000000;
m->NextSRVUpdate = timenow + 0x78000000;
- m->SuppressStdPort53Queries = 0;
- m->ServiceRegistrations = mDNSNULL;
m->DNSServers = mDNSNULL;
m->Router = zeroAddr;
@@ -9392,6 +9560,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
m->AutoTunnelLabel.c[0] = 0;
m->RegisterSearchDomains = mDNSfalse;
+ m->RegisterAutoTunnel6 = mDNStrue;
// NAT traversal fields
m->NATTraversals = mDNSNULL;
@@ -9429,6 +9598,15 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
#if APPLE_OSX_mDNSResponder
m->TunnelClients = mDNSNULL;
+
+#if ! NO_WCF
+ CHECK_WCF_FUNCTION(WCFConnectionNew)
+ {
+ m->WCF = WCFConnectionNew();
+ if (!m->WCF) { LogMsg("WCFConnectionNew failed"); return -1; }
+ }
+#endif
+
#endif
result = mDNSPlatformInit(m);
@@ -9456,7 +9634,7 @@ mDNSexport void mDNS_ConfigChanged(mDNS *const m)
// When SleepProxyServerCallback gets the mStatus_MemFree message,
// it will reregister the service under the new name
m->SPSState = 2;
- mDNS_DeregisterService(m, &m->SPSRecords);
+ mDNS_DeregisterService_drt(m, &m->SPSRecords, mDNS_Dereg_rapid);
}
}
@@ -9480,10 +9658,186 @@ mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const
(void) lameduck;
(void) ptr;
- debugf("uDNS_SetupDNSConfig: %s cache record due to %s server %p %#a:%d (%##s): %s", purge ? "purging" : "reconfirming", lameduck ? "lame duck" : "new", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c, CRDisplayString(m, cr));
+ debugf("PurgeOrReconfirmCacheRecord: %s cache record due to %s server %p %#a:%d (%##s): %s",
+ purge ? "purging" : "reconfirming",
+ lameduck ? "lame duck" : "new",
+ ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c, CRDisplayString(m, cr));
- if (purge) mDNS_PurgeCacheResourceRecord(m, cr);
- else mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
+ if (purge)
+ {
+ LogInfo("PurgeorReconfirmCacheRecord: Purging Resourcerecord %s, RecordType %x", CRDisplayString(m, cr), cr->resrec.RecordType);
+ mDNS_PurgeCacheResourceRecord(m, cr);
+ }
+ else
+ {
+ LogInfo("PurgeorReconfirmCacheRecord: Reconfirming Resourcerecord %s, RecordType %x", CRDisplayString(m, cr), cr->resrec.RecordType);
+ mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
+ }
+ }
+
+mDNSlocal void CacheRecordResetDNSServer(mDNS *const m, DNSQuestion *q, DNSServer *new)
+ {
+ const mDNSu32 slot = HashSlot(&q->qname);
+ CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ CacheRecord *rp;
+ mDNSBool found = mDNSfalse;
+ mDNSBool foundNew = mDNSfalse;
+ DNSServer *old = q->qDNSServer;
+ mDNSBool newQuestion = IsQuestionNew(m, q);
+ DNSQuestion *qptr;
+
+ // This function is called when the DNSServer is updated to the new question. There may already be
+ // some cache entries matching the old DNSServer and/or new DNSServer. There are four cases. In the
+ // following table, "Yes" denotes that a cache entry was found for old/new DNSServer.
+ //
+ // old DNSServer new DNSServer
+ //
+ // Case 1 Yes Yes
+ // Case 2 No Yes
+ // Case 3 Yes No
+ // Case 4 No No
+ //
+ // Case 1: There are cache entries for both old and new DNSServer. We handle this case by simply
+ // expiring the old Cache entries, deliver a RMV event (if an ADD event was delivered before)
+ // followed by the ADD event of the cache entries corresponding to the new server. This
+ // case happens when we pick a DNSServer, issue a query and get a valid response and create
+ // cache entries after which it stops responding. Another query (non-duplicate) picks a different
+ // DNSServer and creates identical cache entries (perhaps through records in Additional records).
+ // Now if the first one expires and tries to pick the new DNSServer (the original DNSServer
+ // is not responding) we will find cache entries corresponding to both DNSServers.
+ //
+ // Case 2: There are no cache entries for the old DNSServer but there are some for the new DNSServer.
+ // This means we should deliver an ADD event. Normally ADD events are delivered by
+ // AnswerNewQuestion if it is a new question. So, we check to see if it is a new question
+ // and if so, leave it to AnswerNewQuestion to deliver it. Otherwise, we use
+ // AnswerQuestionsForDNSServerChanges to deliver the ADD event. This case happens when a
+ // question picks a DNS server for which AnswerNewQuestion could not deliver an answer even
+ // though there were potential cache entries but DNSServer did not match. Now when we
+ // pick a new DNSServer, those cache entries may answer this question.
+ //
+ // Case 3: There are the cache entries for the old DNSServer but none for the new. We just move
+ // the old cache entries to point to the new DNSServer and the caller is expected to
+ // do a purge or reconfirm to delete or validate the RDATA. We don't need to do anything
+ // special for delivering ADD events, as it should have been done/will be done by
+ // AnswerNewQuestion. This case happens when we picked a DNSServer, sent the query and
+ // got a response and the cache is expired now and we are reissuing the question but the
+ // original DNSServer does not respond.
+ //
+ // Case 4: There are no cache entries either for the old or for the new DNSServer. There is nothing
+ // much we can do here.
+ //
+ // Case 2 and 3 are the most common while case 4 is possible when no DNSServers are working. Case 1
+ // is relatively less likely to happen in practice
+
+ // Temporarily set the DNSServer to look for the matching records for the new DNSServer.
+ q->qDNSServer = new;
+ for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next)
+ {
+ if (SameNameRecordAnswersQuestion(&rp->resrec, q))
+ {
+ LogInfo("CacheRecordResetDNSServer: Found cache record %##s for new DNSServer address: %#a", rp->resrec.name->c,
+ (rp->resrec.rDNSServer != mDNSNULL ? &rp->resrec.rDNSServer->addr : mDNSNULL));
+ foundNew = mDNStrue;
+ break;
+ }
+ }
+ q->qDNSServer = old;
+
+ for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next)
+ {
+ if (SameNameRecordAnswersQuestion(&rp->resrec, q))
+ {
+ // Case1
+ found = mDNStrue;
+ if (foundNew)
+ {
+ LogInfo("CacheRecordResetDNSServer: Flushing Resourcerecord %##s, before:%#a, after:%#a", rp->resrec.name->c,
+ (rp->resrec.rDNSServer != mDNSNULL ? &rp->resrec.rDNSServer->addr : mDNSNULL),
+ (new != mDNSNULL ? &new->addr : mDNSNULL));
+ mDNS_PurgeCacheResourceRecord(m, rp);
+ if (newQuestion)
+ {
+ // "q" is not a duplicate question. If it is a newQuestion, then the CRActiveQuestion can't be
+ // possibly set as it is set only when we deliver the ADD event to the question.
+ if (rp->CRActiveQuestion != mDNSNULL)
+ {
+ LogMsg("CacheRecordResetDNSServer: ERROR!!: CRActiveQuestion %p set, current question %p, name %##s", rp->CRActiveQuestion, q, q->qname.c);
+ rp->CRActiveQuestion = mDNSNULL;
+ }
+ // if this is a new question, then we never delivered an ADD yet, so don't deliver the RMV.
+ continue;
+ }
+ }
+ LogInfo("CacheRecordResetDNSServer: resetting cache record %##s DNSServer address before:%#a,"
+ " after:%#a, CRActiveQuestion %p", rp->resrec.name->c, (rp->resrec.rDNSServer != mDNSNULL ?
+ &rp->resrec.rDNSServer->addr : mDNSNULL), (new != mDNSNULL ? &new->addr : mDNSNULL),
+ rp->CRActiveQuestion);
+ // Though we set it to the new DNS server, the caller is *assumed* to do either a purge
+ // or reconfirm or send out questions to the "new" server to verify whether the cached
+ // RDATA is valid
+ rp->resrec.rDNSServer = new;
+ }
+ }
+
+ // Case 1 and Case 2
+ if ((found && foundNew) || (!found && foundNew))
+ {
+ if (newQuestion)
+ LogInfo("CacheRecordResetDNSServer: deliverAddEvents not set for question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+ else if (QuerySuppressed(q))
+ LogInfo("CacheRecordResetDNSServer: deliverAddEvents not set for suppressed question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+ else
+ {
+ LogInfo("CacheRecordResetDNSServer: deliverAddEvents set for %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+ q->deliverAddEvents = mDNStrue;
+ for (qptr = q->next; qptr; qptr = qptr->next)
+ if (qptr->DuplicateOf == q) qptr->deliverAddEvents = mDNStrue;
+ }
+ return;
+ }
+
+ // Case 3 and Case 4
+ return;
+ }
+
+mDNSexport void DNSServerChangeForQuestion(mDNS *const m, DNSQuestion *q, DNSServer *new)
+ {
+ DNSQuestion *qptr;
+
+ // 1. Whenever we change the DNS server, we change the message identifier also so that response
+ // from the old server is not accepted as a response from the new server but only messages
+ // from the new server are accepted as valid responses. We do it irrespective of whether "new"
+ // is NULL or not. It is possible that we send two queries, no responses, pick a new DNS server
+ // which is NULL and now the response comes back and will try to penalize the DNS server which
+ // is NULL. By setting the messageID here, we will not accept that as a valid response.
+
+ q->TargetQID = mDNS_NewMessageID(m);
+
+ // 2. Move the old cache records to point them at the new DNSServer so that we can deliver the ADD/RMV events
+ // appropriately. At any point in time, we want all the cache records point only to one DNSServer for a given
+ // question. "DNSServer" here is the DNSServer object and not the DNS server itself. It is possible to
+ // have the same DNS server address in two objects, one scoped and another not scoped. But, the cache is per
+ // DNSServer object. By maintaining the question and the cache entries point to the same DNSServer
+ // always, the cache maintenance and delivery of ADD/RMV events becomes simpler.
+ //
+ // CacheRecordResetDNSServer should be called only once for the non-duplicate question as once the cache
+ // entries are moved to point to the new DNSServer, we don't need to call it for the duplicate question
+ // and it is wrong to call for the duplicate question as it's decision to mark deliverAddevents will be
+ // incorrect.
+
+ if (q->DuplicateOf)
+ LogMsg("DNSServerChangeForQuestion: ERROR: Called for duplicate question %##s", q->qname.c);
+ else
+ CacheRecordResetDNSServer(m, q, new);
+
+ // 3. Make sure all the duplicate questions point to the same DNSServer so that delivery
+ // of events for all of them are consistent. Duplicates for a question are always inserted
+ // after in the list.
+ q->qDNSServer = new;
+ for (qptr = q->next ; qptr; qptr = qptr->next)
+ {
+ if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = new; }
+ }
}
mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
@@ -9507,16 +9861,53 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
// Let the platform layer get the current DNS information
// The m->RegisterSearchDomains boolean is so that we lazily get the search domain list only on-demand
// (no need to hit the network with domain enumeration queries until we actually need that information).
- for (ptr = m->DNSServers; ptr; ptr = ptr->next) ptr->flags |= DNSServer_FlagDelete;
+ for (ptr = m->DNSServers; ptr; ptr = ptr->next)
+ {
+ ptr->penaltyTime = 0;
+ ptr->flags |= DNSServer_FlagDelete;
+ }
mDNSPlatformSetDNSConfig(m, mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL);
+ // Mark the records to be flushed that match a new resolver. We need to do this before
+ // we walk the questions below where we change the DNSServer pointer of the cache
+ // record
+ FORALL_CACHERECORDS(slot, cg, cr)
+ {
+ if (cr->resrec.InterfaceID) continue;
+
+ // We just mark them for purge or reconfirm. We can't affect the DNSServer pointer
+ // here as the code below that calls CacheRecordResetDNSServer relies on this
+ //
+ // The new DNSServer may be a scoped or non-scoped one. We use the active question's
+ // InterfaceID for looking up the right DNS server
+ ptr = GetServerForName(m, cr->resrec.name, cr->CRActiveQuestion ? cr->CRActiveQuestion->InterfaceID : mDNSNULL);
+
+ // Purge or Reconfirm if this cache entry would use the new DNS server
+ if (ptr && (ptr != cr->resrec.rDNSServer))
+ {
+ // As the DNSServers for this cache record is not the same anymore, we don't
+ // want any new questions to pick this old value
+ if (cr->CRActiveQuestion == mDNSNULL)
+ {
+ LogInfo("uDNS_SetupDNSConfig: Purging Resourcerecord %s", CRDisplayString(m, cr));
+ mDNS_PurgeCacheResourceRecord(m, cr);
+ }
+ else
+ PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNSfalse);
+ }
+ }
// Update our qDNSServer pointers before we go and free the DNSServer object memory
for (q = m->Questions; q; q=q->next)
if (!mDNSOpaque16IsZero(q->TargetQID))
{
- DNSServer *s = GetServerForName(m, &q->qname);
- DNSServer *t = q->qDNSServer;
+ DNSServer *s, *t;
+ DNSQuestion *qptr;
+ if (q->DuplicateOf) continue;
+ SetValidDNSServers(m, q);
+ q->triedAllServersOnce = 0;
+ s = GetServerForQuestion(m, q);
+ t = q->qDNSServer;
if (t != s)
{
// If DNS Server for this question has changed, reactivate it
@@ -9524,20 +9915,47 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
t, t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), t ? t->domain.c : (mDNSu8*)"",
s, s ? &s->addr : mDNSNULL, mDNSVal16(s ? s->port : zeroIPPort), s ? s->domain.c : (mDNSu8*)"",
q->qname.c, DNSTypeName(q->qtype));
- q->qDNSServer = s;
+
+ // After we reset the DNSServer pointer on the cache records here, three things could happen:
+ //
+ // 1) The query gets sent out and when the actual response comes back later it is possible
+ // that the response has the same RDATA, in which case we update our cache entry.
+ // If the response is different, then the entry will expire and a new entry gets added.
+ // For the latter case to generate a RMV followed by ADD events, we need to reset the DNS
+ // server here to match the question and the cache record.
+ //
+ // 2) We might have marked the cache entries for purge above and for us to be able to generate the RMV
+ // events for the questions, the DNSServer on the question should match the Cache Record
+ //
+ // 3) We might have marked the cache entries for reconfirm above, for which we send the query out which is
+ // the same as the first case above.
+
+ DNSServerChangeForQuestion(m, q, s);
q->unansweredQueries = 0;
- ActivateUnicastQuery(m, q, mDNStrue);
+ // We still need to pick a new DNSServer for the questions that have been
+ // suppressed, but it is wrong to activate the query as DNS server change
+ // could not possibly change the status of SuppressUnusable questions
+ if (!QuerySuppressed(q))
+ {
+ debugf("uDNS_SetupDNSConfig: Activating query %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+ ActivateUnicastQuery(m, q, mDNStrue);
+ // ActivateUnicastQuery is called for duplicate questions also as it does something
+ // special for AutoTunnel questions
+ for (qptr = q->next ; qptr; qptr = qptr->next)
+ {
+ if (qptr->DuplicateOf == q) ActivateUnicastQuery(m, qptr, mDNStrue);
+ }
+ }
+ }
+ else
+ {
+ debugf("uDNS_SetupDNSConfig: Not Updating DNS server question %p %##s (%s) DNS server %#a:%d %p %d",
+ q, q->qname.c, DNSTypeName(q->qtype), t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), q->DuplicateOf, q->SuppressUnusable);
+ for (qptr = q->next ; qptr; qptr = qptr->next)
+ if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; }
}
}
- // Flush all records that match a new resolver
- FORALL_CACHERECORDS(slot, cg, cr)
- {
- ptr = GetServerForName(m, cr->resrec.name);
- if (ptr && (ptr->flags & DNSServer_FlagNew) && !cr->resrec.InterfaceID)
- PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNSfalse);
- }
-
while (*p)
{
if (((*p)->flags & DNSServer_FlagDelete) != 0)
@@ -9546,13 +9964,58 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
// We reconfirm any records that match, because in this world of split DNS, firewalls, etc.
// different DNS servers can give different answers to the same question.
ptr = *p;
- ptr->flags &= ~DNSServer_FlagDelete; // Clear del so GetServerForName will (temporarily) find this server again before it's finally deleted
FORALL_CACHERECORDS(slot, cg, cr)
- if (!cr->resrec.InterfaceID && GetServerForName(m, cr->resrec.name) == ptr)
+ {
+ if (cr->resrec.InterfaceID) continue;
+ if (cr->resrec.rDNSServer == ptr)
+ {
+ // If we don't have an active question for this cache record, neither Purge can
+ // generate RMV events nor Reconfirm can send queries out. Just set the DNSServer
+ // pointer on the record NULL so that we don't point to freed memory (We might dereference
+ // DNSServer pointers from resource record for logging purposes).
+ //
+ // If there is an active question, point to its DNSServer as long as it does not point to the
+ // freed one. We already went through the questions above and made them point at either the
+ // new server or NULL if there is no server and also affected the cache entries that match
+ // this question. Hence, whenever we hit a resource record with a DNSServer that is just
+ // about to be deleted, we should never have an active question. The code below just tries to
+ // be careful logging messages if we ever hit this case.
+
+ if (cr->CRActiveQuestion)
+ {
+ DNSQuestion *qptr = cr->CRActiveQuestion;
+ if (qptr->qDNSServer == mDNSNULL)
+ LogMsg("uDNS_SetupDNSConfig: Cache Record %s match: Active question %##s (%s) with DNSServer Address NULL, Server to be deleted %#a",
+ CRDisplayString(m, cr), qptr->qname.c, DNSTypeName(qptr->qtype), &ptr->addr);
+ else
+ LogMsg("uDNS_SetupDNSConfig: Cache Record %s match: Active question %##s (%s) DNSServer Address %#a, Server to be deleted %#a",
+ CRDisplayString(m, cr), qptr->qname.c, DNSTypeName(qptr->qtype), &qptr->qDNSServer->addr, &ptr->addr);
+
+ if (qptr->qDNSServer == ptr)
+ {
+ qptr->validDNSServers = zeroOpaque64;
+ qptr->qDNSServer = mDNSNULL;
+ cr->resrec.rDNSServer = mDNSNULL;
+ }
+ else
+ {
+ cr->resrec.rDNSServer = qptr->qDNSServer;
+ }
+ }
+ else
+ {
+ LogInfo("uDNS_SetupDNSConfig: Cache Record %##s has no Active question, Record's DNSServer Address %#a, Server to be deleted %#a",
+ cr->resrec.name, &cr->resrec.rDNSServer->addr, &ptr->addr);
+ cr->resrec.rDNSServer = mDNSNULL;
+ }
+
PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNStrue);
+ }
+ }
*p = (*p)->next;
debugf("uDNS_SetupDNSConfig: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c);
mDNSPlatformMemFree(ptr);
+ NumUnicastDNSServers--;
}
else
{
@@ -9571,12 +10034,11 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
FORALL_CACHERECORDS(slot, cg, cr) if (!cr->resrec.InterfaceID) { mDNS_PurgeCacheResourceRecord(m, cr); count++; }
LogInfo("uDNS_SetupDNSConfig: %s available; purged %d unicast DNS records from cache",
m->DNSServers ? "DNS server became" : "No DNS servers", count);
+
+ // Force anything that needs to get zone data to get that information again
+ RestartRecordGetZoneData(m);
}
- // If we no longer have any DNS servers, we need to force anything that needs to get zone data
- // to get that information again (which will fail, since we have no more DNS servers)
- if ((m->DNSServers == mDNSNULL) && (oldServers != mDNSNULL)) RestartRecordGetZoneData(m);
-
// Did our FQDN change?
if (!SameDomainName(&fqdn, &m->FQDN))
{
@@ -9610,6 +10072,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
if (m->FQDN.c[0]) mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); // Set status to 1 to indicate temporary failure
}
+ debugf("uDNS_SetupDNSConfig: number of unicast DNS servers %d", NumUnicastDNSServers);
return mStatus_NoError;
}
@@ -9626,21 +10089,24 @@ mDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result)
}
}
-extern ServiceRecordSet *CurrentServiceRecordSet;
-
mDNSlocal void DeregLoop(mDNS *const m, AuthRecord *const start)
{
m->CurrentRecord = start;
while (m->CurrentRecord)
{
AuthRecord *rr = m->CurrentRecord;
+ LogInfo("DeregLoop: %s deregistration for %p %02X %s",
+ (rr->resrec.RecordType != kDNSRecordTypeDeregistering) ? "Initiating " : "Accelerating",
+ rr, rr->resrec.RecordType, ARDisplayString(m, rr));
if (rr->resrec.RecordType != kDNSRecordTypeDeregistering)
+ mDNS_Deregister_internal(m, rr, mDNS_Dereg_rapid);
+ else if (rr->AnnounceCount > 1)
{
- LogInfo("DeregLoop: Deregistering %p %02X %s", rr, rr->resrec.RecordType, ARDisplayString(m, rr));
- mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
+ rr->AnnounceCount = 1;
+ rr->LastAPTime = m->timenow - rr->ThisAPInterval;
}
- // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because
- // the list may have been changed in that call.
+ // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because
+ // new records could have been added to the end of the list as a result of that call.
if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
m->CurrentRecord = rr->next;
}
@@ -9653,17 +10119,25 @@ mDNSexport void mDNS_StartExit(mDNS *const m)
mDNS_Lock(m);
+ LogInfo("mDNS_StartExit");
m->ShutdownTime = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5);
- mDNS_DropLockBeforeCallback(); // mDNSCoreBeSleepProxyServer expects to be called without the lock held, so we emulate that here
- mDNSCoreBeSleepProxyServer(m, 0, 0, 0, 0);
- mDNS_ReclaimLockAfterCallback();
+ mDNSCoreBeSleepProxyServer_internal(m, 0, 0, 0, 0);
+
+#if APPLE_OSX_mDNSResponder
+#if ! NO_WCF
+ CHECK_WCF_FUNCTION(WCFConnectionDealloc)
+ {
+ if (m->WCF) WCFConnectionDealloc((WCFConnection *)m->WCF);
+ }
+#endif
+#endif
#ifndef UNICAST_DISABLED
{
SearchListElem *s;
SuspendLLQs(m);
- // Don't need to do SleepRecordRegistrations() or SleepServiceRegistrations() here,
+ // Don't need to do SleepRecordRegistrations() here
// because we deregister all records and services later in this routine
while (m->Hostnames) mDNS_RemoveDynDNSHostName(m, &m->Hostnames->fqdn);
@@ -9694,9 +10168,11 @@ mDNSexport void mDNS_StartExit(mDNS *const m)
// This has particularly important implications for our AutoTunnel records --
// when we deregister our AutoTunnel records below, we don't want their mStatus_MemFree
// handlers to just turn around and attempt to re-register those same records.
- // Clearing t->ExternalPort will cause the mStatus_MemFree callback handlers to not do this.
+ // Clearing t->ExternalPort/t->RequestedPort will cause the mStatus_MemFree callback handlers
+ // to not do this.
t->ExternalAddress = zerov4Addr;
t->ExternalPort = zeroIPPort;
+ t->RequestedPort = zeroIPPort;
t->Lifetime = 0;
t->Result = mStatus_NoError;
}
@@ -9722,24 +10198,9 @@ mDNSexport void mDNS_StartExit(mDNS *const m)
m->SuppressSending = 0;
}
-#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
- CurrentServiceRecordSet = m->ServiceRegistrations;
- while (CurrentServiceRecordSet)
- {
- ServiceRecordSet *srs = CurrentServiceRecordSet;
- LogInfo("mDNS_StartExit: Deregistering uDNS service %##s", srs->RR_SRV.resrec.name->c);
- uDNS_DeregisterService(m, srs);
- if (CurrentServiceRecordSet == srs)
- CurrentServiceRecordSet = srs->uDNS_next;
- }
-#endif
-
if (m->ResourceRecords) LogInfo("mDNS_StartExit: Sending final record deregistrations");
else LogInfo("mDNS_StartExit: No deregistering records remain");
- if (m->ServiceRegistrations) LogInfo("mDNS_StartExit: Sending final uDNS service deregistrations");
- else LogInfo("mDNS_StartExit: No deregistering uDNS services remain");
-
for (rr = m->DuplicateRecords; rr; rr = rr->next)
LogMsg("mDNS_StartExit: Should not still have Duplicate Records remaining: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr));
@@ -9757,7 +10218,6 @@ mDNSexport void mDNS_FinalExit(mDNS *const m)
mDNSu32 rrcache_totalused = 0;
mDNSu32 slot;
AuthRecord *rr;
- ServiceRecordSet *srs;
LogInfo("mDNS_FinalExit: mDNSPlatformClose");
mDNSPlatformClose(m);
@@ -9786,8 +10246,5 @@ mDNSexport void mDNS_FinalExit(mDNS *const m)
for (rr = m->ResourceRecords; rr; rr = rr->next)
LogMsg("mDNS_FinalExit failed to send goodbye for: %p %02X %s", rr, rr->resrec.RecordType, ARDisplayString(m, rr));
- for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next)
- LogMsg("mDNS_FinalExit failed to deregister service: %p %##s", srs, srs->RR_SRV.resrec.name->c);
-
LogInfo("mDNS_FinalExit: done");
}
diff --git a/external/apache2/mDNSResponder/dist/mDNSCore/mDNSEmbeddedAPI.h b/external/apache2/mDNSResponder/dist/mDNSCore/mDNSEmbeddedAPI.h
index 6412ca7e691..e08015e8c53 100755
--- a/external/apache2/mDNSResponder/dist/mDNSCore/mDNSEmbeddedAPI.h
+++ b/external/apache2/mDNSResponder/dist/mDNSCore/mDNSEmbeddedAPI.h
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
-
NOTE:
If you're building an application that uses DNS Service Discovery
this is probably NOT the header file you're looking for.
@@ -50,934 +49,7 @@
you can still use the exact same client C code as you'd use on a
general-purpose desktop system.
-
- Change History (most recent first):
-
-Log: mDNSEmbeddedAPI.h,v $
-Revision 1.573 2009/06/30 18:17:45 herscher
-Add to 64 bit macro check for 64 bit Windows OSes
-
-Revision 1.572 2009/06/27 00:52:27 cheshire
-<rdar://problem/6959273> mDNSResponder taking up 13% CPU with 400 KBps incoming bonjour requests
-Removed overly-complicate and ineffective multi-packet known-answer snooping code
-(Bracketed it with "#if ENABLE_MULTI_PACKET_QUERY_SNOOPING" for now; will delete actual code later)
-
-Revision 1.571 2009/06/26 01:55:54 cheshire
-<rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
-Additional refinements -- except for the case of explicit queries for record types we don't have (for names we own),
-add additional NSEC records only when there's space to do that without having to generate an additional packet
-
-Revision 1.570 2009/06/24 22:14:21 cheshire
-<rdar://problem/6911445> Plugging and unplugging the power cable shouldn't cause a network change event
-
-Revision 1.569 2009/06/03 23:07:12 cheshire
-<rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
-Large records were not being added in cases where an NSEC record was also required
-
-Revision 1.568 2009/05/19 22:37:04 cheshire
-<rdar://problem/6903507> Sleep Proxy: Retransmission logic not working reliably on quiet networks
-Added NextScheduledSPRetry field
-
-Revision 1.567 2009/05/13 17:25:33 mkrochma
-<rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
-Sleep proxy client should only look for services being advertised via Multicast
-
-Revision 1.566 2009/05/12 23:09:24 cheshire
-<rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
-Declare mDNSCoreHaveAdvertisedServices routine so it can be called from daemon.c
-
-Revision 1.565 2009/05/09 00:10:58 jessic2
-Change expected size of NetworkInterfaceInfo to fix build failure
-
-Revision 1.564 2009/05/07 23:31:26 cheshire
-<rdar://problem/6601427> Sleep Proxy: Retransmit and retry Sleep Proxy Server requests
-Added NextSPSAttempt and NextSPSAttemptTime fields to NetworkInterfaceInfo_struct
-
-Revision 1.563 2009/04/24 21:06:38 cheshire
-Added comment about UDP length field (includes UDP header, so minimum value is 8 bytes)
-
-Revision 1.562 2009/04/24 00:22:23 cheshire
-<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
-Added definition of rdataNSEC
-
-Revision 1.561 2009/04/23 22:06:29 cheshire
-Added CacheRecord and InterfaceID parameters to MakeNegativeCacheRecord, in preparation for:
-<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
-
-Revision 1.560 2009/04/23 21:54:50 cheshire
-Updated comments
-
-Revision 1.559 2009/04/22 00:37:38 cheshire
-<rdar://problem/6814427> Remove unused kDNSType_MAC
-
-Revision 1.558 2009/04/21 23:36:25 cheshire
-<rdar://problem/6814427> Remove unused kDNSType_MAC
-
-Revision 1.557 2009/04/15 20:42:51 mcguire
-<rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
-
-Revision 1.556 2009/04/11 00:19:43 jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.555 2009/04/01 21:12:27 herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows.
-
-Revision 1.554 2009/04/01 17:50:11 mcguire
-cleanup mDNSRandom
-
-Revision 1.553 2009/03/26 03:59:00 jessic2
-Changes for <rdar://problem/6492552&6492593&6492609&6492613&6492628&6492640&6492699>
-
-Revision 1.552 2009/03/20 23:53:03 jessic2
-<rdar://problem/6646228> SIGHUP should restart all in-progress queries
-
-Revision 1.551 2009/03/18 20:41:04 cheshire
-Added definition of the all-ones mDNSOpaque16 ID
-
-Revision 1.550 2009/03/17 19:10:29 mcguire
-Fix sizechecks for x86_64
-
-Revision 1.549 2009/03/17 01:22:56 cheshire
-<rdar://problem/6601427> Sleep Proxy: Retransmit and retry Sleep Proxy Server requests
-Initial support for resolving up to three Sleep Proxies in parallel
-
-Revision 1.548 2009/03/14 01:42:56 mcguire
-<rdar://problem/5457116> BTMM: Fix issues with multiple .Mac accounts on the same machine
-
-Revision 1.547 2009/03/10 01:14:30 cheshire
-Sleep Proxies with invalid names need to be ignored (score 10000),
-not treated as "Sleep Proxy of last resort" (score 9999)
-
-Revision 1.546 2009/03/06 23:51:51 mcguire
-Fix broken build by defining DiscardPort
-
-Revision 1.545 2009/03/06 22:39:23 cheshire
-<rdar://problem/6655850> Ignore prototype base stations when picking Sleep Proxy to register with
-
-Revision 1.544 2009/03/04 01:33:30 cheshire
-Add m->ProxyRecords counter
-
-Revision 1.543 2009/03/03 23:04:43 cheshire
-For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC)
-
-Revision 1.542 2009/03/03 22:51:53 cheshire
-<rdar://problem/6504236> Sleep Proxy: Waking on same network but different interface will cause conflicts
-
-Revision 1.541 2009/03/03 00:45:19 cheshire
-Added m->PrimaryMAC field
-
-Revision 1.540 2009/02/27 02:56:57 cheshire
-Moved struct SearchListElem definition from uDNS.c into mDNSEmbeddedAPI.h
-
-Revision 1.539 2009/02/17 23:29:01 cheshire
-Throttle logging to a slower rate when running on SnowLeopard
-
-Revision 1.538 2009/02/11 02:31:57 cheshire
-Moved SystemWakeOnLANEnabled from mDNSMacOSX.h, so it's accessible to mDNSCore routines
-
-Revision 1.537 2009/02/07 02:51:48 cheshire
-<rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
-Added new functions and timing variables
-
-Revision 1.536 2009/01/30 23:50:31 cheshire
-Added LastLabel() routine to get the last label of a domainname
-
-Revision 1.535 2009/01/23 00:38:36 mcguire
-<rdar://problem/5570906> BTMM: Doesn't work with Linksys WRT54GS firmware 4.71.1
-
-Revision 1.534 2009/01/22 02:14:25 cheshire
-<rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
-
-Revision 1.533 2009/01/21 03:43:57 mcguire
-<rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore
-
-Revision 1.532 2009/01/16 19:50:36 cheshire
-Oops. Fixed definition of SleepProxyServiceType.
-
-Revision 1.531 2009/01/16 19:48:09 cheshire
-Added definition of SleepProxyServiceType
-
-Revision 1.530 2009/01/15 00:22:49 mcguire
-<rdar://problem/6437092> NAT-PMP: mDNSResponder needs to listen on 224.0.0.1:5350/UDP with REUSEPORT
-
-Revision 1.529 2009/01/13 00:31:44 cheshire
-Fixed off-by-one error in computing the implicit limit pointer in the "DomainNameLength(name)" macro
-
-Revision 1.528 2009/01/10 01:43:52 cheshire
-Changed misleading function name 'AnsweredLOQ' to more informative 'AnsweredLocalQ'
-
-Revision 1.527 2008/12/12 01:23:19 cheshire
-Added m->SPSProxyListChanged state variable to flag when we need to update our BPF filter program
-
-Revision 1.526 2008/12/12 00:51:14 cheshire
-Added structure definitions for IPv6Header, etc.
-
-Revision 1.525 2008/12/10 02:18:31 cheshire
-Increased MaxMsg to 160 for showing longer TXT records in SIGINFO output
-
-Revision 1.524 2008/12/10 01:49:39 cheshire
-Fixes for alignment issues on ARMv5
-
-Revision 1.523 2008/12/05 02:35:24 mcguire
-<rdar://problem/6107390> Write to the DynamicStore when a Sleep Proxy server is available on the network
-
-Revision 1.522 2008/12/04 21:08:51 mcguire
-<rdar://problem/6116863> mDNS: Provide mechanism to disable Multicast advertisements
-
-Revision 1.521 2008/12/04 02:19:24 cheshire
-Updated comment
-
-Revision 1.520 2008/11/26 20:28:05 cheshire
-Added new SSHPort constant
-
-Revision 1.519 2008/11/25 22:46:30 cheshire
-For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta"
-
-Revision 1.518 2008/11/25 05:07:15 cheshire
-<rdar://problem/6374328> Advertise Sleep Proxy metrics in service name
-
-Revision 1.517 2008/11/20 01:51:19 cheshire
-Exported RecreateNATMappings so it's callable from other files
-
-Revision 1.516 2008/11/16 16:49:25 cheshire
-<rdar://problem/6375808> LLQs broken in mDNSResponder-184
-DNSOpt_LLQData_Space was incorrectly defined to be 18 instead of 22
-
-Revision 1.515 2008/11/14 20:59:41 cheshire
-Added mDNSEthAddressIsZero(A) macro
-
-Revision 1.514 2008/11/14 02:17:41 cheshire
-Added NextScheduledSPS task scheduling variable
-
-Revision 1.513 2008/11/14 00:47:19 cheshire
-Added TimeRcvd and TimeExpire fields to AuthRecord_struct
-
-Revision 1.512 2008/11/14 00:00:53 cheshire
-After client machine wakes up, Sleep Proxy machine need to remove any records
-it was temporarily holding as proxy for that client
-
-Revision 1.511 2008/11/13 19:04:44 cheshire
-Added definition of OwnerOptData
-
-Revision 1.510 2008/11/06 23:48:32 cheshire
-Changed SleepProxyServerType to mDNSu8
-
-Revision 1.509 2008/11/04 23:06:50 cheshire
-Split RDataBody union definition into RDataBody and RDataBody2, and removed
-SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord
-
-Revision 1.508 2008/11/04 22:21:43 cheshire
-Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord
-
-Revision 1.507 2008/11/04 22:13:43 cheshire
-Made RDataBody parameter to GetRRDisplayString_rdb "const"
-
-Revision 1.506 2008/11/04 20:06:19 cheshire
-<rdar://problem/6186231> Change MAX_DOMAIN_NAME to 256
-
-Revision 1.505 2008/11/03 23:49:47 mkrochma
-Increase NATMAP_DEFAULT_LEASE to 2 hours so we do maintenance wake less often
-
-Revision 1.504 2008/10/31 22:55:04 cheshire
-Initial support for structured SPS names
-
-Revision 1.503 2008/10/24 23:58:47 cheshire
-Ports should be mDNSIPPort, not mDNSOpaque16
-
-Revision 1.502 2008/10/23 22:25:56 cheshire
-Renamed field "id" to more descriptive "updateid"
-
-Revision 1.501 2008/10/22 22:22:27 cheshire
-Added packet structure definitions
-
-Revision 1.500 2008/10/22 19:55:35 cheshire
-Miscellaneous fixes; renamed FindFirstAnswerInCache to FindSPSInCache
-
-Revision 1.499 2008/10/22 17:15:47 cheshire
-Updated definitions of mDNSIPv4AddressIsZero/mDNSIPv4AddressIsOnes, etc.
-
-Revision 1.498 2008/10/22 01:01:52 cheshire
-Added onesEthAddr constant, used for sending ARP broadcasts
-
-Revision 1.497 2008/10/21 00:51:11 cheshire
-Added declaration of mDNSPlatformSetBPF(), used by uds_daemon.c to pass BPF fd to mDNSMacOSX.c
-
-Revision 1.496 2008/10/16 22:38:52 cheshire
-Added declaration of mDNSCoreReceiveRawPacket()
-
-Revision 1.495 2008/10/15 22:53:51 cheshire
-Removed unused "#define LocalReverseMapDomain"
-
-Revision 1.494 2008/10/15 20:37:17 cheshire
-Added "#define DNSOpt_Lease_Space 19"
-
-Revision 1.493 2008/10/14 21:37:56 cheshire
-Removed unnecessary m->BeSleepProxyServer variable
-
-Revision 1.492 2008/10/14 20:26:36 cheshire
-Added definition of a new kDNSType_MAC rdata type
-
-Revision 1.491 2008/10/09 22:29:04 cheshire
-Added "mDNSEthAddr MAC" to NetworkInterfaceInfo_struct
-
-Revision 1.490 2008/10/09 21:39:20 cheshire
-Update list of DNS types
-
-Revision 1.489 2008/10/09 18:59:19 cheshire
-Added NetWakeResolve code, removed unused m->SendDeregistrations and m->SendImmediateAnswers
-
-Revision 1.488 2008/10/08 01:02:03 cheshire
-Added mDNS_SetupQuestion() convenience function
-
-Revision 1.487 2008/10/07 21:41:57 mcguire
-Increase sizecheck limits to account for DNSQuestion added to NetworkInterfaceInfo_struct in 64bit builds
-
-Revision 1.486 2008/10/07 15:56:24 cheshire
-Increase sizecheck limits to account for DNSQuestion added to NetworkInterfaceInfo_struct
-
-Revision 1.485 2008/10/04 00:48:37 cheshire
-Added DNSQuestion to NetworkInterfaceInfo_struct, used for browsing for Sleep Proxy Servers
-
-Revision 1.484 2008/10/04 00:01:45 cheshire
-Move NetworkInterfaceInfo_struct further down in file (we'll need to add a DNSQuestion to it later)
-
-Revision 1.483 2008/10/03 23:28:41 cheshire
-Added declaration of mDNSPlatformSendRawPacket
-
-Revision 1.482 2008/10/03 17:30:05 cheshire
-Added declaration of mDNS_ConfigChanged(mDNS *const m);
-
-Revision 1.481 2008/10/02 22:38:58 cheshire
-Added SleepProxyServer fields, and mDNSCoreBeSleepProxyServer() call for turning SleepProxyServer on and off
-
-Revision 1.480 2008/10/01 21:22:17 cheshire
-Added NetWake field to NetworkInterfaceInfo structure, to signal when Wake-On-Magic-Packet is enabled for that interface
-
-Revision 1.479 2008/09/29 20:12:37 cheshire
-Rename 'AnswerLocalQuestions' to more descriptive 'AnswerLocalOnlyQuestions' and 'AnsweredLocalQ' to 'AnsweredLOQ'
-
-Revision 1.478 2008/09/23 02:37:10 cheshire
-Added FirstLabel/SecondLabel macros
-
-Revision 1.477 2008/09/20 00:34:22 mcguire
-<rdar://problem/6129039> BTMM: Add support for WANPPPConnection
-
-Revision 1.476 2008/09/05 22:22:01 cheshire
-Move "UDPSocket *LocalSocket" field to more logical place in DNSQuestion_struct
-
-Revision 1.475 2008/07/25 22:34:11 mcguire
-fix sizecheck issues for 64bit
-
-Revision 1.474 2008/07/24 20:23:03 cheshire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-
-Revision 1.473 2008/07/18 21:37:42 mcguire
-<rdar://problem/5736845> BTMM: alternate SSDP queries between multicast & unicast
-
-Revision 1.472 2008/07/01 01:39:59 mcguire
-<rdar://problem/5823010> 64-bit fixes
-
-Revision 1.471 2008/06/26 17:24:11 mkrochma
-<rdar://problem/5450912> BTMM: Stop listening on UDP 5351 for NAT Status Announcements
-
-Revision 1.470 2008/06/19 01:20:49 mcguire
-<rdar://problem/4206534> Use all configured DNS servers
-
-Revision 1.469 2008/03/07 18:56:02 cheshire
-<rdar://problem/5777647> dnsbugtest query every three seconds when source IP address of response doesn't match
-
-Revision 1.468 2008/03/06 02:48:34 mcguire
-<rdar://problem/5321824> write status to the DS
-
-Revision 1.467 2008/02/26 20:48:46 cheshire
-Need parentheses around use of macro argument in mDNS_TimeNow_NoLock(m)
-
-Revision 1.466 2008/02/21 21:36:32 cheshire
-Updated comment about record type values (kDNSRecordTypePacketAns/Auth/Add)
-
-Revision 1.465 2008/02/20 00:39:05 mcguire
-<rdar://problem/5427102> Some device info XML blobs too large
-
-Revision 1.464 2008/01/31 23:33:29 mcguire
-<rdar://problem/5614450> changes to build using gcc 4.2 with -Werror
-
-Revision 1.463 2007/12/17 23:53:25 cheshire
-Added DNSDigest_SignMessageHostByteOrder, for signing messages not yet converted to network byte order
-
-Revision 1.462 2007/12/17 23:48:29 cheshire
-DNSDigest_SignMessage doesn't need to return a result -- it already updates the 'end' parameter
-
-Revision 1.461 2007/12/15 00:18:51 cheshire
-Renamed question->origLease to question->ReqLease
-
-Revision 1.460 2007/12/14 23:55:28 cheshire
-Moved "struct tcpInfo_t" definition from uDNS.c to mDNSEmbeddedAPI.h
-
-Revision 1.459 2007/12/07 22:40:34 cheshire
-Rename 'LocalAnswer' to more descriptive 'AnsweredLocalQ'
-
-Revision 1.458 2007/12/07 00:45:58 cheshire
-<rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
-
-Revision 1.457 2007/12/06 00:22:27 mcguire
-<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
-
-Revision 1.456 2007/12/05 01:45:35 cheshire
-Renamed markedForDeletion -> MarkedForDeletion
-
-Revision 1.455 2007/12/01 01:21:27 jgraessley
-<rdar://problem/5623140> mDNSResponder unicast DNS improvements
-
-Revision 1.454 2007/12/01 00:34:03 cheshire
-Fixes from Bob Bradley for building on EFI
-
-Revision 1.453 2007/10/29 23:51:22 cheshire
-Added comment about NATTraversalInfo ExternalAddress field
-
-Revision 1.452 2007/10/29 18:13:40 cheshire
-Added Question_uDNS macro, analogous to AuthRecord_uDNS macro
-
-Revision 1.451 2007/10/26 23:42:57 cheshire
-Removed unused "mDNSs32 expire" field from ServiceRecordSet_struct
-
-Revision 1.450 2007/10/26 22:24:08 cheshire
-Added AuthRecord_uDNS() macro to determine when a given AuthRecord needs to be registered via unicast DNS
-
-Revision 1.449 2007/10/25 20:48:47 cheshire
-For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
-
-Revision 1.448 2007/10/22 22:19:44 cheshire
-Tidied up code alignment
-
-Revision 1.447 2007/10/22 19:40:30 cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-Made subroutine mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst)
-
-Revision 1.446 2007/10/17 22:49:54 cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-
-Revision 1.445 2007/10/17 22:37:23 cheshire
-<rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
-
-Revision 1.444 2007/09/29 03:14:52 cheshire
-<rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
-Added AutoTunnelUnregistered macro to check state of DomainAuthInfo AuthRecords
-
-Revision 1.443 2007/09/27 21:21:39 cheshire
-Export CompleteDeregistration so it's callable from other files
-
-Revision 1.442 2007/09/27 00:25:39 cheshire
-Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
-<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
-
-Revision 1.441 2007/09/26 23:17:49 cheshire
-Get rid of unused kWideAreaTTL constant
-
-Revision 1.440 2007/09/26 22:06:02 cheshire
-<rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
-
-Revision 1.439 2007/09/21 21:12:36 cheshire
-DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter
-
-Revision 1.438 2007/09/19 20:32:09 cheshire
-Export GetAuthInfoForName so it's callable from other files
-
-Revision 1.437 2007/09/18 21:42:29 cheshire
-To reduce programming mistakes, renamed ExtPort to RequestedPort
-
-Revision 1.436 2007/09/14 21:26:08 cheshire
-<rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
-
-Revision 1.435 2007/09/13 00:16:41 cheshire
-<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
-
-Revision 1.434 2007/09/12 23:03:07 cheshire
-<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
-
-Revision 1.433 2007/09/12 22:19:28 cheshire
-<rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
-
-Revision 1.432 2007/09/12 19:22:19 cheshire
-Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
-Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
-
-Revision 1.431 2007/09/11 19:19:16 cheshire
-Correct capitalization of "uPNP" to "UPnP"
-
-Revision 1.430 2007/09/10 22:06:50 cheshire
-Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
-
-Revision 1.429 2007/09/07 21:16:58 cheshire
-Add new symbol "NATPMPAnnouncementPort" (5350)
-
-Revision 1.428 2007/09/05 21:48:01 cheshire
-<rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
-Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code needs
-to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
-otherwise those records will expire and vanish from the cache.
-
-Revision 1.427 2007/09/05 20:47:12 cheshire
-Tidied up alignment of code layout
-
-Revision 1.426 2007/09/04 20:37:06 cheshire
-<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
-Reorder fields into more logical order, with AuthInfo before DuplicateOf
-
-Revision 1.425 2007/08/31 19:53:14 cheshire
-<rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
-If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
-
-Revision 1.424 2007/08/31 18:49:49 vazquez
-<rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
-
-Revision 1.423 2007/08/31 00:04:28 cheshire
-Added comment explaining deltime in DomainAuthInfo structure
-
-Revision 1.422 2007/08/28 23:58:42 cheshire
-Rename HostTarget -> AutoTarget
-
-Revision 1.421 2007/08/27 20:30:43 cheshire
-Only include TunnelClients list when building for OS X
-
-Revision 1.420 2007/08/23 21:47:09 vazquez
-<rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
-make sure we clean up port mappings on base stations by sending a lease value of 0,
-and only send NAT-PMP packets on private networks; also save some memory by
-not using packet structs in NATTraversals.
-
-Revision 1.419 2007/08/08 21:07:47 vazquez
-<rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
-
-Revision 1.418 2007/08/01 16:09:13 cheshire
-Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
-
-Revision 1.417 2007/08/01 03:04:59 cheshire
-Add NATTraversalInfo structures to HostnameInfo and DomainAuthInfo
-
-Revision 1.416 2007/08/01 00:04:13 cheshire
-<rdar://problem/5261696> Crash in tcpKQSocketCallback
-Half-open TCP connections were not being cancelled properly
-
-Revision 1.415 2007/07/31 02:28:35 vazquez
-<rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
-
-Revision 1.414 2007/07/30 23:34:19 cheshire
-Remove unused "udpSock" from DNSQuestion
-
-Revision 1.413 2007/07/28 01:25:56 cheshire
-<rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
-
-Revision 1.412 2007/07/27 23:57:23 cheshire
-Added compile-time structure size checks
-
-Revision 1.411 2007/07/27 22:50:08 vazquez
-Allocate memory for UPnP request and reply buffers instead of using arrays
-
-Revision 1.410 2007/07/27 19:37:19 cheshire
-Moved AutomaticBrowseDomainQ into main mDNS object
-
-Revision 1.409 2007/07/27 19:30:39 cheshire
-Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
-to properly reflect tri-state nature of the possible responses
-
-Revision 1.408 2007/07/27 18:44:01 cheshire
-Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
-
-Revision 1.407 2007/07/26 21:19:26 vazquez
-Retry port mapping with incremented port number (up to max) in order to handle
-port mapping conflicts on UPnP gateways
-
-Revision 1.406 2007/07/25 22:19:59 cheshire
-ClientTunnel structure also needs a rmt_outer_port field
-
-Revision 1.405 2007/07/25 03:05:02 vazquez
-Fixes for:
-<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
-<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
-and a myriad of other security problems
-
-Revision 1.404 2007/07/24 20:22:07 cheshire
-Add AutoTunnelHostAddrActive flag
-
-Revision 1.403 2007/07/24 04:14:29 cheshire
-<rdar://problem/5356281> LLQs not working in with NAT Traversal
-
-Revision 1.402 2007/07/21 00:54:44 cheshire
-<rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
-
-Revision 1.401 2007/07/20 20:01:38 cheshire
-Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
-
-Revision 1.400 2007/07/20 00:54:18 cheshire
-<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-
-Revision 1.399 2007/07/18 03:22:35 cheshire
-SetupLocalAutoTunnelInterface_internal needs to be callable from uDNS.c
-
-Revision 1.398 2007/07/18 02:26:56 cheshire
-Don't need to declare UpdateTunnels here
-
-Revision 1.397 2007/07/18 01:03:50 cheshire
-<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
-Add list of client tunnels so we can automatically reconfigure when local address changes
-
-Revision 1.396 2007/07/16 23:54:48 cheshire
-<rdar://problem/5338850> Crash when removing or changing DNS keys
-
-Revision 1.395 2007/07/16 20:12:33 vazquez
-<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
-
-Revision 1.394 2007/07/12 02:51:27 cheshire
-<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
-
-Revision 1.393 2007/07/11 23:43:42 cheshire
-Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
-
-Revision 1.392 2007/07/11 22:44:40 cheshire
-<rdar://problem/5328801> SIGHUP should purge the cache
-
-Revision 1.391 2007/07/11 20:30:45 cheshire
-<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
-Added AutoTunnelTarget and AutoTunnelService to DomainAuthInfo structure
-
-Revision 1.390 2007/07/11 18:56:55 cheshire
-Added comments about AutoTunnelHostAddr and AutoTunnelLabel
-
-Revision 1.389 2007/07/11 02:44:03 cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-Added AutoTunnel fields to structures
-
-Revision 1.388 2007/07/10 01:53:18 cheshire
-<rdar://problem/5196524> uDNS: mDNSresponder is leaking TCP connections to DNS server
-AuthRecord, ServiceRecordSet, and DNSQuestion structures need tcpInfo_t pointers
-so they can keep track of what TCP connections they open
-
-Revision 1.387 2007/07/06 18:55:15 cheshire
-Add explicit NextScheduledNATOp scheduling variable
-
-Revision 1.386 2007/07/03 20:54:11 cheshire
-Tidied up code layout of NATTraversalInfo_struct fields and comments
-
-Revision 1.385 2007/07/03 00:40:23 vazquez
-More changes for <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-Safely deal with packet replies and client callbacks
-
-Revision 1.384 2007/06/29 00:08:07 vazquez
-<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-
-Revision 1.383 2007/06/20 01:10:12 cheshire
-<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-
-Revision 1.382 2007/06/19 20:31:59 cheshire
-Add DNSServer_Disabled state
-Add mDNSInterfaceID for DNS servers reachable over specific interfaces
-
-Revision 1.381 2007/06/15 18:11:16 cheshire
-<rdar://problem/5174466> mDNSResponder crashed in memove() near end of MobileSafari stress test
-Made AssignDomainName more defensive when source name is garbage
-
-Revision 1.380 2007/05/25 00:04:51 cheshire
-Added comment explaining rdlength
-
-Revision 1.379 2007/05/21 18:04:40 cheshire
-Updated comments -- port_mapping_create_reply renamed to port_mapping_reply
-
-Revision 1.378 2007/05/17 19:11:46 cheshire
-Tidy up code layout
-
-Revision 1.377 2007/05/15 00:43:33 cheshire
-Remove unused regState_Cancelled
-
-Revision 1.376 2007/05/14 23:51:49 cheshire
-Added constants MAX_REVERSE_MAPPING_NAME_V4 and MAX_REVERSE_MAPPING_NAME_V6
-
-Revision 1.375 2007/05/10 21:19:18 cheshire
-Rate-limit DNS test queries to at most one per three seconds
-(useful when we have a dozen active WAB queries, and then we join a new network)
-
-Revision 1.374 2007/05/07 22:07:47 cheshire
-<rdar://problem/4738025> Enhance GetLargeResourceRecord to decompress more record types
-
-Revision 1.373 2007/05/07 20:43:45 cheshire
-<rdar://problem/4241419> Reduce the number of queries and announcements
-
-Revision 1.372 2007/05/04 22:15:29 cheshire
-Get rid of unused q->RestartTime
-
-Revision 1.371 2007/05/03 22:40:37 cheshire
-<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
-
-Revision 1.370 2007/05/02 22:18:09 cheshire
-Renamed NATTraversalInfo_struct context to NATTraversalContext
-
-Revision 1.369 2007/05/01 21:21:42 cheshire
-Add missing parentheses in LEASE_OPT_RDLEN definition
-
-Revision 1.368 2007/04/30 21:33:38 cheshire
-Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
-is iterating through the m->ServiceRegistrations list
-
-Revision 1.367 2007/04/28 01:31:59 cheshire
-Improve debugging support for catching memory corruption problems
-
-Revision 1.366 2007/04/27 19:28:02 cheshire
-Any code that calls StartGetZoneData needs to keep a handle to the structure, so
-it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
--- it would start a query and then quickly cancel it, and then when
-StartGetZoneData completed, it had a dangling pointer and crashed.)
-
-Revision 1.365 2007/04/26 00:35:15 cheshire
-<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
-Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
-inside the firewall may give answers where a public one gives none, and vice versa.)
-
-Revision 1.364 2007/04/24 02:07:42 cheshire
-<rdar://problem/4246187> Identical client queries should reference a single shared core query
-Deleted some more redundant code
-
-Revision 1.363 2007/04/24 00:09:47 cheshire
-Remove MappedV4 field from mDNS_struct (not actually used anywhere)
-
-Revision 1.362 2007/04/22 06:02:02 cheshire
-<rdar://problem/4615977> Query should immediately return failure when no server
-
-Revision 1.361 2007/04/21 19:43:33 cheshire
-Code tidying: represent NAT opcodes as bitwise combinations rather than numerical additions
-
-Revision 1.360 2007/04/20 21:17:24 cheshire
-For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
-
-Revision 1.359 2007/04/19 22:50:53 cheshire
-<rdar://problem/4246187> Identical client queries should reference a single shared core query
-
-Revision 1.358 2007/04/19 20:06:41 cheshire
-Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
-
-Revision 1.357 2007/04/19 18:14:51 cheshire
-In mDNS_AddSearchDomain_CString check for NULL pointer before calling MakeDomainNameFromDNSNameString()
-
-Revision 1.356 2007/04/18 20:56:46 cheshire
-Added mDNS_AddSearchDomain_CString macro
-
-Revision 1.355 2007/04/17 19:21:29 cheshire
-<rdar://problem/5140339> Domain discovery not working over VPN
-
-Revision 1.354 2007/04/05 22:55:34 cheshire
-<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
-
-Revision 1.353 2007/04/05 20:40:37 cheshire
-Remove unused mDNSPlatformTCPGetFlags()
-
-Revision 1.352 2007/04/04 21:48:52 cheshire
-<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
-
-Revision 1.351 2007/04/04 01:27:45 cheshire
-Update comment
-
-Revision 1.350 2007/04/04 00:03:26 cheshire
-<rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
-
-Revision 1.349 2007/04/03 19:37:58 cheshire
-Rename mDNSAddrIsv4Private() to more precise mDNSAddrIsRFC1918()
-
-Revision 1.348 2007/04/03 19:13:39 cheshire
-Added macros mDNSSameIPPort, mDNSSameOpaque16, mDNSIPPortIsZero, mDNSOpaque16IsZero
-
-Revision 1.347 2007/03/28 20:59:26 cheshire
-<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
-
-Revision 1.346 2007/03/28 15:56:37 cheshire
-<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
-
-Revision 1.345 2007/03/22 19:29:23 cheshire
-Add comment and check to ensure StandardAuthRDSize is at least 256 bytes
-
-Revision 1.344 2007/03/22 18:31:48 cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.343 2007/03/22 00:49:20 cheshire
-<rdar://problem/4848295> Advertise model information via Bonjour
-
-Revision 1.342 2007/03/21 23:06:00 cheshire
-Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
-
-Revision 1.341 2007/03/21 20:44:11 cheshire
-Added mDNSAddressIsv4LinkLocal macro
-
-Revision 1.340 2007/03/21 00:30:02 cheshire
-<rdar://problem/4789455> Multiple errors in DNameList-related code
-
-Revision 1.339 2007/03/20 17:07:15 cheshire
-Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-
-Revision 1.338 2007/03/10 02:28:28 cheshire
-Added comment explaining NATResponseHndlr
-
-Revision 1.337 2007/03/10 02:02:58 cheshire
-<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
-Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
-
-Revision 1.336 2007/02/28 22:12:24 cheshire
-Get rid of unused mDNSVal32 and mDNSOpaque32fromIntVal
-
-Revision 1.335 2007/02/28 21:49:07 cheshire
-Off-by-one error: SameDomainLabelCS (case-sensitive) was stopping one character short of
-the end of the label, e.g. it would fail to detect that "chesh1" and "chesh2" are different.
-
-Revision 1.334 2007/02/28 01:44:26 cheshire
-<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
-
-Revision 1.333 2007/02/27 22:55:22 cheshire
-Get rid of unused AllDNSLinkGroupv4 and AllDNSLinkGroupv6
-
-Revision 1.332 2007/02/27 02:48:24 cheshire
-Parameter to LNT_GetPublicIP function is IPv4 address, not anonymous "mDNSOpaque32" object
-
-Revision 1.331 2007/02/14 03:16:39 cheshire
-<rdar://problem/4789477> Eliminate unnecessary malloc/free in mDNSCore code
-
-Revision 1.330 2007/02/08 21:12:28 cheshire
-<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
-
-Revision 1.329 2007/02/07 01:19:36 cheshire
-<rdar://problem/4849427> API: Reconcile conflicting error code values
-
-Revision 1.328 2007/01/25 00:19:40 cheshire
-Add CNAMEReferrals field to DNSQuestion_struct
-
-Revision 1.327 2007/01/23 02:56:10 cheshire
-Store negative results in the cache, instead of generating them out of pktResponseHndlr()
-
-Revision 1.326 2007/01/20 01:30:49 cheshire
-Update comments
-
-Revision 1.325 2007/01/19 18:39:11 cheshire
-Fix a bunch of parameters that should have been declared "const"
-
-Revision 1.324 2007/01/19 18:04:04 cheshire
-For naming consistency, use capital letters for RR types: rdataOpt should be rdataOPT
-
-Revision 1.323 2007/01/17 21:46:02 cheshire
-Remove redundant duplicated "isPrivate" field from LLQ_Info
-
-Revision 1.322 2007/01/10 22:51:56 cheshire
-<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
-
-Revision 1.321 2007/01/09 22:37:18 cheshire
-Provide ten-second grace period for deleted keys, to give mDNSResponder
-time to delete host name before it gives up access to the required key.
-
-Revision 1.320 2007/01/05 08:30:41 cheshire
-Trim excessive "Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.319 2007/01/04 23:11:11 cheshire
-<rdar://problem/4720673> uDNS: Need to start caching unicast records
-When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
-
-Revision 1.318 2007/01/04 20:57:48 cheshire
-Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
-
-Revision 1.317 2007/01/04 02:39:53 cheshire
-<rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
-
-Revision 1.316 2006/12/22 20:59:49 cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.315 2006/12/20 04:07:35 cheshire
-Remove uDNS_info substructure from AuthRecord_struct
-
-Revision 1.314 2006/12/19 22:49:23 cheshire
-Remove uDNS_info substructure from ServiceRecordSet_struct
-
-Revision 1.313 2006/12/19 02:38:20 cheshire
-Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
-
-Revision 1.312 2006/12/19 02:18:48 cheshire
-Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
-
-Revision 1.311 2006/12/16 01:58:31 cheshire
-<rdar://problem/4720673> uDNS: Need to start caching unicast records
-
-Revision 1.310 2006/12/15 19:09:56 cheshire
-<rdar://problem/4769083> ValidateRData() should be stricter about malformed MX and SRV records
-Made DomainNameLength() more defensive by adding a limit parameter, so it can be
-safely used to inspect potentially malformed data received from external sources.
-Without this, a domain name that starts off apparently valid, but extends beyond the end of
-the received packet data, could have appeared valid if the random bytes are already in memory
-beyond the end of the packet just happened to have reasonable values (e.g. all zeroes).
-
-Revision 1.309 2006/12/14 03:02:37 cheshire
-<rdar://problem/4838433> Tools: dns-sd -G 0 only returns IPv6 when you have a routable IPv6 address
-
-Revision 1.308 2006/11/30 23:07:56 herscher
-<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
-
-Revision 1.307 2006/11/18 05:01:30 cheshire
-Preliminary support for unifying the uDNS and mDNS code,
-including caching of uDNS answers
-
-Revision 1.306 2006/11/10 07:44:04 herscher
-<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
-
-Revision 1.305 2006/11/10 00:54:15 cheshire
-<rdar://problem/4816598> Changing case of Computer Name doesn't work
-
-Revision 1.304 2006/10/20 05:35:05 herscher
-<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
-
-Revision 1.303 2006/10/04 21:37:33 herscher
-Remove uDNS_info substructure from DNSQuestion_struct
-
-Revision 1.302 2006/09/26 01:53:25 herscher
-<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
-
-Revision 1.301 2006/09/15 21:20:15 cheshire
-Remove uDNS_info substructure from mDNS_struct
-
-Revision 1.300 2006/08/14 23:24:23 cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.299 2006/07/15 02:01:28 cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Fix broken "empty string" browsing
-
-Revision 1.298 2006/07/05 22:55:03 cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Need Private field in uDNS_RegInfo
-
-Revision 1.297 2006/07/05 22:20:03 cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-
-Revision 1.296 2006/06/29 05:28:01 cheshire
-Added comment about mDNSlocal and mDNSexport
-
-Revision 1.295 2006/06/29 03:02:43 cheshire
-<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
-
-Revision 1.294 2006/06/28 06:50:08 cheshire
-In future we may want to change definition of mDNSs32 from "signed long" to "signed int"
-I doubt anyone is building mDNSResponder on systems where int is 16-bits,
-but lets add a compile-time assertion to make sure.
-
-Revision 1.293 2006/06/12 18:00:43 cheshire
-To make code a little more defensive, check _ILP64 before _LP64,
-in case both are set by mistake on some platforms
-
-Revision 1.292 2006/03/19 17:00:57 cheshire
-Define symbol MaxMsg instead of using hard-coded constant value '80'
-
-Revision 1.291 2006/03/19 02:00:07 cheshire
-<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-
-Revision 1.290 2006/03/08 22:42:23 cheshire
-Fix spelling mistake: LocalReverseMapomain -> LocalReverseMapDomain
-
-Revision 1.289 2006/02/26 00:54:41 cheshire
-Fixes to avoid code generation warning/error on FreeBSD 7
-
-*/
+ */
#ifndef __mDNSClientAPI_h
#define __mDNSClientAPI_h
@@ -1207,6 +279,12 @@ typedef mDNSOpaque32 mDNSv4Addr; // An IP address is a four-byte opaque identi
typedef mDNSOpaque128 mDNSv6Addr; // An IPv6 address is a 16-byte opaque identifier (not an integer)
typedef mDNSOpaque48 mDNSEthAddr; // An Ethernet address is a six-byte opaque identifier (not an integer)
+// Bit operations for opaque 64 bit quantity. Uses the 32 bit quantity(l[2]) to set and clear bits
+#define mDNSNBBY 8
+#define bit_set_opaque64(op64, index) (op64.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] |= (1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY))))
+#define bit_clr_opaque64(op64, index) (op64.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] &= ~(1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY))))
+#define bit_get_opaque64(op64, index) (op64.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] & (1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY))))
+
enum
{
mDNSAddrType_None = 0,
@@ -1215,6 +293,13 @@ enum
mDNSAddrType_Unknown = ~0 // Special marker value used in known answer list recording
};
+enum
+ {
+ mDNSTransport_None = 0,
+ mDNSTransport_UDP = 1,
+ mDNSTransport_TCP = 2
+ };
+
typedef struct
{
mDNSs32 type;
@@ -1286,7 +371,8 @@ typedef mDNSs32 mStatus;
#define MAX_DOMAIN_LABEL 63
typedef struct { mDNSu8 c[ 64]; } domainlabel; // One label: length byte and up to 63 characters
-// RFC 1034/1035/2181 specify that a domain name, including length bytes, data bytes, and terminating zero, may be up to 256 bytes long
+// RFC 1034/1035/2181 specify that a domain name (length bytes and data bytes) may be up to 255 bytes long,
+// plus the terminating zero at the end makes 256 bytes total in the on-the-wire format.
#define MAX_DOMAIN_NAME 256
typedef struct { mDNSu8 c[256]; } domainname; // Up to 256 bytes of length-prefixed domainlabels
@@ -1323,6 +409,18 @@ typedef struct { mDNSu8 c[256]; } UTF8str255; // Null-terminated C string
#define kStandardTTL (3600UL * 100 / 80)
#define kHostNameTTL 120UL
+// Multicast DNS uses announcements (gratuitous responses) to update peer caches.
+// This means it is feasible to use relatively larger TTL values than we might otherwise
+// use, because we have a cache coherency protocol to keep the peer caches up to date.
+// With Unicast DNS, once an authoritative server gives a record with a certain TTL value to a client
+// or caching server, that client or caching server is entitled to hold onto the record until its TTL
+// expires, and has no obligation to contact the authoritative server again until that time arrives.
+// This means that whereas Multicast DNS can use announcements to pre-emptively update stale data
+// before it would otherwise have expired, standard Unicast DNS (not using LLQs) has no equivalent
+// mechanism, and TTL expiry is the *only* mechanism by which stale data gets deleted. Because of this,
+// we currently limit the TTL to ten seconds in such cases where no dynamic cache updating is possible.
+#define kStaticCacheTTL 10
+
#define DefaultTTLforRRType(X) (((X) == kDNSType_A || (X) == kDNSType_AAAA || (X) == kDNSType_SRV) ? kHostNameTTL : kStandardTTL)
typedef struct AuthRecord_struct AuthRecord;
@@ -1378,10 +476,10 @@ typedef struct tcpInfo_t
DNSMessage request;
int requestLen;
DNSQuestion *question; // For queries
- ServiceRecordSet *srs; // For service record updates
AuthRecord *rr; // For record updates
mDNSAddr Addr;
mDNSIPPort Port;
+ mDNSIPPort SrcPort;
DNSMessage *reply;
mDNSu16 replylen;
unsigned long nread;
@@ -1422,7 +520,7 @@ typedef packedstruct
mDNSOpaque16 id;
mDNSOpaque16 flagsfrags;
mDNSu8 ttl;
- mDNSu8 protocol;
+ mDNSu8 protocol; // Payload type: 0x06 = TCP, 0x11 = UDP
mDNSu16 checksum;
mDNSv4Addr src;
mDNSv4Addr dst;
@@ -1432,7 +530,7 @@ typedef packedstruct
{
mDNSu32 vcf; // Version, Traffic Class, Flow Label
mDNSu16 len; // Payload Length
- mDNSu8 protocol; // Type of next header: 0x06 = TCP, 0x11 = UDP, 0x3A = ICMPv6
+ mDNSu8 pro; // Type of next header: 0x06 = TCP, 0x11 = UDP, 0x3A = ICMPv6
mDNSu8 ttl; // Hop Limit
mDNSv6Addr src;
mDNSv6Addr dst;
@@ -1440,20 +538,19 @@ typedef packedstruct
typedef packedstruct
{
- mDNSu8 type; // 0x87 == Neighbor Solicitation, 0x88 == Neighbor Advertisement
- mDNSu8 code;
- mDNSu16 checksum;
- mDNSu32 reserved;
- mDNSv6Addr target;
- } IPv6ND; // 24 bytes
+ mDNSv6Addr src;
+ mDNSv6Addr dst;
+ mDNSOpaque32 len;
+ mDNSOpaque32 pro;
+ } IPv6PseudoHeader; // 40 bytes
-typedef packedstruct
+typedef union
{
- mDNSIPPort src;
- mDNSIPPort dst;
- mDNSu16 len; // Length including UDP header (ie. minimum value is 8 bytes)
- mDNSu16 checksum;
- } UDPHeader; // 8 bytes
+ mDNSu8 bytes[20];
+ ARP_EthIP arp;
+ IPv4Header v4;
+ IPv6Header v6;
+ } NetworkLayerPacket;
typedef packedstruct
{
@@ -1466,7 +563,55 @@ typedef packedstruct
mDNSu16 window;
mDNSu16 checksum;
mDNSu16 urgent;
- } TCPHeader; // 20 bytes
+ } TCPHeader; // 20 bytes; IP protocol type 0x06
+
+typedef packedstruct
+ {
+ mDNSIPPort src;
+ mDNSIPPort dst;
+ mDNSu16 len; // Length including UDP header (i.e. minimum value is 8 bytes)
+ mDNSu16 checksum;
+ } UDPHeader; // 8 bytes; IP protocol type 0x11
+
+typedef packedstruct
+ {
+ mDNSu8 type; // 0x87 == Neighbor Solicitation, 0x88 == Neighbor Advertisement
+ mDNSu8 code;
+ mDNSu16 checksum;
+ mDNSu32 flags_res; // R/S/O flags and reserved bits
+ mDNSv6Addr target;
+ // Typically 8 bytes of options are also present
+ } IPv6NDP; // 24 bytes or more; IP protocol type 0x3A
+
+#define NDP_Sol 0x87
+#define NDP_Adv 0x88
+
+#define NDP_Router 0x80
+#define NDP_Solicited 0x40
+#define NDP_Override 0x20
+
+#define NDP_SrcLL 1
+#define NDP_TgtLL 2
+
+typedef union
+ {
+ mDNSu8 bytes[20];
+ TCPHeader tcp;
+ UDPHeader udp;
+ IPv6NDP ndp;
+ } TransportLayerPacket;
+
+typedef packedstruct
+ {
+ mDNSOpaque64 InitiatorCookie;
+ mDNSOpaque64 ResponderCookie;
+ mDNSu8 NextPayload;
+ mDNSu8 Version;
+ mDNSu8 ExchangeType;
+ mDNSu8 Flags;
+ mDNSOpaque32 MessageID;
+ mDNSu32 Length;
+ } IKEHeader; // 28 bytes
// ***************************************************************************
#if 0
@@ -1541,7 +686,9 @@ enum
kDNSRecordTypeKnownUnique = 0x20, // Known Unique means mDNS can assume name is unique without checking
// For Dynamic Update records, Known Unique means the record must already exist on the server.
kDNSRecordTypeUniqueMask = (kDNSRecordTypeUnique | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique),
- kDNSRecordTypeActiveMask = (kDNSRecordTypeAdvisory | kDNSRecordTypeShared | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique),
+ kDNSRecordTypeActiveSharedMask = (kDNSRecordTypeAdvisory | kDNSRecordTypeShared),
+ kDNSRecordTypeActiveUniqueMask = (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique),
+ kDNSRecordTypeActiveMask = (kDNSRecordTypeActiveSharedMask | kDNSRecordTypeActiveUniqueMask),
kDNSRecordTypePacketAdd = 0x80, // Received in the Additional Section of a DNS Response
kDNSRecordTypePacketAddUnique = 0x90, // Received in the Additional Section of a DNS Response with kDNSClass_UniqueRRSet set
@@ -1552,7 +699,7 @@ enum
kDNSRecordTypePacketNegative = 0xF0, // Pseudo-RR generated to cache non-existence results like NXDomain
- kDNSRecordTypePacketUniqueMask = 0x10 // True for PacketAddUnique, PacketAnsUnique, PacketAuthUnique
+ kDNSRecordTypePacketUniqueMask = 0x10 // True for PacketAddUnique, PacketAnsUnique, PacketAuthUnique, kDNSRecordTypePacketNegative
};
typedef packedstruct { mDNSu16 priority; mDNSu16 weight; mDNSIPPort port; domainname target; } rdataSRV;
@@ -1625,16 +772,12 @@ typedef packedstruct
(X) == DNSOpt_OwnerData_ID_Wake_PW4_Space - 4 || \
(X) == DNSOpt_OwnerData_ID_Wake_PW6_Space - 4 )
-#define ValidDNSOpt(O) (((O)->opt == kDNSOpt_LLQ && (O)->optlen == DNSOpt_LLQData_Space - 4) || \
- ((O)->opt == kDNSOpt_Lease && (O)->optlen == DNSOpt_LeaseData_Space - 4) || \
- ((O)->opt == kDNSOpt_Owner && ValidOwnerLength((O)->optlen) ) )
-
-#define DNSOpt_Owner_Space(O) (mDNSSameEthAddress(&(O)->u.owner.HMAC, &(O)->u.owner.IMAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space)
+#define DNSOpt_Owner_Space(A,B) (mDNSSameEthAddress((A),(B)) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space)
#define DNSOpt_Data_Space(O) ( \
(O)->opt == kDNSOpt_LLQ ? DNSOpt_LLQData_Space : \
(O)->opt == kDNSOpt_Lease ? DNSOpt_LeaseData_Space : \
- (O)->opt == kDNSOpt_Owner ? DNSOpt_Owner_Space(O) : 0x10000)
+ (O)->opt == kDNSOpt_Owner ? DNSOpt_Owner_Space(&(O)->u.owner.HMAC, &(O)->u.owner.IMAC) : 0x10000)
// A maximal NSEC record is:
// 256 bytes domainname 'nextname'
@@ -1669,15 +812,15 @@ typedef struct
// On 64-bit, the pointers in a CacheRecord are bigger, and that creates 8 bytes more space for the name in a CacheGroup
#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
#if defined(_ILP64) || defined(__ILP64__) || defined(_LP64) || defined(__LP64__) || defined(_WIN64)
- #define InlineCacheGroupNameSize 152
+ #define InlineCacheGroupNameSize 160
#else
- #define InlineCacheGroupNameSize 144
+ #define InlineCacheGroupNameSize 148
#endif
#else
#if defined(_ILP64) || defined(__ILP64__) || defined(_LP64) || defined(__LP64__) || defined(_WIN64)
- #define InlineCacheGroupNameSize 136
+ #define InlineCacheGroupNameSize 144
#else
- #define InlineCacheGroupNameSize 128
+ #define InlineCacheGroupNameSize 132
#endif
#endif
@@ -1737,7 +880,7 @@ typedef void mDNSRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus res
// Restrictions: An mDNSRecordUpdateCallback may not make any mDNS API calls.
// The intent of this callback is to allow the client to free memory, if necessary.
// The internal data structures of the mDNS code may not be in a state where mDNS API calls may be made safely.
-typedef void mDNSRecordUpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData);
+typedef void mDNSRecordUpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData, mDNSu16 OldRDLen);
// ***************************************************************************
#if 0
@@ -1829,9 +972,9 @@ struct tcpLNTInfo_struct
LNTOp_t op; // operation performed using this connection
mDNSAddr Address; // router address
mDNSIPPort Port; // router port
- mDNSs8 *Request; // xml request to router
+ mDNSu8 *Request; // xml request to router
int requestLen;
- mDNSs8 *Reply; // xml reply from router
+ mDNSu8 *Reply; // xml reply from router
int replyLen;
unsigned long nread; // number of bytes read so far
int retries; // number of times we've tried to do this port mapping
@@ -1882,6 +1025,36 @@ struct NATTraversalInfo_struct
void *clientContext;
};
+enum
+ {
+ DNSServer_Untested = 0,
+ DNSServer_Passed = 1,
+ DNSServer_Failed = 2,
+ DNSServer_Disabled = 3
+ };
+
+enum
+ {
+ DNSServer_FlagDelete = 1,
+ DNSServer_FlagNew = 2
+ };
+
+typedef struct DNSServer
+ {
+ struct DNSServer *next;
+ mDNSInterfaceID interface; // For specialized uses; we can have DNS servers reachable over specific interfaces
+ mDNSAddr addr;
+ mDNSIPPort port;
+ mDNSOpaque16 testid;
+ mDNSu32 flags; // Set when we're planning to delete this from the list
+ mDNSu32 teststate; // Have we sent bug-detection query to this server?
+ mDNSs32 lasttest; // Time we sent last bug-detection query to this server
+ domainname domain; // name->server matching for "split dns"
+ mDNSs32 penaltyTime; // amount of time this server is penalized
+ mDNSBool scoped; // interface should be matched against question only
+ // if scoped is set
+ } DNSServer;
+
typedef struct // Size is 36 bytes when compiling for 32-bit; 48 when compiling for 64-bit
{
mDNSu8 RecordType; // See enum above
@@ -1907,24 +1080,22 @@ typedef struct // Size is 36 bytes when compiling for 32-bit; 48 when comp
// that are interface-specific (e.g. address records, especially linklocal addresses)
const domainname *name;
RData *rdata; // Pointer to storage for this rdata
+ DNSServer *rDNSServer; // Unicast DNS server authoritative for this entry;null for multicast
} ResourceRecord;
// Unless otherwise noted, states may apply to either independent record registrations or service registrations
typedef enum
{
regState_Zero = 0,
- regState_FetchingZoneData = 1, // getting info - update not sent
- regState_Pending = 2, // update sent, reply not received
- regState_Registered = 3, // update sent, reply received
- regState_DeregPending = 4, // dereg sent, reply not received
- regState_DeregDeferred = 5, // dereg requested while in Pending state - send dereg AFTER registration is confirmed
- regState_Unregistered = 8, // not in any list
- regState_Refresh = 9, // outstanding refresh (or target change) message
- regState_NATMap = 10, // establishing NAT port mapping (service registrations only)
- regState_UpdatePending = 11, // update in flight as result of mDNS_Update call
- regState_NoTarget = 12, // service registration pending registration of hostname (ServiceRegistrations only)
- regState_ExtraQueued = 13, // extra record to be registered upon completion of service registration (RecordRegistrations only)
- regState_NATError = 14 // unable to complete NAT traversal
+ regState_Pending = 1, // update sent, reply not received
+ regState_Registered = 2, // update sent, reply received
+ regState_DeregPending = 3, // dereg sent, reply not received
+ regState_Unregistered = 4, // not in any list
+ regState_Refresh = 5, // outstanding refresh (or target change) message
+ regState_NATMap = 6, // establishing NAT port mapping
+ regState_UpdatePending = 7, // update in flight as result of mDNS_Update call
+ regState_NoTarget = 8, // SRV Record registration pending registration of hostname
+ regState_NATError = 9 // unable to complete NAT traversal
} regState_t;
enum
@@ -1934,6 +1105,12 @@ enum
Target_AutoHostAndNATMAP = 2
};
+typedef enum
+ {
+ mergeState_Zero = 0,
+ mergeState_DontMerge = 1 // Set on fatal error conditions to disable merging
+ } mergeState_t;
+
struct AuthRecord_struct
{
// For examples of how to set up this structure for use in mDNS_Register(),
@@ -1956,11 +1133,10 @@ struct AuthRecord_struct
mDNSu8 AllowRemoteQuery; // Set if we allow hosts not on the local link to query this record
mDNSu8 ForceMCast; // Set by client to advertise solely via multicast, even for apparently unicast names
- OwnerOptData WakeUp; // Fpr Sleep Proxy records, MAC address of original owner (so we can wake it)
+ OwnerOptData WakeUp; // WakeUp.HMAC.l[0] nonzero indicates that this is a Sleep Proxy record
mDNSAddr AddressProxy; // For reverse-mapping Sleep Proxy PTR records, address in question
mDNSs32 TimeRcvd; // In platform time units
mDNSs32 TimeExpire; // In platform time units
-
// Field Group 3: Transient state for Authoritative Records
mDNSu8 Acknowledged; // Set if we've given the success callback to the client
@@ -2003,15 +1179,17 @@ struct AuthRecord_struct
mDNSBool Private; // If zone is private, DNS updates may have to be encrypted to prevent eavesdropping
mDNSOpaque16 updateid; // Identifier to match update request and response -- also used when transferring records to Sleep Proxy
const domainname *zone; // the zone that is updated
- mDNSAddr UpdateServer; // DNS server that handles updates for this zone
- mDNSIPPort UpdatePort; // port on which server accepts dynamic updates
- // !!!KRS not technically correct to cache longer than TTL
- // SDC Perhaps should keep a reference to the relevant SRV record in the cache?
ZoneData *nta;
struct tcpInfo_t *tcp;
+ NATTraversalInfo NATinfo;
+ mDNSBool SRVChanged; // temporarily deregistered service because its SRV target or port changed
+ mergeState_t mState; // Unicast Record Registrations merge state
+ mDNSu8 refreshCount; // Number of refreshes to the server
+ mStatus updateError; // Record update resulted in Error ?
// uDNS_UpdateRecord support fields
// Do we really need all these in *addition* to NewRData and newrdlength above?
+ void *UpdateContext; // Context parameter for the update callback function
mDNSu16 OrigRDLen; // previously registered, being deleted
mDNSu16 InFlightRDLen; // currently being registered
mDNSu16 QueuedRDLen; // pending operation (re-transmitting if necessary) THEN register the queued update
@@ -2027,8 +1205,27 @@ struct AuthRecord_struct
// DO NOT ADD ANY MORE FIELDS HERE
};
+// IsLocalDomain alone is not sufficient to determine that a record is mDNS or uDNS. By default domain names within
+// the "local" pseudo-TLD (and within the IPv4 and IPv6 link-local reverse mapping domains) are automatically treated
+// as mDNS records, but it is also possible to force any record (even those not within one of the inherently local
+// domains) to be handled as an mDNS record by setting the ForceMCast flag, or by setting a non-zero InterfaceID.
+// For example, the reverse-mapping PTR record created in AdvertiseInterface sets the ForceMCast flag, since it points to
+// a dot-local hostname, and therefore it would make no sense to register this record with a wide-area Unicast DNS server.
+// The same applies to Sleep Proxy records, which we will answer for when queried via mDNS, but we never want to try
+// to register them with a wide-area Unicast DNS server -- and we probably don't have the required credentials anyway.
+// Currently we have no concept of a wide-area uDNS record scoped to a particular interface, so if the InterfaceID is
+// nonzero we treat this the same as ForceMCast.
+// Note: Question_uDNS(Q) is used in *only* one place -- on entry to mDNS_StartQuery_internal, to decide whether to set TargetQID.
+// Everywhere else in the code, the determination of whether a question is unicast is made by checking to see if TargetQID is nonzero.
#define AuthRecord_uDNS(R) ((R)->resrec.InterfaceID == mDNSInterface_Any && !(R)->ForceMCast && !IsLocalDomain((R)->resrec.name))
-#define Question_uDNS(Q) ((Q)->InterfaceID == mDNSInterface_Any && !(Q)->ForceMCast && !IsLocalDomain(&(Q)->qname))
+#define Question_uDNS(Q) ((Q)->InterfaceID == mDNSInterface_Unicast || \
+ ((Q)->InterfaceID != mDNSInterface_LocalOnly && (Q)->InterfaceID != mDNSInterface_P2P && !(Q)->ForceMCast && !IsLocalDomain(&(Q)->qname)))
+
+// Question (A or AAAA) that is suppressed currently because IPv4 or IPv6 address
+// is not available locally for A or AAAA question respectively
+#define QuerySuppressed(Q) ((Q)->SuppressUnusable && (Q)->SuppressQuery)
+
+#define PrivateQuery(Q) ((Q)->AuthInfo && (Q)->AuthInfo->AutoTunnel)
// Wrapper struct for Auth Records for higher-level code that cannot use the AuthRecord's ->next pointer field
typedef struct ARListElem
@@ -2059,7 +1256,7 @@ struct CacheRecord_struct
mDNSs32 DelayDelivery; // Set if we want to defer delivery of this answer to local clients
mDNSs32 NextRequiredQuery; // In platform time units
mDNSs32 LastUsed; // In platform time units
- DNSQuestion *CRActiveQuestion; // Points to an active question referencing this answer
+ DNSQuestion *CRActiveQuestion; // Points to an active question referencing this answer. Can never point to a NewQuestion.
mDNSu32 UnansweredQueries; // Number of times we've issued a query for this record without getting an answer
mDNSs32 LastUnansweredTime; // In platform time units; last time we incremented UnansweredQueries
#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
@@ -2096,33 +1293,6 @@ typedef struct HostnameInfo
const void *StatusContext; // Client Context
} HostnameInfo;
-enum
- {
- DNSServer_Untested = 0,
- DNSServer_Passed = 1,
- DNSServer_Failed = 2,
- DNSServer_Disabled = 3
- };
-
-enum
- {
- DNSServer_FlagDelete = 1,
- DNSServer_FlagNew = 2
- };
-
-typedef struct DNSServer
- {
- struct DNSServer *next;
- mDNSInterfaceID interface; // For specialized uses; we can have DNS servers reachable over specific interfaces
- mDNSAddr addr;
- mDNSIPPort port;
- mDNSOpaque16 testid;
- mDNSu32 flags; // Set when we're planning to delete this from the list
- mDNSu32 teststate; // Have we sent bug-detection query to this server?
- mDNSs32 lasttest; // Time we sent last bug-detection query to this server
- domainname domain; // name->server matching for "split dns"
- } DNSServer;
-
typedef struct ExtraResourceRecord_struct ExtraResourceRecord;
struct ExtraResourceRecord_struct
{
@@ -2137,49 +1307,21 @@ struct ExtraResourceRecord_struct
// Note: Within an mDNSServiceCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute()
typedef void mDNSServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result);
-// A ServiceRecordSet is basically a convenience structure to group together
-// the PTR/SRV/TXT records that make up a standard service registration
-// It contains its own ServiceCallback+ServiceContext to report aggregate results up to the next layer of software above
+// A ServiceRecordSet has no special meaning to the core code of the Multicast DNS protocol engine;
+// it is just a convenience structure to group together the records that make up a standard service
+// registration so that they can be allocted and deallocted together as a single memory object.
+// It contains its own ServiceCallback+ServiceContext to report aggregate results up to the next layer of software above.
// It also contains:
+// * the basic PTR/SRV/TXT triplet used to represent any DNS-SD service
// * the "_services" PTR record for service enumeration
-// * the optional target host name (for proxy registrations)
// * the optional list of SubType PTR records
// * the optional list of additional records attached to the service set (e.g. iChat pictures)
-//
-// ... and a bunch of stuff related to uDNS, some of which could be simplified or eliminated
struct ServiceRecordSet_struct
{
// These internal state fields are used internally by mDNSCore; the client layer needn't be concerned with them.
// No fields need to be set up by the client prior to calling mDNS_RegisterService();
// all required data is passed as parameters to that function.
-
- // Begin uDNS info ****************
- // All of these fields should be eliminated
-
- // Note: The current uDNS code keeps an explicit list of registered services, and handles them
- // differently to how individual records are treated (this is probably a mistake). What this means is
- // that ServiceRecordSets for uDNS are kept in a linked list, whereas ServiceRecordSets for mDNS exist
- // just as a convenient placeholder to group the component records together and are not kept on any list.
- ServiceRecordSet *uDNS_next;
- regState_t state;
- mDNSBool srs_uselease; // dynamic update contains (should contain) lease option
- mDNSBool TestForSelfConflict; // on name conflict, check if we're just seeing our own orphaned records
- mDNSBool Private; // If zone is private, DNS updates may have to be encrypted to prevent eavesdropping
- ZoneData *srs_nta;
- mDNSOpaque16 id;
- domainname zone; // the zone that is updated
- mDNSAddr SRSUpdateServer; // primary name server for the record's zone !!!KRS not technically correct to cache longer than TTL
- mDNSIPPort SRSUpdatePort; // port on which server accepts dynamic updates
- NATTraversalInfo NATinfo;
- mDNSBool ClientCallbackDeferred; // invoke client callback on completion of pending operation(s)
- mStatus DeferredStatus; // status to deliver when above flag is set
- mDNSBool SRVUpdateDeferred; // do we need to change target or port once current operation completes?
- mDNSBool SRVChanged; // temporarily deregistered service because its SRV target or port changed
- struct tcpInfo_t *tcp;
-
- // End uDNS info ****************
-
mDNSServiceCallback *ServiceCallback;
void *ServiceContext;
mDNSBool Conflict; // Set if this record set was forcibly deregistered because of a conflict
@@ -2202,7 +1344,7 @@ struct ServiceRecordSet_struct
#endif
// We record the last eight instances of each duplicate query
-// This gives us v4/v6 on each of Ethernet/AirPort and Firewire, and two free slots "for future expansion"
+// This gives us v4/v6 on each of Ethernet, AirPort and Firewire, and two free slots "for future expansion"
// If the host has more active interfaces that this it is not fatal -- duplicate question suppression will degrade gracefully.
// Since we will still remember the last eight, the busiest interfaces will still get the effective duplicate question suppression.
#define DupSuppressInfoSize 8
@@ -2254,7 +1396,8 @@ enum { NoAnswer_Normal = 0, NoAnswer_Suspended = 1, NoAnswer_Fail = 2 };
#define AutoTunnelUnregistered(X) ( \
(X)->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered && \
(X)->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered && \
- (X)->AutoTunnelService. resrec.RecordType == kDNSRecordTypeUnregistered )
+ (X)->AutoTunnelService. resrec.RecordType == kDNSRecordTypeUnregistered && \
+ (X)->AutoTunnel6Record. resrec.RecordType == kDNSRecordTypeUnregistered )
// Internal data structure to maintain authentication information
typedef struct DomainAuthInfo
@@ -2266,6 +1409,7 @@ typedef struct DomainAuthInfo
AuthRecord AutoTunnelTarget; // Opaque hostname of tunnel endpoint; used as SRV target for AutoTunnelService record
AuthRecord AutoTunnelDeviceInfo; // Device info of tunnel endpoint
AuthRecord AutoTunnelService; // Service record (possibly NAT-Mapped) of IKE daemon implementing tunnel endpoint
+ AuthRecord AutoTunnel6Record; // AutoTunnel AAAA Record obtained from Connectivityd
NATTraversalInfo AutoTunnelNAT;
domainname domain;
domainname keyname;
@@ -2277,6 +1421,11 @@ typedef struct DomainAuthInfo
// Note: Within an mDNSQuestionCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute()
typedef enum { QC_rmv = 0, QC_add = 1, QC_addnocache = 2 } QC_result;
typedef void mDNSQuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
+
+#define NextQSendTime(Q) ((Q)->LastQTime + (Q)->ThisQInterval)
+#define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
+#define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - NextQSendTime(Q) >= 0)
+
struct DNSQuestion_struct
{
// Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
@@ -2305,23 +1454,33 @@ struct DNSQuestion_struct
mDNSu32 RequestUnicast; // Non-zero if we want to send query with kDNSQClass_UnicastResponse bit set
mDNSs32 LastQTxTime; // Last time this Q was sent on one (but not necessarily all) interfaces
mDNSu32 CNAMEReferrals; // Count of how many CNAME redirections we've done
+ mDNSBool SuppressQuery; // This query should be suppressed and not sent on the wire
// Wide Area fields. These are used internally by the uDNS core
UDPSocket *LocalSocket;
+ mDNSBool deliverAddEvents; // Change in DNSSserver requiring to deliver ADD events
DNSServer *qDNSServer; // Caching server for this query (in the absence of an SRV saying otherwise)
+ mDNSOpaque64 validDNSServers; // Valid DNSServers for this question
+ mDNSu16 noServerResponse; // At least one server did not respond.
+ mDNSu16 triedAllServersOnce; // Tried all DNS servers once
mDNSu8 unansweredQueries;// The number of unanswered queries to this server
ZoneData *nta; // Used for getting zone data for private or LLQ query
mDNSAddr servAddr; // Address and port learned from _dns-llq, _dns-llq-tls or _dns-query-tls SRV query
mDNSIPPort servPort;
struct tcpInfo_t *tcp;
+ mDNSIPPort tcpSrcPort; // Local Port TCP packet received on;need this as tcp struct is disposed
+ // by tcpCallback before calling into mDNSCoreReceive
mDNSu8 NoAnswer; // Set if we want to suppress answers until tunnel setup has completed
// LLQ-specific fields. These fields are only meaningful when LongLived flag is set
LLQ_State state;
mDNSu32 ReqLease; // seconds (relative)
mDNSs32 expire; // ticks (absolute)
- mDNSs16 ntries;
+ mDNSs16 ntries; // for UDP: the number of packets sent for this LLQ state
+ // for TCP: there is some ambiguity in the use of this variable, but in general, it is
+ // the number of TCP/TLS connection attempts for this LLQ state, or
+ // the number of packets sent for this TCP/TLS connection
mDNSOpaque64 id;
// Client API fields: The client must set up these fields *before* calling mDNS_StartQuery()
@@ -2336,6 +1495,7 @@ struct DNSQuestion_struct
mDNSBool ExpectUnique; // Set by client if it's expecting unique RR(s) for this question, not shared RRs
mDNSBool ForceMCast; // Set by client to force mDNS query, even for apparently uDNS names
mDNSBool ReturnIntermed; // Set by client to request callbacks for intermediate CNAME/NXDOMAIN results
+ mDNSBool SuppressUnusable; // Set by client to suppress unusable queries to be sent on the wire
mDNSQuestionCallback *QuestionCallback;
void *QuestionContext;
};
@@ -2407,6 +1567,12 @@ typedef struct DNameListElem
} DNameListElem;
#if APPLE_OSX_mDNSResponder
+// Different states that we go through locating the peer
+#define TC_STATE_AAAA_PEER 0x000000001 /* Peer's BTMM IPv6 address */
+#define TC_STATE_AAAA_PEER_RELAY 0x000000002 /* Peer's IPv6 Relay address */
+#define TC_STATE_SRV_PEER 0x000000003 /* Peer's SRV Record corresponding to IPv4 address */
+#define TC_STATE_ADDR_PEER 0x000000004 /* Peer's IPv4 address */
+
typedef struct ClientTunnel
{
struct ClientTunnel *next;
@@ -2414,9 +1580,12 @@ typedef struct ClientTunnel
mDNSBool MarkedForDeletion;
mDNSv6Addr loc_inner;
mDNSv4Addr loc_outer;
+ mDNSv6Addr loc_outer6;
mDNSv6Addr rmt_inner;
mDNSv4Addr rmt_outer;
+ mDNSv6Addr rmt_outer6;
mDNSIPPort rmt_outer_port;
+ mDNSu16 tc_state;
DNSQuestion q;
} ClientTunnel;
#endif
@@ -2480,6 +1649,8 @@ typedef struct SearchListElem
DNSQuestion AutomaticBrowseQ;
DNSQuestion RegisterQ;
DNSQuestion DefRegisterQ;
+ DNSQuestion DirQ;
+ int numDirAnswers;
ARListElem *AuthRecs;
} SearchListElem;
@@ -2500,10 +1671,11 @@ typedef void mDNSCallback(mDNS *const m, mStatus result);
#define CACHE_HASH_SLOTS 499
-enum
+enum // Bit flags -- i.e. values should be 1, 2, 4, 8, etc.
{
mDNS_KnownBug_PhantomInterfaces = 1,
- mDNS_KnownBug_LossySyslog = 2 // <rdar://problem/6561888>
+ mDNS_KnownBug_LimitedIPv6 = 2,
+ mDNS_KnownBug_LossySyslog = 4 // <rdar://problem/6561888>
};
enum
@@ -2549,7 +1721,7 @@ struct mDNS_struct
mDNSs32 timenow_last; // The time the last time we ran
mDNSs32 NextScheduledEvent; // Derived from values below
mDNSs32 ShutdownTime; // Set when we're shutting down; allows us to skip some unnecessary steps
- mDNSs32 SuppressSending; // Don't send *any* packets during this time
+ mDNSs32 SuppressSending; // Don't send local-link mDNS packets during this time
mDNSs32 NextCacheCheck; // Next time to refresh cache record before it expires
mDNSs32 NextScheduledQuery; // Next time to send query in its exponential backoff sequence
mDNSs32 NextScheduledProbe; // Next time to probe for new authoritative record
@@ -2559,26 +1731,32 @@ struct mDNS_struct
mDNSs32 RandomQueryDelay; // For de-synchronization of query packets on the wire
mDNSu32 RandomReconfirmDelay; // For de-synchronization of reconfirmation queries on the wire
mDNSs32 PktNum; // Unique sequence number assigned to each received packet
+ mDNSu8 LocalRemoveEvents; // Set if we may need to deliver remove events for local-only questions and/or local-only records
mDNSu8 SleepState; // Set if we're sleeping
mDNSu8 SleepSeqNum; // "Epoch number" of our current period of wakefulness
mDNSu8 SystemWakeOnLANEnabled; // Set if we want to register with a Sleep Proxy before going to sleep
+ mDNSu8 SentSleepProxyRegistration;// Set if we registered (or tried to register) with a Sleep Proxy
+ mDNSu8 SystemSleepOnlyIfWakeOnLAN;// Set if we may only sleep if we managed to register with a Sleep Proxy
+ mDNSs32 AnnounceOwner; // After waking from sleep, include OWNER option in packets until this time
mDNSs32 DelaySleep; // To inhibit re-sleeping too quickly right after wake
mDNSs32 SleepLimit; // Time window to allow deregistrations, etc.,
// during which underying platform layer should inhibit system sleep
- mDNSs32 NextScheduledSPRetry; // Time next sleep proxy registration action is required. Only valid if SleepLimit is nonzero.
+ mDNSs32 NextScheduledSPRetry; // Time next sleep proxy registration action is required.
+ // Only valid if SleepLimit is nonzero and DelaySleep is zero.
// These fields only required for mDNS Searcher...
DNSQuestion *Questions; // List of all registered questions, active and inactive
DNSQuestion *NewQuestions; // Fresh questions not yet answered from cache
DNSQuestion *CurrentQuestion; // Next question about to be examined in AnswerLocalQuestions()
- DNSQuestion *LocalOnlyQuestions; // Questions with InterfaceID set to mDNSInterface_LocalOnly
- DNSQuestion *NewLocalOnlyQuestions; // Fresh local-only questions not yet answered
+ DNSQuestion *LocalOnlyQuestions; // Questions with InterfaceID set to mDNSInterface_LocalOnly or mDNSInterface_P2P
+ DNSQuestion *NewLocalOnlyQuestions; // Fresh local-only or P2P questions not yet answered
mDNSu32 rrcache_size; // Total number of available cache entries
mDNSu32 rrcache_totalused; // Number of cache entries currently occupied
mDNSu32 rrcache_active; // Number of cache entries currently occupied by records that answer active questions
mDNSu32 rrcache_report;
CacheEntity *rrcache_free;
CacheGroup *rrcache_hash[CACHE_HASH_SLOTS];
+ mDNSs32 rrcache_nextcheck[CACHE_HASH_SLOTS];
// Fields below only required for mDNS Responder...
domainlabel nicelabel; // Rich text label encoded using canonically precomposed UTF-8
@@ -2589,7 +1767,7 @@ struct mDNS_struct
AuthRecord DeviceInfo;
AuthRecord *ResourceRecords;
AuthRecord *DuplicateRecords; // Records currently 'on hold' because they are duplicates of existing records
- AuthRecord *NewLocalRecords; // Fresh local-only records not yet delivered to local-only questions
+ AuthRecord *NewLocalRecords; // Fresh AuthRecords (both local-only and public) not yet delivered to our local-only questions
AuthRecord *CurrentRecord; // Next AuthRecord about to be examined
NetworkInterfaceInfo *HostInterfaces;
mDNSs32 ProbeFailTime;
@@ -2599,9 +1777,7 @@ struct mDNS_struct
// Unicast-specific data
mDNSs32 NextuDNSEvent; // uDNS next event
mDNSs32 NextSRVUpdate; // Time to perform delayed update
- mDNSs32 SuppressStdPort53Queries; // Wait before allowing the next standard unicast query to the user's configured DNS server
- ServiceRecordSet *ServiceRegistrations;
DNSServer *DNSServers; // list of DNS servers
mDNSAddr Router;
@@ -2617,9 +1793,11 @@ struct mDNS_struct
HostnameInfo *Hostnames; // List of registered hostnames + hostname metadata
mDNSv6Addr AutoTunnelHostAddr; // IPv6 address advertised for AutoTunnel services on this machine
mDNSBool AutoTunnelHostAddrActive;
+ mDNSv6Addr AutoTunnelRelayAddr; // IPv6 address advertised for AutoTunnel Relay services on this machine
domainlabel AutoTunnelLabel; // Used to construct hostname for *IPv4* address of tunnel endpoints
mDNSBool RegisterSearchDomains;
+ mDNSBool RegisterAutoTunnel6;
// NAT-Traversal fields
NATTraversalInfo LLQNAT; // Single shared NAT Traversal to receive inbound LLQ notifications
@@ -2664,6 +1842,7 @@ struct mDNS_struct
#if APPLE_OSX_mDNSResponder
ClientTunnel *TunnelClients;
uuid_t asl_uuid; // uuid for ASL logging
+ void *WCF;
#endif
// Fixed storage, to avoid creating large objects on the stack
@@ -2684,25 +1863,17 @@ struct mDNS_struct
#pragma mark - Useful Static Constants
#endif
-extern const mDNSIPPort zeroIPPort;
-extern const mDNSv4Addr zerov4Addr;
-extern const mDNSv6Addr zerov6Addr;
-extern const mDNSEthAddr zeroEthAddr;
-extern const mDNSv4Addr onesIPv4Addr;
-extern const mDNSv6Addr onesIPv6Addr;
-extern const mDNSEthAddr onesEthAddr;
-extern const mDNSAddr zeroAddr;
-
-extern const OwnerOptData zeroOwner;
-
extern const mDNSInterfaceID mDNSInterface_Any; // Zero
extern const mDNSInterfaceID mDNSInterface_LocalOnly; // Special value
extern const mDNSInterfaceID mDNSInterface_Unicast; // Special value
+extern const mDNSInterfaceID mDNSInterfaceMark; // Special value
+extern const mDNSInterfaceID mDNSInterface_P2P; // Special value
extern const mDNSIPPort DiscardPort;
extern const mDNSIPPort SSHPort;
extern const mDNSIPPort UnicastDNSPort;
extern const mDNSIPPort SSDPPort;
+extern const mDNSIPPort IPSECPort;
extern const mDNSIPPort NSIPCPort;
extern const mDNSIPPort NATPMPAnnouncementPort;
extern const mDNSIPPort NATPMPPort;
@@ -2711,8 +1882,22 @@ extern const mDNSIPPort MulticastDNSPort;
extern const mDNSIPPort LoopbackIPCPort;
extern const mDNSIPPort PrivateDNSPort;
+extern const OwnerOptData zeroOwner;
+
+extern const mDNSIPPort zeroIPPort;
+extern const mDNSv4Addr zerov4Addr;
+extern const mDNSv6Addr zerov6Addr;
+extern const mDNSEthAddr zeroEthAddr;
+extern const mDNSv4Addr onesIPv4Addr;
+extern const mDNSv6Addr onesIPv6Addr;
+extern const mDNSEthAddr onesEthAddr;
+extern const mDNSAddr zeroAddr;
+
extern const mDNSv4Addr AllDNSAdminGroup;
-extern const mDNSv4Addr AllSystemsMcast;
+extern const mDNSv4Addr AllHosts_v4;
+extern const mDNSv6Addr AllHosts_v6;
+extern const mDNSv6Addr NDP_prefix;
+extern const mDNSEthAddr AllHosts_v6_Eth;
extern const mDNSAddr AllDNSLinkGroup_v4;
extern const mDNSAddr AllDNSLinkGroup_v6;
@@ -2726,6 +1911,9 @@ extern const mDNSOpaque16 UpdateRespFlags;
extern const mDNSOpaque64 zeroOpaque64;
+extern mDNSBool StrictUnicastOrdering;
+extern mDNSu8 NumUnicastDNSServers;
+
#define localdomain (*(const domainname *)"\x5" "local")
#define DeviceInfoName (*(const domainname *)"\xC" "_device-info" "\x4" "_tcp")
#define SleepProxyServiceType (*(const domainname *)"\xC" "_sleep-proxy" "\x4" "_udp")
@@ -2845,7 +2033,7 @@ extern void mDNS_GrowCache (mDNS *const m, CacheEntity *storage, mDNSu32 numr
extern void mDNS_StartExit (mDNS *const m);
extern void mDNS_FinalExit (mDNS *const m);
#define mDNS_Close(m) do { mDNS_StartExit(m); mDNS_FinalExit(m); } while(0)
-#define mDNS_ExitNow(m, now) ((now) - (m)->ShutdownTime >= 0 || (!(m)->ResourceRecords && !(m)->ServiceRegistrations))
+#define mDNS_ExitNow(m, now) ((now) - (m)->ShutdownTime >= 0 || (!(m)->ResourceRecords))
extern mDNSs32 mDNS_Execute (mDNS *const m);
@@ -2868,6 +2056,8 @@ extern mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *travers
extern DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const name);
+extern void mDNS_UpdateAllowSleep(mDNS *const m);
+
// ***************************************************************************
#if 0
#pragma mark -
@@ -2882,6 +2072,12 @@ extern mDNSs32 mDNSPlatformOneSecond;
#pragma mark - General utility and helper functions
#endif
+// mDNS_Dereg_normal is used for most calls to mDNS_Deregister_internal
+// mDNS_Dereg_rapid is used to send one goodbye instead of three, when we want the memory available for reuse sooner
+// mDNS_Dereg_conflict is used to indicate that this record is being forcibly deregistered because of a conflict
+// mDNS_Dereg_repeat is used when cleaning up, for records that may have already been forcibly deregistered
+typedef enum { mDNS_Dereg_normal, mDNS_Dereg_rapid, mDNS_Dereg_conflict, mDNS_Dereg_repeat } mDNS_Dereg_type;
+
// mDNS_RegisterService is a single call to register the set of resource records associated with a given named service.
//
// mDNS_StartResolveService is single call which is equivalent to multiple calls to mDNS_StartQuery,
@@ -2915,7 +2111,8 @@ extern mStatus mDNS_RegisterService (mDNS *const m, ServiceRecordSet *sr,
extern mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl);
extern mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, mDNSRecordCallback MemFreeCallback, void *Context);
extern mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname);
-extern mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr);
+extern mStatus mDNS_DeregisterService_drt(mDNS *const m, ServiceRecordSet *sr, mDNS_Dereg_type drt);
+#define mDNS_DeregisterService(M,S) mDNS_DeregisterService_drt((M), (S), mDNS_Dereg_normal)
extern mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr,
const domainlabel *const name, const domainname *const type, const domainname *const domain,
@@ -2954,8 +2151,11 @@ extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainT
#define mDNS_StopAdvertiseDomains mDNS_Deregister
extern mDNSOpaque16 mDNS_NewMessageID(mDNS *const m);
-
-extern DNSServer *GetServerForName(mDNS *m, const domainname *name);
+extern mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr);
+
+extern DNSServer *GetServerForName(mDNS *m, const domainname *name, mDNSInterfaceID InterfaceID);
+extern DNSServer *GetServerForQuestion(mDNS *m, DNSQuestion *question);
+extern void SetValidDNSServers(mDNS *m, DNSQuestion *question);
// ***************************************************************************
#if 0
@@ -2980,10 +2180,15 @@ extern DNSServer *GetServerForName(mDNS *m, const domainname *name);
extern mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
extern mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2);
extern mDNSBool SameDomainNameCS(const domainname *const d1, const domainname *const d2);
+typedef mDNSBool DomainNameComparisonFn(const domainname *const d1, const domainname *const d2);
extern mDNSBool IsLocalDomain(const domainname *d); // returns true for domains that by default should be looked up using link-local multicast
+#define StripFirstLabel(X) ((const domainname *)&(X)->c[(X)->c[0] ? 1 + (X)->c[0] : 0])
+
#define FirstLabel(X) ((const domainlabel *)(X))
-#define SecondLabel(X) ((const domainlabel *)&(X)->c[1 + (X)->c[0]])
+#define SecondLabel(X) ((const domainlabel *)StripFirstLabel(X))
+#define ThirdLabel(X) ((const domainlabel *)StripFirstLabel(StripFirstLabel(X)))
+
extern const mDNSu8 *LastLabel(const domainname *d);
// Get total length of domain name, in native DNS format, including terminal root label
@@ -3109,6 +2314,12 @@ extern mDNSBool mDNSv4AddrIsRFC1918(mDNSv4Addr *addr); // returns true for RFC1
((X)->type == mDNSAddrType_IPv4) ? mDNSv4AddressIsLinkLocal(&(X)->ip.v4) : \
((X)->type == mDNSAddrType_IPv6) ? mDNSv6AddressIsLinkLocal(&(X)->ip.v6) : mDNSfalse)
+#define mDNSv4AddressIsLoopback(X) ((X)->b[0] == 127 && (X)->b[1] == 0 && (X)->b[2] == 0 && (X)->b[3] == 1)
+#define mDNSv6AddressIsLoopback(X) ((((X)->l[0] | (X)->l[1] | (X)->l[2]) == 0) && ((X)->b[12] == 0 && (X)->b[13] == 0 && (X)->b[14] == 0 && (X)->b[15] == 1))
+
+#define mDNSAddressIsLoopback(X) ( \
+ ((X)->type == mDNSAddrType_IPv4) ? mDNSv4AddressIsLoopback(&(X)->ip.v4) : \
+ ((X)->type == mDNSAddrType_IPv6) ? mDNSv6AddressIsLoopback(&(X)->ip.v6) : mDNSfalse)
// ***************************************************************************
#if 0
#pragma mark -
@@ -3149,8 +2360,8 @@ extern void RecreateNATMappings(mDNS *const m);
extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext);
extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn);
extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router);
-extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port);
-extern void PushDNSServerToEnd(mDNS *const m, DNSQuestion *q);
+extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped);
+extern void PenalizeDNSServer(mDNS *const m, DNSQuestion *q);
extern void mDNS_AddSearchDomain(const domainname *const domain);
// We use ((void *)0) here instead of mDNSNULL to avoid compile warnings on gcc 4.2
@@ -3299,8 +2510,8 @@ typedef void (*TCPConnectionCallback)(TCPSocket *sock, void *context, mDNSBool C
extern TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port); // creates a TCP socket
extern TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd);
extern int mDNSPlatformTCPGetFD(TCPSocket *sock);
-extern mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
- TCPConnectionCallback callback, void *context);
+extern mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname,
+ mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context);
extern void mDNSPlatformTCPCloseConnection(TCPSocket *sock);
extern long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed);
extern long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len);
@@ -3309,7 +2520,7 @@ extern void mDNSPlatformUDPClose(UDPSocket *sock);
extern void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd);
extern void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID);
extern void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID);
-extern void mDNSPlatformSetLocalARP(const mDNSv4Addr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID);
+extern void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID);
extern void mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst);
// mDNSPlatformTLSSetupCerts/mDNSPlatformTLSTearDownCerts used by dnsextd
@@ -3323,10 +2534,12 @@ extern void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, m
extern mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *router);
extern void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status);
+extern void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep);
+
#ifdef _LEGACY_NAT_TRAVERSAL_
// Support for legacy NAT traversal protocols, implemented by the platform layer and callable by the core.
extern void LNT_SendDiscoveryMsg(mDNS *m);
-extern void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *data, mDNSu16 len);
+extern void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, const mDNSu8 *const data, const mDNSu16 len);
extern mStatus LNT_GetExternalAddress(mDNS *m);
extern mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *n);
extern mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *n);
@@ -3376,41 +2589,173 @@ extern void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
extern void mDNSCoreInitComplete(mDNS *const m, mStatus result);
extern void mDNSCoreReceive(mDNS *const m, void *const msg, const mDNSu8 *const end,
const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
- const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID);
+ const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID);
extern void mDNSCoreRestartQueries(mDNS *const m);
extern mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m);
extern void mDNSCoreMachineSleep(mDNS *const m, mDNSBool wake);
-extern mDNSBool mDNSCoreReadyForSleep(mDNS *m);
+extern mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now);
extern mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now);
-extern void mDNSCoreBeSleepProxyServer(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower);
extern void mDNSCoreReceiveRawPacket (mDNS *const m, const mDNSu8 *const p, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID);
extern mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip);
-extern CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg);
+extern CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg, mDNSs32 delay);
+extern void ScheduleNextCacheCheckTime(mDNS *const m, const mDNSu32 slot, const mDNSs32 event);
extern void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease);
extern void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr,
- const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds, mDNSInterfaceID InterfaceID);
+ const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds,
+ mDNSInterfaceID InterfaceID, DNSServer *dnsserver);
extern void CompleteDeregistration(mDNS *const m, AuthRecord *rr);
-extern void FindSPSInCache(mDNS *const m, const DNSQuestion *const q, const CacheRecord *sps[3]);
-#define PrototypeSPSName(X) ((X)[0] >= 11 && (X)[3] == '-' && (X)[ 4] == '9' && (X)[ 5] == '9' && \
- (X)[6] == '-' && (X)[ 7] == '9' && (X)[ 8] == '9' && \
- (X)[9] == '-' && (X)[10] == '9' && (X)[11] == '9' )
-#define ValidSPSName(X) ((X)[0] >= 5 && mDNSIsDigit((X)[1]) && mDNSIsDigit((X)[2]) && mDNSIsDigit((X)[4]) && mDNSIsDigit((X)[5]))
-#define SPSMetric(X) (!ValidSPSName(X) || PrototypeSPSName(X) ? 1000000 : \
- ((X)[1]-'0') * 100000 + ((X)[2]-'0') * 10000 + ((X)[4]-'0') * 1000 + ((X)[5]-'0') * 100 + ((X)[7]-'0') * 10 + ((X)[8]-'0'))
extern void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord);
+extern char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID);
+extern void DNSServerChangeForQuestion(mDNS *const m, DNSQuestion *q, DNSServer *new);
+extern void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr);
+extern void CheckSuppressUnusableQuestions(mDNS *const m);
// For now this AutoTunnel stuff is specific to Mac OS X.
// In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
#if APPLE_OSX_mDNSResponder
extern void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
extern void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q);
-extern void SetupLocalAutoTunnelInterface_internal(mDNS *const m);
+extern void SetupLocalAutoTunnelInterface_internal(mDNS *const m, mDNSBool servicesStarting);
extern void UpdateAutoTunnelDomainStatuses(const mDNS *const m);
+extern mStatus ActivateLocalProxy(mDNS *const m, char *ifname);
+extern void RemoveAutoTunnel6Record(mDNS *const m);
+extern void SetupConndConfigChanges(mDNS *const m);
+extern mDNSBool RecordReadyForSleep(mDNS *const m, AuthRecord *rr);
+#endif
+
+// ***************************************************************************
+#if 0
+#pragma mark -
+#pragma mark - Sleep Proxy
#endif
+// Sleep Proxy Server Property Encoding
+//
+// Sleep Proxy Servers are advertised using a structured service name, consisting of four
+// metrics followed by a human-readable name. The metrics assist clients in deciding which
+// Sleep Proxy Server(s) to use when multiple are available on the network. Each metric
+// is a two-digit decimal number in the range 10-99. Lower metrics are generally better.
+//
+// AA-BB-CC-DD Name
+//
+// Metrics:
+//
+// AA = Intent
+// BB = Portability
+// CC = Marginal Power
+// DD = Total Power
+//
+//
+// ** Intent Metric **
+//
+// 20 = Dedicated Sleep Proxy Server -- a device, permanently powered on,
+// installed for the express purpose of providing Sleep Proxy Service.
+//
+// 30 = Primary Network Infrastructure Hardware -- a router, DHCP server, NAT gateway,
+// or similar permanently installed device which is permanently powered on.
+// This is hardware designed for the express purpose of being network
+// infrastructure, and for most home users is typically a single point
+// of failure for the local network -- e.g. most home users only have
+// a single NAT gateway / DHCP server. Even though in principle the
+// hardware might technically be capable of running different software,
+// a typical user is unlikely to do that. e.g. AirPort base station.
+//
+// 40 = Primary Network Infrastructure Software -- a general-purpose computer
+// (e.g. Mac, Windows, Linux, etc.) which is currently running DHCP server
+// or NAT gateway software, but the user could choose to turn that off
+// fairly easily. e.g. iMac running Internet Sharing
+//
+// 50 = Secondary Network Infrastructure Hardware -- like primary infrastructure
+// hardware, except not a single point of failure for the entire local network.
+// For example, an AirPort base station in bridge mode. This may have clients
+// associated with it, and if it goes away those clients will be inconvenienced,
+// but unlike the NAT gateway / DHCP server, the entire local network is not
+// dependent on it.
+//
+// 60 = Secondary Network Infrastructure Software -- like 50, but in a general-
+// purpose CPU.
+//
+// 70 = Incidentally Available Hardware -- a device which has no power switch
+// and is generally left powered on all the time. Even though it is not a
+// part of what we conventionally consider network infrastructure (router,
+// DHCP, NAT, DNS, etc.), and the rest of the network can operate fine
+// without it, since it's available and unlikely to be turned off, it is a
+// reasonable candidate for providing Sleep Proxy Service e.g. Apple TV,
+// or an AirPort base station in client mode, associated with an existing
+// wireless network (e.g. AirPort Express connected to a music system, or
+// being used to share a USB printer).
+//
+// 80 = Incidentally Available Software -- a general-purpose computer which
+// happens at this time to be set to "never sleep", and as such could be
+// useful as a Sleep Proxy Server, but has not been intentionally provided
+// for this purpose. Of all the Intent Metric categories this is the
+// one most likely to be shut down or put to sleep without warning.
+// However, if nothing else is availalable, it may be better than nothing.
+// e.g. Office computer in the workplace which has been set to "never sleep"
+//
+//
+// ** Portability Metric **
+//
+// Inversely related to mass of device, on the basis that, all other things
+// being equal, heavier devices are less likely to be moved than lighter devices.
+// E.g. A MacBook running Internet Sharing is probably more likely to be
+// put to sleep and taken away than a Mac Pro running Internet Sharing.
+// The Portability Metric is a logarithmic decibel scale, computed by taking the
+// (approximate) mass of the device in milligrammes, taking the base 10 logarithm
+// of that, multiplying by 10, and subtracting the result from 100:
+//
+// Portability Metric = 100 - (log10(mg) * 10)
+//
+// The Portability Metric is not necessarily computed literally from the actual
+// mass of the device; the intent is just that lower numbers indicate more
+// permanent devices, and higher numbers indicate devices more likely to be
+// removed from the network, e.g., in order of increasing portability:
+//
+// Mac Pro < iMac < Laptop < iPhone
+//
+// Example values:
+//
+// 10 = 1 metric tonne
+// 40 = 1kg
+// 70 = 1g
+// 90 = 10mg
+//
+//
+// ** Marginal Power and Total Power Metrics **
+//
+// The Marginal Power Metric is the power difference between sleeping and staying awake
+// to be a Sleep Proxy Server.
+//
+// The Total Power Metric is the total power consumption when being Sleep Proxy Server.
+//
+// The Power Metrics use a logarithmic decibel scale, computed as ten times the
+// base 10 logarithm of the (approximate) power in microwatts:
+//
+// Power Metric = log10(uW) * 10
+//
+// Higher values indicate higher power consumption. Example values:
+//
+// 10 = 10 uW
+// 20 = 100 uW
+// 30 = 1 mW
+// 60 = 1 W
+// 90 = 1 kW
+
+extern void mDNSCoreBeSleepProxyServer_internal(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower);
+#define mDNSCoreBeSleepProxyServer(M,S,P,MP,TP) \
+ do { mDNS_Lock(m); mDNSCoreBeSleepProxyServer_internal((M),(S),(P),(MP),(TP)); mDNS_Unlock(m); } while(0)
+
+extern void FindSPSInCache(mDNS *const m, const DNSQuestion *const q, const CacheRecord *sps[3]);
+#define PrototypeSPSName(X) ((X)[0] >= 11 && (X)[3] == '-' && (X)[ 4] == '9' && (X)[ 5] == '9' && \
+ (X)[6] == '-' && (X)[ 7] == '9' && (X)[ 8] == '9' && \
+ (X)[9] == '-' && (X)[10] == '9' && (X)[11] == '9' )
+#define ValidSPSName(X) ((X)[0] >= 5 && mDNSIsDigit((X)[1]) && mDNSIsDigit((X)[2]) && mDNSIsDigit((X)[4]) && mDNSIsDigit((X)[5]))
+#define SPSMetric(X) (!ValidSPSName(X) || PrototypeSPSName(X) ? 1000000 : \
+ ((X)[1]-'0') * 100000 + ((X)[2]-'0') * 10000 + ((X)[4]-'0') * 1000 + ((X)[5]-'0') * 100 + ((X)[7]-'0') * 10 + ((X)[8]-'0'))
+
// ***************************************************************************
#if 0
#pragma mark -
@@ -3446,29 +2791,30 @@ struct CompileTimeAssertionChecks_mDNS
char assertG[(sizeof(ARP_EthIP ) == 28 ) ? 1 : -1];
char assertH[(sizeof(IPv4Header ) == 20 ) ? 1 : -1];
char assertI[(sizeof(IPv6Header ) == 40 ) ? 1 : -1];
- char assertJ[(sizeof(IPv6ND ) == 24 ) ? 1 : -1];
+ char assertJ[(sizeof(IPv6NDP ) == 24 ) ? 1 : -1];
char assertK[(sizeof(UDPHeader ) == 8 ) ? 1 : -1];
- char assertL[(sizeof(TCPHeader ) == 20 ) ? 1 : -1];
+ char assertL[(sizeof(IKEHeader ) == 28 ) ? 1 : -1];
+ char assertM[(sizeof(TCPHeader ) == 20 ) ? 1 : -1];
// Check our structures are reasonable sizes. Including overly-large buffers, or embedding
// other overly-large structures instead of having a pointer to them, can inadvertently
// cause structure sizes (and therefore memory usage) to balloon unreasonably.
char sizecheck_RDataBody [(sizeof(RDataBody) == 264) ? 1 : -1];
- char sizecheck_ResourceRecord [(sizeof(ResourceRecord) <= 56) ? 1 : -1];
- char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1000) ? 1 : -1];
- char sizecheck_CacheRecord [(sizeof(CacheRecord) <= 176) ? 1 : -1];
- char sizecheck_CacheGroup [(sizeof(CacheGroup) <= 176) ? 1 : -1];
- char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 728) ? 1 : -1];
- char sizecheck_ZoneData [(sizeof(ZoneData) <= 1560) ? 1 : -1];
+ char sizecheck_ResourceRecord [(sizeof(ResourceRecord) <= 64) ? 1 : -1];
+ char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1208) ? 1 : -1];
+ char sizecheck_CacheRecord [(sizeof(CacheRecord) <= 184) ? 1 : -1];
+ char sizecheck_CacheGroup [(sizeof(CacheGroup) <= 184) ? 1 : -1];
+ char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 752) ? 1 : -1];
+ char sizecheck_ZoneData [(sizeof(ZoneData) <= 1588) ? 1 : -1];
char sizecheck_NATTraversalInfo [(sizeof(NATTraversalInfo) <= 192) ? 1 : -1];
- char sizecheck_HostnameInfo [(sizeof(HostnameInfo) <= 2800) ? 1 : -1];
- char sizecheck_DNSServer [(sizeof(DNSServer) <= 312) ? 1 : -1];
- char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 5968) ? 1 : -1];
+ char sizecheck_HostnameInfo [(sizeof(HostnameInfo) <= 3050) ? 1 : -1];
+ char sizecheck_DNSServer [(sizeof(DNSServer) <= 320) ? 1 : -1];
+ char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 6750) ? 1 : -1];
char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 5500) ? 1 : -1];
- char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 5500) ? 1 : -1];
- char sizecheck_ServiceInfoQuery [(sizeof(ServiceInfoQuery) <= 2944) ? 1 : -1];
+ char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 7550) ? 1 : -1];
+ char sizecheck_ServiceInfoQuery [(sizeof(ServiceInfoQuery) <= 3050) ? 1 : -1];
#if APPLE_OSX_mDNSResponder
- char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1072) ? 1 : -1];
+ char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1104) ? 1 : -1];
#endif
};
diff --git a/external/apache2/mDNSResponder/dist/mDNSPosix/PosixDaemon.c b/external/apache2/mDNSResponder/dist/mDNSPosix/PosixDaemon.c
index 8a440129b1e..350063161f8 100644
--- a/external/apache2/mDNSResponder/dist/mDNSPosix/PosixDaemon.c
+++ b/external/apache2/mDNSResponder/dist/mDNSPosix/PosixDaemon.c
@@ -18,74 +18,15 @@
Contains: main & associated Application layer for mDNSResponder on Linux.
- Change History (most recent first):
+ */
-Log: PosixDaemon.c,v $
-Revision 1.49 2009/04/30 20:07:51 mcguire
-<rdar://problem/6822674> Support multiple UDSs from launchd
-
-Revision 1.48 2009/04/11 01:43:28 jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.47 2009/01/11 03:20:06 mkrochma
-<rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris
-
-Revision 1.46 2008/11/03 23:09:15 cheshire
-Don't need to include mDNSDebug.h as well as mDNSEmbeddedAPI.h
-
-Revision 1.45 2008/10/03 18:25:17 cheshire
-Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);"
-
-Revision 1.44 2008/09/15 23:52:30 cheshire
-<rdar://problem/6218902> mDNSResponder-177 fails to compile on Linux with .desc pseudo-op
-Made __crashreporter_info__ symbol conditional, so we only use it for OS X build
-
-Revision 1.43 2007/10/22 20:05:34 cheshire
-Use mDNSPlatformSourceAddrForDest instead of FindSourceAddrForIP
-
-Revision 1.42 2007/09/18 19:09:02 cheshire
-<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
-
-Revision 1.41 2007/09/04 17:02:25 cheshire
-<rdar://problem/5458929> False positives in changed files list in nightly builds
-Added MDNS_VERSIONSTR_NODTS option at the reqest of Rishi Srivatsavai (Sun)
-
-Revision 1.40 2007/07/31 23:08:34 mcguire
-<rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
-
-Revision 1.39 2007/03/21 00:30:44 cheshire
-Remove obsolete mDNS_DeleteDNSServers() call
-
-Revision 1.38 2007/02/14 01:58:19 cheshire
-<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
-
-Revision 1.37 2007/02/07 19:32:00 cheshire
-<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
-
-Revision 1.36 2007/02/06 19:06:48 cheshire
-<rdar://problem/3956518> Need to go native with launchd
-
-Revision 1.35 2007/01/05 08:30:52 cheshire
-Trim excessive "Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.34 2007/01/05 05:46:08 cheshire
-Add mDNS *const m parameter to udsserver_handle_configchange()
-
-Revision 1.33 2006/12/21 00:10:53 cheshire
-Make mDNS_PlatformSupport PlatformStorage a static global instead of a stack variable
-
-Revision 1.32 2006/11/03 22:28:50 cheshire
-PosixDaemon needs to handle mStatus_ConfigChanged and mStatus_GrowCache messages
-
-Revision 1.31 2006/08/14 23:24:46 cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.30 2006/07/07 01:09:12 cheshire
-<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
-
-*/
+#if __APPLE__
+// In Mac OS X 10.5 and later trying to use the daemon function gives a “‘daemon’ is deprecated”
+// error, which prevents compilation because we build with "-Werror".
+// Since this is supposed to be portable cross-platform code, we don't care that daemon is
+// deprecated on Mac OS X 10.5, so we use this preprocessor trick to eliminate the error message.
+#define daemon yes_we_know_that_daemon_is_deprecated_in_os_x_10_5_thankyou
+#endif
#include <stdio.h>
#include <string.h>
@@ -97,6 +38,11 @@ Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsex
#include <pwd.h>
#include <sys/types.h>
+#if __APPLE__
+#undef daemon
+extern int daemon(int, int);
+#endif
+
#include "mDNSEmbeddedAPI.h"
#include "mDNSPosix.h"
#include "mDNSUNP.h" // For daemon()
@@ -335,16 +281,24 @@ int main(int argc, char **argv)
// uds_daemon support ////////////////////////////////////////////////////////////
-mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context)
+mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context, void **platform_data)
/* Support routine for uds_daemon.c */
{
// Depends on the fact that udsEventCallback == mDNSPosixEventCallback
+ (void) platform_data;
return mDNSPosixAddFDToEventLoop(fd, callback, context);
}
-mStatus udsSupportRemoveFDFromEventLoop(int fd) // Note: This also CLOSES the file descriptor
+int udsSupportReadFD(dnssd_sock_t fd, char *buf, int len, int flags, void *platform_data)
+ {
+ (void) platform_data;
+ return recv(fd, buf, len, flags);
+ }
+
+mStatus udsSupportRemoveFDFromEventLoop(int fd, void *platform_data) // Note: This also CLOSES the file descriptor
{
mStatus err = mDNSPosixRemoveFDFromEventLoop(fd);
+ (void) platform_data;
close(fd);
return err;
}
diff --git a/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSPosix.c b/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSPosix.c
index e984ed0e0cb..a01a2544e14 100755
--- a/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSPosix.c
+++ b/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSPosix.c
@@ -26,123 +26,7 @@
* thinking that variables x and y are both of type "char*" -- and anyone who doesn't
* understand why variable y is not of type "char*" just proves the point that poor code
* layout leads people to unfortunate misunderstandings about how the C language really works.)
-
- Change History (most recent first):
-
-Log: mDNSPosix.c,v $
-Revision 1.108 2009/01/25 03:16:46 mkrochma
-Added skeleton definition of mDNSPlatformSetLocalARP
-
-Revision 1.107 2009/01/07 08:25:03 mkrochma
-Added skeleton definition of mDNSPlatformUpdateProxyList
-
-Revision 1.106 2008/10/22 17:19:57 cheshire
-Don't need to define BPF_fd any more (it's now per-interface, not global)
-
-Revision 1.105 2008/10/03 23:34:08 cheshire
-Added skeleton definition of mDNSPlatformSendRawPacket
-
-Revision 1.104 2008/09/05 22:16:48 cheshire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-Add "UDPSocket *src" parameter in mDNSPlatformSendUDP
-
-Revision 1.103 2007/10/02 19:31:17 cheshire
-In ParseDNSServers, should use strncasecmp for case-insensitive compare
-
-Revision 1.102 2007/09/12 19:23:17 cheshire
-Get rid of unnecessary mDNSPlatformTCPIsConnected() routine
-
-Revision 1.101 2007/07/20 00:54:23 cheshire
-<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-
-Revision 1.100 2007/07/19 21:45:30 cheshire
-Fixed code spacing
-
-Revision 1.99 2007/07/11 02:56:51 cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-Remove unused mDNSPlatformDefaultRegDomainChanged
-
-Revision 1.98 2007/06/20 01:10:13 cheshire
-<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-
-Revision 1.97 2007/04/26 00:35:16 cheshire
-<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
-Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
-inside the firewall may give answers where a public one gives none, and vice versa.)
-
-Revision 1.96 2007/04/22 20:29:59 cheshire
-Fix locking error
-
-Revision 1.95 2007/04/22 20:15:46 cheshire
-Add missing parameters for mDNSPosixEventCallback
-
-Revision 1.94 2007/04/17 19:21:29 cheshire
-<rdar://problem/5140339> Domain discovery not working over VPN
-
-Revision 1.93 2007/04/16 20:49:40 cheshire
-Fix compile errors for mDNSPosix build
-
-Revision 1.92 2007/04/05 20:40:37 cheshire
-Remove unused mDNSPlatformTCPGetFlags()
-
-Revision 1.91 2007/03/22 18:31:48 cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.90 2007/03/21 00:31:45 cheshire
-Remove unnecessary (and unimplemented) platform functions
-
-Revision 1.89 2007/03/20 17:07:15 cheshire
-Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-
-Revision 1.88 2007/03/07 00:30:18 mkrochma
-<rdar://problem/5034370> POSIX: kDNSServiceInterfaceIndexAny not correctly handled
-Thanks goes to Aidan Williams of Audinate who did a lot of work in diagnosing this
-
-Revision 1.87 2007/02/08 21:12:28 cheshire
-<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
-
-Revision 1.86 2007/01/05 08:30:52 cheshire
-Trim excessive "Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.85 2007/01/04 23:12:20 cheshire
-Remove unused mDNSPlatformDefaultBrowseDomainChanged
-
-Revision 1.84 2006/12/22 21:07:35 cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.83 2006/12/21 00:09:46 cheshire
-Use mDNSPlatformMemZero instead of bzero
-
-Revision 1.82 2006/12/19 22:43:55 cheshire
-Fix compiler warnings
-
-Revision 1.81 2006/08/14 23:24:46 cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.80 2006/07/22 03:05:33 cheshire
-Improve error reporting for socket creation failures
-
-Revision 1.79 2006/07/06 00:02:16 cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-
-Revision 1.78 2006/06/28 09:12:22 cheshire
-Added debugging message
-
-Revision 1.77 2006/03/19 02:00:11 cheshire
-<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-
-Revision 1.76 2006/01/09 19:29:16 cheshire
-<rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log
-
-Revision 1.75 2006/01/05 22:04:57 cheshire
-<rdar://problem/4399479> Log error message when send fails with "operation not permitted"
-
-Revision 1.74 2006/01/05 21:45:27 cheshire
-<rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
-
-*/
+ */
#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
#include "DNSCommon.h"
@@ -450,12 +334,13 @@ mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
return -1;
}
-mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
+mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID,
TCPConnectionCallback callback, void *context)
{
(void)sock; // Unused
(void)dst; // Unused
(void)dstport; // Unused
+ (void)hostname; // Unused
(void)InterfaceID; // Unused
(void)callback; // Unused
(void)context; // Unused
@@ -509,8 +394,9 @@ mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *c
(void)InterfaceID; // Unused
}
-mDNSexport void mDNSPlatformSetLocalARP(const mDNSv4Addr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
+mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
{
+ (void)m; // Unused
(void)tpa; // Unused
(void)tha; // Unused
(void)InterfaceID; // Unused
@@ -596,7 +482,7 @@ mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
mDNSAddr DNSAddr;
DNSAddr.type = mDNSAddrType_IPv4;
DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
- mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, &DNSAddr, UnicastDNSPort);
+ mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, &DNSAddr, UnicastDNSPort, mDNSfalse);
numOfServers++;
}
}
@@ -627,6 +513,7 @@ mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const
assert(m != NULL);
if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
+ if (index == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P);
if (index == kDNSServiceInterfaceIndexAny ) return(mDNSInterface_Any);
intf = (PosixNetworkInterface*)(m->HostInterfaces);
@@ -643,6 +530,7 @@ mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNS
assert(m != NULL);
if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
+ if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P);
if (id == mDNSInterface_Any ) return(kDNSServiceInterfaceIndexAny);
intf = (PosixNetworkInterface*)(m->HostInterfaces);
@@ -1306,6 +1194,36 @@ mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
return(err == 0);
}
+#ifdef __NetBSD__
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+void
+initmachinedescr(mDNS *const m)
+{
+ char hwbuf[256], swbuf[256];
+ size_t hwlen, swlen;
+ const int hwmib[] = { CTL_HW, HW_MODEL };
+ const int swmib[] = { CTL_KERN, KERN_OSRELEASE };
+ const char netbsd[] = "NetBSD ";
+
+ hwlen = sizeof(hwbuf);
+ swlen = sizeof(swbuf);
+ if (sysctl(hwmib, 2, hwbuf, &hwlen, 0, 0) ||
+ sysctl(swmib, 2, swbuf, &swlen, 0, 0))
+ return;
+
+ if (hwlen + swlen + sizeof(netbsd) >=254)
+ return;
+
+ m->HIHardware.c[0] = hwlen - 1;
+ m->HISoftware.c[0] = swlen + sizeof(netbsd) - 2;
+ memcpy(&m->HIHardware.c[1], hwbuf, hwlen - 1);
+ memcpy(&m->HISoftware.c[1], netbsd, sizeof(netbsd) - 1);
+ memcpy(&m->HISoftware.c[1 + sizeof(netbsd) - 1], swbuf, swlen - 1);
+}
+#endif
+
// mDNS core calls this routine to initialise the platform-specific data.
mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
{
@@ -1327,6 +1245,10 @@ mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
GetUserSpecifiedRFC1034ComputerName(&m->hostlabel);
if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Computer");
+#ifdef __NetBSD__
+ initmachinedescr(m);
+#endif
+
mDNS_SetFQDN(m);
sa.sa_family = AF_INET;
diff --git a/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSUNP.c b/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSUNP.c
index 5a4f95668af..1059c83cf15 100755
--- a/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSUNP.c
+++ b/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSUNP.c
@@ -13,141 +13,7 @@
* 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: mDNSUNP.c,v $
-Revision 1.40 2009/01/13 05:31:34 mkrochma
-<rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
-
-Revision 1.39 2009/01/11 03:20:06 mkrochma
-<rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris
-
-Revision 1.38 2009/01/10 22:54:42 mkrochma
-<rdar://problem/5797544> Fixes from Igor Seleznev to get mdnsd working on Linux
-
-Revision 1.37 2008/10/23 22:33:24 cheshire
-Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
-
-Revision 1.36 2008/04/21 18:21:22 mkrochma
-<rdar://problem/5877307> Need to free ifi_netmask
-Submitted by Igor Seleznev
-
-Revision 1.35 2007/11/15 21:36:19 cheshire
-<rdar://problem/5289340> POSIX: Off by one overflow in get_ifi_info_linuxv6()
-
-Revision 1.34 2006/08/14 23:24:47 cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.33 2006/03/13 23:14:21 cheshire
-<rdar://problem/4427969> Compile problems on FreeBSD
-Use <netinet/in_var.h> instead of <netinet6/in6_var.h>
-
-Revision 1.32 2005/12/21 02:56:43 cheshire
-<rdar://problem/4243433> get_ifi_info() should fake ifi_index when SIOCGIFINDEX undefined
-
-Revision 1.31 2005/12/21 02:46:05 cheshire
-<rdar://problem/4243514> mDNSUNP.c needs to include <sys/param.h> on 4.4BSD Lite
-
-Revision 1.30 2005/11/29 20:03:02 mkrochma
-Wrapped sin_len with #ifndef NOT_HAVE_SA_LEN
-
-Revision 1.29 2005/11/12 02:23:10 cheshire
-<rdar://problem/4317680> mDNSUNP.c needs to deal with lame results from SIOCGIFNETMASK, SIOCGIFBRDADDR and SIOCGIFDSTADDR
-
-Revision 1.28 2005/10/31 22:09:45 cheshire
-Buffer "char addr6[33]" was seven bytes too small
-
-Revision 1.27 2005/06/29 15:54:21 cheshire
-<rdar://problem/4113742> mDNSResponder-107.1 does not work on FreeBSD
-Refine last checkin so that it (hopefully) doesn't break get_ifi_info() for every other OS
-
-Revision 1.26 2005/04/08 21:43:59 ksekar
-<rdar://problem/4083426> mDNSPosix (v98) retrieve interface list bug on AMD64 architecture
-Submitted by Andrew de Quincey
-
-Revision 1.25 2005/04/08 21:37:57 ksekar
-<rdar://problem/3792767> get_ifi_info doesn't return IPv6 interfaces on Linux
-
-Revision 1.24 2005/04/08 21:30:16 ksekar
-<rdar://problem/4007457> Compiling problems with mDNSResponder-98 on Solaris/Sparc v9
-Patch submitted by Bernd Kuhls
-
-Revision 1.23 2004/12/01 04:25:05 cheshire
-<rdar://problem/3872803> Darwin patches for Solaris and Suse
-Provide daemon() for platforms that don't have it
-
-Revision 1.22 2004/11/30 22:37:01 cheshire
-Update copyright dates and add "Mode: C; tab-width: 4" headers
-
-Revision 1.21 2004/11/08 22:13:59 rpantos
-Create sockf6 lazily when v6 interface found.
-
-Revision 1.20 2004/10/16 00:17:01 cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
-
-Revision 1.19 2004/07/20 01:47:36 rpantos
-NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
-
-Revision 1.18 2004/07/08 21:30:21 rpantos
-
-Revision 1.17 2004/06/25 00:26:27 rpantos
-Changes to fix the Posix build on Solaris.
-
-Revision 1.16 2004/03/20 05:37:09 cheshire
-Fix contributed by Terry Lambert & Alfred Perlstein:
-Don't use uint8_t -- it requires stdint.h, which doesn't exist on FreeBSD 4.x
-
-Revision 1.15 2004/02/14 01:09:45 rpantos
-Just use HAVE_IPV6 rather than defined(HAVE_IPV6).
-
-Revision 1.14 2003/12/11 18:53:40 cheshire
-Fix compiler warning reported by Paul Guyot
-
-Revision 1.13 2003/12/08 20:47:02 rpantos
-Add support for mDNSResponder on Linux.
-
-Revision 1.12 2003/09/02 20:47:13 cheshire
-Fix signed/unsigned warning
-
-Revision 1.11 2003/08/12 19:56:26 cheshire
-Update to APSL 2.0
-
-Revision 1.10 2003/08/06 18:20:51 cheshire
-Makefile cleanup
-
-Revision 1.9 2003/07/14 18:11:54 cheshire
-Fix stricter compiler warnings
-
-Revision 1.8 2003/07/02 21:19:59 cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.7 2003/03/20 21:10:31 cheshire
-Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
-
-Revision 1.6 2003/03/13 03:46:21 cheshire
-Fixes to make the code build on Linux
-
-Revision 1.5 2003/02/07 03:02:02 cheshire
-Submitted by: Mitsutaka Watanabe
-The code saying "index += 1;" was effectively making up random interface index values.
-The right way to find the correct interface index is if_nametoindex();
-
-Revision 1.4 2002/12/23 22:13:31 jgraessl
-
-Reviewed by: Stuart Cheshire
-Initial IPv6 support for mDNSResponder.
-
-Revision 1.3 2002/09/21 20:44:53 zarzycki
-Added APSL info
-
-Revision 1.2 2002/09/19 04:20:44 cheshire
-Remove high-ascii characters that confuse some systems
-
-Revision 1.1 2002/09/17 06:24:34 cheshire
-First checkin
-
-*/
+ */
#include "mDNSUNP.h"
@@ -207,8 +73,8 @@ void plen_to_mask(int plen, char *addr) {
int bits_in_block=16; /* Bits per IPv6 block */
for(i=0;i<=colons;i++) {
int block, ones=0xffff, ones_in_block;
- if(plen>bits_in_block) ones_in_block=bits_in_block;
- else ones_in_block=plen;
+ if (plen>bits_in_block) ones_in_block=bits_in_block;
+ else ones_in_block=plen;
block = ones & (ones << (bits_in_block-ones_in_block));
i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
plen -= ones_in_block;
@@ -241,6 +107,8 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
addr[4],addr[5],addr[6],addr[7],
&index, &plen, &scope, &flags, ifname) != EOF) {
+ char ipv6addr[INET6_ADDRSTRLEN];
+
myflags = 0;
if (strncmp(lastname, ifname, IFNAMSIZ) == 0) {
if (doaliases == 0)
@@ -275,7 +143,6 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
/* Add netmask of the interface */
- char ipv6addr[INET6_ADDRSTRLEN];
plen_to_mask(plen, ipv6addr);
ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
if (ifi->ifi_addr == NULL) {
@@ -338,7 +205,7 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
#endif
#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
- if(family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
+ if (family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
#endif
sockfd = -1;
diff --git a/external/apache2/mDNSResponder/dist/mDNSShared/dns-sd.1 b/external/apache2/mDNSResponder/dist/mDNSShared/dns-sd.1
index 93ca9ae043b..1c48802ce50 100644
--- a/external/apache2/mDNSResponder/dist/mDNSShared/dns-sd.1
+++ b/external/apache2/mDNSResponder/dist/mDNSShared/dns-sd.1
@@ -14,27 +14,6 @@
.\" See the License for the specific language governing permissions and
.\" limitations under the License.
.\"
-.\" Log: dns-sd.1,v $
-.\" Revision 1.6 2006/08/14 23:24:56 cheshire
-.\" Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-.\"
-.\" Revision 1.5 2005/07/04 23:12:35 cheshire
-.\" <rdar://problem/4103628> The dns-sd command first appeared in Mac OS X 10.4 (Tiger)
-.\"
-.\" Revision 1.4 2005/02/16 02:29:32 cheshire
-.\" Update terminology
-.\"
-.\" Revision 1.3 2005/02/10 22:35:28 cheshire
-.\" <rdar://problem/3727944> Update name
-.\"
-.\" Revision 1.2 2004/09/24 18:33:05 cheshire
-.\" <rdar://problem/3561780> Update man pages to clarify that mDNS and dns-sd are not intended for script use
-.\"
-.\" Revision 1.1 2004/09/22 22:46:25 cheshire
-.\" Man page for dns-sd command-line tool
-.\"
-.\"
-.\"
.Dd April 2004 \" Date
.Dt dns-sd 1 \" Document Title
.Os NetBSD \" Operating System
diff --git a/external/apache2/mDNSResponder/dist/mDNSShared/dns_sd.h b/external/apache2/mDNSResponder/dist/mDNSShared/dns_sd.h
index d93f9724bf7..fe61f8cf5c0 100644
--- a/external/apache2/mDNSResponder/dist/mDNSShared/dns_sd.h
+++ b/external/apache2/mDNSResponder/dist/mDNSShared/dns_sd.h
@@ -77,12 +77,19 @@
*/
#ifndef _DNS_SD_H
-#define _DNS_SD_H 2120100
+#define _DNS_SD_H 2581400
#ifdef __cplusplus
extern "C" {
#endif
+/* Set to 1 if libdispatch is supported
+ * Note: May also be set by project and/or Makefile
+ */
+#ifndef _DNS_SD_LIBDISPATCH
+#define _DNS_SD_LIBDISPATCH 0
+#endif /* ndef _DNS_SD_LIBDISPATCH */
+
/* standard calling convention under Win32 is __stdcall */
/* Note: When compiling Intel EFI (Extensible Firmware Interface) under MS Visual Studio, the */
/* _WIN32 symbol is defined by the compiler even though it's NOT compiling code for Windows32 */
@@ -129,6 +136,10 @@ typedef INT32 int32_t;
#include <stdint.h>
#endif
+#if _DNS_SD_LIBDISPATCH
+#include <dispatch/dispatch.h>
+#endif
+
/* DNSServiceRef, DNSRecordRef
*
* Opaque internal data types.
@@ -331,8 +342,15 @@ enum
*/
kDNSServiceFlagsSuppressUnusable = 0x8000
- /* Placeholder definition, for future use
- */
+ /*
+ * This flag is meaningful only in DNSServiceQueryRecord which suppresses unusable queries on the
+ * wire. If "hostname" is a wide-area unicast DNS hostname (i.e. not a ".local." name)
+ * but this host has no routable IPv6 address, then the call will not try to look up IPv6 addresses
+ * for "hostname", since any addresses it found would be unlikely to be of any use anyway. Similarly,
+ * if this host has no routable IPv4 address, the call will not try to look up IPv4 addresses for
+ * "hostname".
+ */
+
};
/* Possible protocols for DNSServiceNATPortMappingCreate(). */
@@ -368,73 +386,73 @@ enum
enum
{
- kDNSServiceType_A = 1, /* Host address. */
- kDNSServiceType_NS = 2, /* Authoritative server. */
- kDNSServiceType_MD = 3, /* Mail destination. */
- kDNSServiceType_MF = 4, /* Mail forwarder. */
- kDNSServiceType_CNAME = 5, /* Canonical name. */
- kDNSServiceType_SOA = 6, /* Start of authority zone. */
- kDNSServiceType_MB = 7, /* Mailbox domain name. */
- kDNSServiceType_MG = 8, /* Mail group member. */
- kDNSServiceType_MR = 9, /* Mail rename name. */
- kDNSServiceType_NULL = 10, /* Null resource record. */
- kDNSServiceType_WKS = 11, /* Well known service. */
- kDNSServiceType_PTR = 12, /* Domain name pointer. */
- kDNSServiceType_HINFO = 13, /* Host information. */
- kDNSServiceType_MINFO = 14, /* Mailbox information. */
- kDNSServiceType_MX = 15, /* Mail routing information. */
- kDNSServiceType_TXT = 16, /* One or more text strings (NOT "zero or more..."). */
- kDNSServiceType_RP = 17, /* Responsible person. */
- kDNSServiceType_AFSDB = 18, /* AFS cell database. */
- kDNSServiceType_X25 = 19, /* X_25 calling address. */
- kDNSServiceType_ISDN = 20, /* ISDN calling address. */
- kDNSServiceType_RT = 21, /* Router. */
- kDNSServiceType_NSAP = 22, /* NSAP address. */
- kDNSServiceType_NSAP_PTR = 23, /* Reverse NSAP lookup (deprecated). */
- kDNSServiceType_SIG = 24, /* Security signature. */
- kDNSServiceType_KEY = 25, /* Security key. */
- kDNSServiceType_PX = 26, /* X.400 mail mapping. */
- kDNSServiceType_GPOS = 27, /* Geographical position (withdrawn). */
- kDNSServiceType_AAAA = 28, /* IPv6 Address. */
- kDNSServiceType_LOC = 29, /* Location Information. */
- kDNSServiceType_NXT = 30, /* Next domain (security). */
- kDNSServiceType_EID = 31, /* Endpoint identifier. */
- kDNSServiceType_NIMLOC = 32, /* Nimrod Locator. */
- kDNSServiceType_SRV = 33, /* Server Selection. */
- kDNSServiceType_ATMA = 34, /* ATM Address */
- kDNSServiceType_NAPTR = 35, /* Naming Authority PoinTeR */
- kDNSServiceType_KX = 36, /* Key Exchange */
- kDNSServiceType_CERT = 37, /* Certification record */
- kDNSServiceType_A6 = 38, /* IPv6 Address (deprecated) */
- kDNSServiceType_DNAME = 39, /* Non-terminal DNAME (for IPv6) */
- kDNSServiceType_SINK = 40, /* Kitchen sink (experimental) */
- kDNSServiceType_OPT = 41, /* EDNS0 option (meta-RR) */
- kDNSServiceType_APL = 42, /* Address Prefix List */
- kDNSServiceType_DS = 43, /* Delegation Signer */
- kDNSServiceType_SSHFP = 44, /* SSH Key Fingerprint */
- kDNSServiceType_IPSECKEY = 45, /* IPSECKEY */
- kDNSServiceType_RRSIG = 46, /* RRSIG */
- kDNSServiceType_NSEC = 47, /* Denial of Existence */
- kDNSServiceType_DNSKEY = 48, /* DNSKEY */
- kDNSServiceType_DHCID = 49, /* DHCP Client Identifier */
- kDNSServiceType_NSEC3 = 50, /* Hashed Authenticated Denial of Existence */
- kDNSServiceType_NSEC3PARAM= 51, /* Hashed Authenticated Denial of Existence */
-
- kDNSServiceType_HIP = 55, /* Host Identity Protocol */
-
- kDNSServiceType_SPF = 99, /* Sender Policy Framework for E-Mail */
- kDNSServiceType_UINFO = 100, /* IANA-Reserved */
- kDNSServiceType_UID = 101, /* IANA-Reserved */
- kDNSServiceType_GID = 102, /* IANA-Reserved */
- kDNSServiceType_UNSPEC = 103, /* IANA-Reserved */
-
- kDNSServiceType_TKEY = 249, /* Transaction key */
- kDNSServiceType_TSIG = 250, /* Transaction signature. */
- kDNSServiceType_IXFR = 251, /* Incremental zone transfer. */
- kDNSServiceType_AXFR = 252, /* Transfer zone of authority. */
- kDNSServiceType_MAILB = 253, /* Transfer mailbox records. */
- kDNSServiceType_MAILA = 254, /* Transfer mail agent records. */
- kDNSServiceType_ANY = 255 /* Wildcard match. */
+ kDNSServiceType_A = 1, /* Host address. */
+ kDNSServiceType_NS = 2, /* Authoritative server. */
+ kDNSServiceType_MD = 3, /* Mail destination. */
+ kDNSServiceType_MF = 4, /* Mail forwarder. */
+ kDNSServiceType_CNAME = 5, /* Canonical name. */
+ kDNSServiceType_SOA = 6, /* Start of authority zone. */
+ kDNSServiceType_MB = 7, /* Mailbox domain name. */
+ kDNSServiceType_MG = 8, /* Mail group member. */
+ kDNSServiceType_MR = 9, /* Mail rename name. */
+ kDNSServiceType_NULL = 10, /* Null resource record. */
+ kDNSServiceType_WKS = 11, /* Well known service. */
+ kDNSServiceType_PTR = 12, /* Domain name pointer. */
+ kDNSServiceType_HINFO = 13, /* Host information. */
+ kDNSServiceType_MINFO = 14, /* Mailbox information. */
+ kDNSServiceType_MX = 15, /* Mail routing information. */
+ kDNSServiceType_TXT = 16, /* One or more text strings (NOT "zero or more..."). */
+ kDNSServiceType_RP = 17, /* Responsible person. */
+ kDNSServiceType_AFSDB = 18, /* AFS cell database. */
+ kDNSServiceType_X25 = 19, /* X_25 calling address. */
+ kDNSServiceType_ISDN = 20, /* ISDN calling address. */
+ kDNSServiceType_RT = 21, /* Router. */
+ kDNSServiceType_NSAP = 22, /* NSAP address. */
+ kDNSServiceType_NSAP_PTR = 23, /* Reverse NSAP lookup (deprecated). */
+ kDNSServiceType_SIG = 24, /* Security signature. */
+ kDNSServiceType_KEY = 25, /* Security key. */
+ kDNSServiceType_PX = 26, /* X.400 mail mapping. */
+ kDNSServiceType_GPOS = 27, /* Geographical position (withdrawn). */
+ kDNSServiceType_AAAA = 28, /* IPv6 Address. */
+ kDNSServiceType_LOC = 29, /* Location Information. */
+ kDNSServiceType_NXT = 30, /* Next domain (security). */
+ kDNSServiceType_EID = 31, /* Endpoint identifier. */
+ kDNSServiceType_NIMLOC = 32, /* Nimrod Locator. */
+ kDNSServiceType_SRV = 33, /* Server Selection. */
+ kDNSServiceType_ATMA = 34, /* ATM Address */
+ kDNSServiceType_NAPTR = 35, /* Naming Authority PoinTeR */
+ kDNSServiceType_KX = 36, /* Key Exchange */
+ kDNSServiceType_CERT = 37, /* Certification record */
+ kDNSServiceType_A6 = 38, /* IPv6 Address (deprecated) */
+ kDNSServiceType_DNAME = 39, /* Non-terminal DNAME (for IPv6) */
+ kDNSServiceType_SINK = 40, /* Kitchen sink (experimental) */
+ kDNSServiceType_OPT = 41, /* EDNS0 option (meta-RR) */
+ kDNSServiceType_APL = 42, /* Address Prefix List */
+ kDNSServiceType_DS = 43, /* Delegation Signer */
+ kDNSServiceType_SSHFP = 44, /* SSH Key Fingerprint */
+ kDNSServiceType_IPSECKEY = 45, /* IPSECKEY */
+ kDNSServiceType_RRSIG = 46, /* RRSIG */
+ kDNSServiceType_NSEC = 47, /* Denial of Existence */
+ kDNSServiceType_DNSKEY = 48, /* DNSKEY */
+ kDNSServiceType_DHCID = 49, /* DHCP Client Identifier */
+ kDNSServiceType_NSEC3 = 50, /* Hashed Authenticated Denial of Existence */
+ kDNSServiceType_NSEC3PARAM = 51, /* Hashed Authenticated Denial of Existence */
+
+ kDNSServiceType_HIP = 55, /* Host Identity Protocol */
+
+ kDNSServiceType_SPF = 99, /* Sender Policy Framework for E-Mail */
+ kDNSServiceType_UINFO = 100, /* IANA-Reserved */
+ kDNSServiceType_UID = 101, /* IANA-Reserved */
+ kDNSServiceType_GID = 102, /* IANA-Reserved */
+ kDNSServiceType_UNSPEC = 103, /* IANA-Reserved */
+
+ kDNSServiceType_TKEY = 249, /* Transaction key */
+ kDNSServiceType_TSIG = 250, /* Transaction signature. */
+ kDNSServiceType_IXFR = 251, /* Incremental zone transfer. */
+ kDNSServiceType_AXFR = 252, /* Transfer zone of authority. */
+ kDNSServiceType_MAILB = 253, /* Transfer mailbox records. */
+ kDNSServiceType_MAILA = 254, /* Transfer mail agent records. */
+ kDNSServiceType_ANY = 255 /* Wildcard match. */
};
/* possible error code values */
@@ -514,7 +532,7 @@ enum
*
* The servicename may be up to 63 bytes of UTF-8 text (not counting the C-String
* terminating NULL at the end). The regtype is of the form _service._tcp or
- * _service._udp, where the "service" part is 1-14 characters, which may be
+ * _service._udp, where the "service" part is 1-15 characters, which may be
* letters, digits, or hyphens. The domain part of the three-part name may be
* any legal domain, providing that the resulting servicename+regtype+domain
* name does not exceed 256 bytes.
@@ -567,11 +585,30 @@ enum
* accomplish this by inspecting the interfaceIndex of each service reported
* to their DNSServiceBrowseReply() callback function, and discarding those
* where the interface index is not kDNSServiceInterfaceIndexLocalOnly.
+ *
+ * kDNSServiceInterfaceIndexP2P is meaningful only in Browse, QueryRecord,
+ * and Resolve operations. It should not be used in other DNSService APIs.
+ *
+ * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceBrowse or
+ * DNSServiceQueryRecord, it restricts the operation to P2P.
+ *
+ * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceResolve, it is
+ * mapped internally to kDNSServiceInterfaceIndexAny, because resolving
+ * a P2P service may create and/or enable an interface whose index is not
+ * known a priori. The resolve callback will indicate the index of the
+ * interface via which the service can be accessed.
+ *
+ * If applications pass kDNSServiceInterfaceIndexAny to DNSServiceBrowse
+ * or DNSServiceQueryRecord, the operation will also include P2P. In this
+ * case, if a service instance or the record being queried is found over P2P,
+ * the resulting ADD event will indicate kDNSServiceInterfaceIndexP2P as the
+ * interface index.
*/
#define kDNSServiceInterfaceIndexAny 0
#define kDNSServiceInterfaceIndexLocalOnly ((uint32_t)-1)
#define kDNSServiceInterfaceIndexUnicast ((uint32_t)-2)
+#define kDNSServiceInterfaceIndexP2P ((uint32_t)-3)
typedef uint32_t DNSServiceFlags;
typedef uint32_t DNSServiceProtocol;
@@ -886,7 +923,7 @@ typedef void (DNSSD_API *DNSServiceRegisterReply)
*
* regtype: The service type followed by the protocol, separated by a dot
* (e.g. "_ftp._tcp"). The service type must be an underscore, followed
- * by 1-14 characters, which may be letters, digits, or hyphens.
+ * by 1-15 characters, which may be letters, digits, or hyphens.
* The transport protocol must be "_tcp" or "_udp". New service types
* should be registered at <http://www.dns-sd.org/ServiceTypes.html>.
*
@@ -912,6 +949,13 @@ typedef void (DNSSD_API *DNSServiceRegisterReply)
* % dns-sd -B _test._tcp,HasFeatureA # finds "Better" and "Best"
* % dns-sd -B _test._tcp,HasFeatureB # finds only "Best"
*
+ * Subtype labels may be up to 63 bytes long, and may contain any eight-
+ * bit byte values, including zero bytes. However, due to the nature of
+ * using a C-string-based API, conventional DNS escaping must be used for
+ * dots ('.'), commas (','), backslashes ('\') and zero bytes, as shown below:
+ *
+ * % dns-sd -R Test '_test._tcp,s\.one,s\,two,s\\three,s\000four' local 123
+ *
* domain: If non-NULL, specifies the domain on which to advertise the service.
* Most applications will not specify a domain, instead automatically
* registering in the default domain(s).
@@ -965,7 +1009,7 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister
const char *regtype,
const char *domain, /* may be NULL */
const char *host, /* may be NULL */
- uint16_t port,
+ uint16_t port, /* In network byte order */
uint16_t txtLen,
const void *txtRecord, /* may be NULL */
DNSServiceRegisterReply callBack, /* may be NULL */
@@ -1267,7 +1311,7 @@ typedef void (DNSSD_API *DNSServiceResolveReply)
DNSServiceErrorType errorCode,
const char *fullname,
const char *hosttarget,
- uint16_t port,
+ uint16_t port, /* In network byte order */
uint16_t txtLen,
const unsigned char *txtRecord,
void *context
@@ -1528,11 +1572,6 @@ typedef void (DNSSD_API *DNSServiceGetAddrInfoReply)
* unlikely to be of any use anyway. Similarly, if this host has no routable
* IPv4 address, the call will not try to look up IPv4 addresses for "hostname".
*
- * * If "hostname" is a link-local multicast DNS hostname (i.e. a ".local." name)
- * but this host has no IPv6 address of any kind, then it will not try to look
- * up IPv6 addresses for "hostname". Similarly, if this host has no IPv4 address
- * of any kind, the call will not try to look up IPv4 addresses for "hostname".
- *
* hostname: The fully qualified domain name of the host to be queried for.
*
* callBack: The function to be called when the query succeeds or fails asynchronously.
@@ -1735,7 +1774,8 @@ DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
/* DNSServiceNATPortMappingCreate
*
* Request a port mapping in the NAT gateway, which maps a port on the local machine
- * to an external port on the NAT.
+ * to an external port on the NAT. The NAT should support either the NAT-PMP or the UPnP IGD
+ * protocol for this API to create a successful mapping.
*
* The port mapping will be renewed indefinitely until the client process exits, or
* explicitly terminates the port mapping request by calling DNSServiceRefDeallocate().
@@ -1836,9 +1876,9 @@ typedef void (DNSSD_API *DNSServiceNATPortMappingReply)
DNSServiceErrorType errorCode,
uint32_t externalAddress, /* four byte IPv4 address in network byte order */
DNSServiceProtocol protocol,
- uint16_t internalPort,
- uint16_t externalPort, /* may be different than the requested port */
- uint32_t ttl, /* may be different than the requested ttl */
+ uint16_t internalPort, /* In network byte order */
+ uint16_t externalPort, /* In network byte order and may be different than the requested port */
+ uint32_t ttl, /* may be different than the requested ttl */
void *context
);
@@ -1940,10 +1980,10 @@ DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
DNSServiceErrorType DNSSD_API DNSServiceConstructFullName
(
- char *fullName,
- const char *service, /* may be NULL */
- const char *regtype,
- const char *domain
+ char * const fullName,
+ const char * const service, /* may be NULL */
+ const char * const regtype,
+ const char * const domain
);
@@ -2299,41 +2339,56 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
const void **value
);
-#ifdef __APPLE_API_PRIVATE
-
+#if _DNS_SD_LIBDISPATCH
/*
- * Mac OS X specific functionality
- * 3rd party clients of this API should not depend on future support or availability of this routine
- */
+* DNSServiceSetDispatchQueue
+*
+* Allows you to schedule a DNSServiceRef on a serial dispatch queue for receiving asynchronous
+* callbacks. It's the clients responsibility to ensure that the provided dispatch queue is running.
+*
+* A typical application that uses CFRunLoopRun or dispatch_main on its main thread will
+* usually schedule DNSServiceRefs on its main queue (which is always a serial queue)
+* using "DNSServiceSetDispatchQueue(sdref, dispatch_get_main_queue());"
+*
+* If there is any error during the processing of events, the application callback will
+* be called with an error code. For shared connections, each subordinate DNSServiceRef
+* will get its own error callback. Currently these error callbacks only happen
+* if the mDNSResponder daemon is manually terminated or crashes, and the error
+* code in this case is kDNSServiceErr_ServiceNotRunning. The application must call
+* DNSServiceRefDeallocate to free the DNSServiceRef when it gets such an error code.
+* These error callbacks are rare and should not normally happen on customer machines,
+* but application code should be written defensively to handle such error callbacks
+* gracefully if they occur.
+*
+* After using DNSServiceSetDispatchQueue on a DNSServiceRef, calling DNSServiceProcessResult
+* on the same DNSServiceRef will result in undefined behavior and should be avoided.
+*
+* Once the application successfully schedules a DNSServiceRef on a serial dispatch queue using
+* DNSServiceSetDispatchQueue, it cannot remove the DNSServiceRef from the dispatch queue, or use
+* DNSServiceSetDispatchQueue a second time to schedule the DNSServiceRef onto a different serial dispatch
+* queue. Once scheduled onto a dispatch queue a DNSServiceRef will deliver events to that queue until
+* the application no longer requires that operation and terminates it using DNSServiceRefDeallocate.
+*
+* service: DNSServiceRef that was allocated and returned to the application, when the
+* application calls one of the DNSService API.
+*
+* queue: dispatch queue where the application callback will be scheduled
+*
+* return value: Returns kDNSServiceErr_NoError on success.
+* Returns kDNSServiceErr_NoMemory if it cannot create a dispatch source
+* Returns kDNSServiceErr_BadParam if the service param is invalid or the
+* queue param is invalid
+*/
+
+DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
+ (
+ DNSServiceRef service,
+ dispatch_queue_t queue
+ );
+#endif //_DNS_SD_LIBDISPATCH
-/* DNSServiceSetDefaultDomainForUser()
- *
- * Set the default domain for the caller's UID. Future browse and registration
- * calls by this user that do not specify an explicit domain will browse and
- * register in this wide-area domain in addition to .local. In addition, this
- * domain will be returned as a Browse domain via domain enumeration calls.
- *
- * Parameters:
- *
- * flags: Pass kDNSServiceFlagsAdd to add a domain for a user. Call without
- * this flag set to clear a previously added domain.
- *
- * domain: The domain to be used for the caller's UID.
- *
- * return value: Returns kDNSServiceErr_NoError on success, otherwise returns
- * an error code indicating the error that occurred.
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
- (
- DNSServiceFlags flags,
- const char *domain
- );
+#ifdef __APPLE_API_PRIVATE
-/* Symbol defined to tell System Configuration Framework where to look in the Dynamic Store
- * for the list of PrivateDNS domains that need to be handed off to mDNSResponder
- * (the complete key is "State:/Network/PrivateDNS")
- */
#define kDNSServiceCompPrivateDNS "PrivateDNS"
#define kDNSServiceCompMulticastDNS "MulticastDNS"
diff --git a/external/apache2/mDNSResponder/dist/mDNSShared/dnssd_clientlib.c b/external/apache2/mDNSResponder/dist/mDNSShared/dnssd_clientlib.c
index 4f30820c610..8abbb6d0896 100644
--- a/external/apache2/mDNSResponder/dist/mDNSShared/dnssd_clientlib.c
+++ b/external/apache2/mDNSResponder/dist/mDNSShared/dnssd_clientlib.c
@@ -24,79 +24,6 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- Change History (most recent first):
-
-Log: dnssd_clientlib.c,v $
-Revision 1.21 2009/04/01 21:10:11 herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows. Use _stricmp and _strnicmp.
-
-Revision 1.20 2008/11/26 20:57:37 cheshire
-For consistency with other similar macros, renamed mdnsIsDigit/mdnsIsLetter/mdnsValidHostChar
-to mDNSIsDigit/mDNSIsLetter/mDNSValidHostChar
-
-Revision 1.19 2008/11/04 21:15:18 cheshire
-<rdar://problem/5969564> Potential buffer overflows in DNSServiceConstructFullName
-
-Revision 1.18 2007/11/30 23:06:10 cheshire
-Fixed compile warning: declaration of 'index' shadows a global declaration
-
-Revision 1.17 2007/10/02 19:36:04 cheshire
-<rdar://problem/5516444> TXTRecordGetValuePtr should be case-insenstive
-
-Revision 1.16 2007/09/18 19:09:02 cheshire
-<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
-
-Revision 1.15 2007/07/28 00:00:43 cheshire
-Renamed CompileTimeAssertionCheck structure for consistency with others
-
-Revision 1.14 2007/03/20 17:07:16 cheshire
-Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-
-Revision 1.13 2007/02/27 00:25:03 cheshire
-<rdar://problem/5010640> DNSServiceConstructFullName() doesn't handle empty string for instance name
-
-Revision 1.12 2007/02/07 19:32:00 cheshire
-<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
-
-Revision 1.11 2006/08/14 23:05:53 cheshire
-Added "tab-width" emacs header line
-
-Revision 1.10 2005/04/06 02:06:56 shersche
-Add DNSSD_API macro to TXTRecord API calls
-
-Revision 1.9 2004/10/06 02:22:19 cheshire
-Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
-
-Revision 1.8 2004/10/01 22:15:55 rpantos
-rdar://problem/3824265: Replace APSL in client lib with BSD license.
-
-Revision 1.7 2004/06/26 03:16:34 shersche
-clean up warning messages on Win32 platform
-
-Submitted by: herscher
-
-Revision 1.6 2004/06/12 01:09:45 cheshire
-To be callable from the broadest range of clients on Windows (e.g. Visual Basic, C#, etc.)
-API routines have to be declared as "__stdcall", instead of the C default, "__cdecl"
-
-Revision 1.5 2004/05/25 18:29:33 cheshire
-Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
-so that it's also accessible to dnssd_clientshim.c (single address space) clients.
-
-Revision 1.4 2004/05/25 17:08:55 cheshire
-Fix compiler warning (doesn't make sense for function return type to be const)
-
-Revision 1.3 2004/05/21 21:41:35 cheshire
-Add TXT record building and parsing APIs
-
-Revision 1.2 2004/05/20 22:22:21 cheshire
-Enable code that was bracketed by "#if 0"
-
-Revision 1.1 2004/03/12 21:30:29 cheshire
-Build a System-Context Shared Library from mDNSCore, for the benefit of developers
-like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
-
*/
#include <stdlib.h>
diff --git a/external/apache2/mDNSResponder/dist/mDNSShared/dnssd_clientstub.c b/external/apache2/mDNSResponder/dist/mDNSShared/dnssd_clientstub.c
index 47971230baf..14e3e86bfde 100644
--- a/external/apache2/mDNSResponder/dist/mDNSShared/dnssd_clientstub.c
+++ b/external/apache2/mDNSResponder/dist/mDNSShared/dnssd_clientstub.c
@@ -24,290 +24,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- Change History (most recent first):
-
-Log: dnssd_clientstub.c,v $
-Revision 1.134 2009/06/19 23:13:24 cheshire
-<rdar://problem/6990066> Library: crash at handle_resolve_response + 183
-Added check for NULL after calling get_string
-
-Revision 1.133 2009/05/27 22:19:12 cheshire
-Remove questionable uses of errno
-
-Revision 1.132 2009/05/26 21:31:07 herscher
-Fix compile errors on Windows
-
-Revision 1.131 2009/05/26 04:48:19 herscher
-<rdar://problem/6844819> ExplorerPlugin does not work in B4W 2.0
-
-Revision 1.130 2009/05/02 01:29:48 mcguire
-<rdar://problem/6847601> spin calling DNSServiceProcessResult if errno was set to EWOULDBLOCK by an unrelated call
-
-Revision 1.129 2009/05/01 19:18:50 cheshire
-<rdar://problem/6843645> Using duplicate DNSServiceRefs when sharing a connection should return an error
-
-Revision 1.128 2009/04/01 21:09:35 herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows.
-
-Revision 1.127 2009/03/03 21:38:19 cheshire
-Improved "deliver_request ERROR" message
-
-Revision 1.126 2009/02/12 21:02:22 cheshire
-Commented out BPF "Sending fd" debugging message
-
-Revision 1.125 2009/02/12 20:28:32 cheshire
-Added some missing "const" declarations
-
-Revision 1.124 2009/02/10 01:44:39 cheshire
-<rdar://problem/6553729> DNSServiceUpdateRecord fails with kDNSServiceErr_BadReference for otherwise valid reference
-
-Revision 1.123 2009/01/19 00:49:21 mkrochma
-Type cast size_t values to unsigned long
-
-Revision 1.122 2009/01/18 03:51:37 mkrochma
-Fix warning in deliver_request on Linux
-
-Revision 1.121 2009/01/16 23:34:37 cheshire
-<rdar://problem/6504143> Uninitialized error code variable in error handling path in deliver_request
-
-Revision 1.120 2009/01/13 05:31:35 mkrochma
-<rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
-
-Revision 1.119 2009/01/11 03:45:08 mkrochma
-Stop type casting num_written and num_read to int
-
-Revision 1.118 2009/01/11 03:20:06 mkrochma
-<rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris
-
-Revision 1.117 2009/01/10 22:03:43 mkrochma
-<rdar://problem/5797507> dnsextd fails to build on Linux
-
-Revision 1.116 2009/01/05 16:55:24 cheshire
-<rdar://problem/6452199> Stuck in "Examining available disks"
-ConnectionResponse handler was accidentally matching the parent DNSServiceRef before
-finding the appropriate subordinate DNSServiceRef for the operation in question.
-
-Revision 1.115 2008/12/18 00:19:11 mcguire
-<rdar://problem/6452199> Stuck in "Examining available disks"
-
-Revision 1.114 2008/12/10 02:11:43 cheshire
-ARMv5 compiler doesn't like uncommented stuff after #endif
-
-Revision 1.113 2008/12/04 03:23:05 cheshire
-Preincrement UID counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear
-
-Revision 1.112 2008/11/25 22:56:54 cheshire
-<rdar://problem/6377257> Make library code more defensive when client calls DNSServiceProcessResult with bad DNSServiceRef repeatedly
-
-Revision 1.111 2008/10/28 17:58:44 cheshire
-If client code keeps calling DNSServiceProcessResult repeatedly after an error, rate-limit the
-"DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function" log messages
-
-Revision 1.110 2008/10/23 23:38:58 cheshire
-For Windows compatibility, instead of "strerror(errno)" use "dnssd_strerror(dnssd_errno)"
-
-Revision 1.109 2008/10/23 23:06:17 cheshire
-Removed () from dnssd_errno macro definition -- it's not a function and doesn't need any arguments
-
-Revision 1.108 2008/10/23 22:33:24 cheshire
-Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
-
-Revision 1.107 2008/10/20 21:50:11 cheshire
-Improved /dev/bpf error message
-
-Revision 1.106 2008/10/20 15:37:18 cheshire
-Log error message if opening /dev/bpf fails
-
-Revision 1.105 2008/09/27 01:26:34 cheshire
-Added handler to pass back BPF fd when requested
-
-Revision 1.104 2008/09/23 01:36:00 cheshire
-Updated code to use internalPort/externalPort terminology, instead of the old privatePort/publicPort
-terms (which could be misleading, because the word "private" suggests security).
-
-Revision 1.103 2008/07/24 18:51:13 cheshire
-Removed spurious spaces
-
-Revision 1.102 2008/02/25 19:16:19 cheshire
-<rdar://problem/5708953> Problems with DNSServiceGetAddrInfo API
-Was returning a bogus result (NULL pointer) when following a CNAME referral
-
-Revision 1.101 2008/02/20 21:18:21 cheshire
-<rdar://problem/5708953> DNSServiceGetAddrInfo doesn't set the scope ID of returned IPv6 link local addresses
-
-Revision 1.100 2007/11/02 17:56:37 cheshire
-<rdar://problem/5565787> Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails)
-Wrap hack code in "#if APPLE_OSX_mDNSResponder" since (as far as we know right now)
-we don't want to do this on 64-bit Linux, Solaris, etc.
-
-Revision 1.99 2007/11/02 17:29:40 cheshire
-<rdar://problem/5565787> Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails)
-To get 64-bit code that works, we need to NOT use the standard CMSG_* macros
-
-Revision 1.98 2007/11/01 19:52:43 cheshire
-Wrap debugging messages in "#if DEBUG_64BIT_SCM_RIGHTS"
-
-Revision 1.97 2007/11/01 19:45:55 cheshire
-Added "DEBUG_64BIT_SCM_RIGHTS" debugging code
-See <rdar://problem/5565787> Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails)
-
-Revision 1.96 2007/11/01 15:59:33 cheshire
-umask not being set and restored properly in USE_NAMED_ERROR_RETURN_SOCKET code
-(no longer used on OS X, but relevant for other platforms)
-
-Revision 1.95 2007/10/31 20:07:16 cheshire
-<rdar://problem/5541498> Set SO_NOSIGPIPE on client socket
-Refinement: the cleanup code still needs to close listenfd when necesssary
-
-Revision 1.94 2007/10/15 22:34:27 cheshire
-<rdar://problem/5541498> Set SO_NOSIGPIPE on client socket
-
-Revision 1.93 2007/10/10 00:48:54 cheshire
-<rdar://problem/5526379> Daemon spins in an infinite loop when it doesn't get the control message it's expecting
-
-Revision 1.92 2007/10/06 03:44:44 cheshire
-Testing code for <rdar://problem/5526374> kqueue does not get a kevent to wake it up when a control message arrives on a socket
-
-Revision 1.91 2007/10/04 20:53:59 cheshire
-Improved debugging message when sendmsg fails
-
-Revision 1.90 2007/09/30 00:09:27 cheshire
-<rdar://problem/5492315> Pass socket fd via SCM_RIGHTS sendmsg instead of using named UDS in the filesystem
-
-Revision 1.89 2007/09/19 23:53:12 cheshire
-Fixed spelling mistake in comment
-
-Revision 1.88 2007/09/07 23:18:27 cheshire
-<rdar://problem/5467542> Change "client_context" to be an incrementing 64-bit counter
-
-Revision 1.87 2007/09/07 22:50:09 cheshire
-Added comment explaining moreptr field in DNSServiceOp structure
-
-Revision 1.86 2007/09/07 20:21:22 cheshire
-<rdar://problem/5462371> Make DNSSD library more resilient
-Add more comments explaining the moreptr/morebytes logic; don't allow DNSServiceRefSockFD or
-DNSServiceProcessResult for subordinate DNSServiceRefs created using kDNSServiceFlagsShareConnection
-
-Revision 1.85 2007/09/06 21:43:23 cheshire
-<rdar://problem/5462371> Make DNSSD library more resilient
-Allow DNSServiceRefDeallocate from within DNSServiceProcessResult callback
-
-Revision 1.84 2007/09/06 18:31:47 cheshire
-<rdar://problem/5462371> Make DNSSD library more resilient against client programming errors
-
-Revision 1.83 2007/08/28 20:45:45 cheshire
-Typo: ctrl_path needs to be 64 bytes, not 44 bytes
-
-Revision 1.82 2007/08/28 19:53:52 cheshire
-<rdar://problem/5437423> Bonjour failures when /tmp is not writable (e.g. when booted from installer disc)
-
-Revision 1.81 2007/07/27 00:03:20 cheshire
-Fixed compiler warnings that showed up now we're building optimized ("-Os")
-
-Revision 1.80 2007/07/23 22:12:53 cheshire
-<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
-
-Revision 1.79 2007/07/23 19:58:24 cheshire
-<rdar://problem/5351640> Library: Leak in DNSServiceRefDeallocate
-
-Revision 1.78 2007/07/12 20:42:27 cheshire
-<rdar://problem/5280735> If daemon is killed, return kDNSServiceErr_ServiceNotRunning
-to clients instead of kDNSServiceErr_Unknown
-
-Revision 1.77 2007/07/02 23:07:13 cheshire
-<rdar://problem/5308280> Reduce DNS-SD client syslog error messages
-
-Revision 1.76 2007/06/22 20:12:18 cheshire
-<rdar://problem/5277024> Leak in DNSServiceRefDeallocate
-
-Revision 1.75 2007/05/23 18:59:22 cheshire
-Remove unnecessary IPC_FLAGS_REUSE_SOCKET
-
-Revision 1.74 2007/05/22 18:28:38 cheshire
-Fixed compile errors in posix build
-
-Revision 1.73 2007/05/22 01:20:47 cheshire
-To determine current operation, need to check hdr->op, not sdr->op
-
-Revision 1.72 2007/05/22 01:07:42 cheshire
-<rdar://problem/3563675> API: Need a way to get version/feature information
-
-Revision 1.71 2007/05/18 23:55:22 cheshire
-<rdar://problem/4454655> Allow multiple register/browse/resolve operations to share single Unix Domain Socket
-
-Revision 1.70 2007/05/17 20:58:22 cheshire
-<rdar://problem/4647145> DNSServiceQueryRecord should return useful information with NXDOMAIN
-
-Revision 1.69 2007/05/16 16:58:27 cheshire
-<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
-As long as select indicates that data is waiting, loop within DNSServiceProcessResult delivering additional results
-
-Revision 1.68 2007/05/16 01:06:52 cheshire
-<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
-
-Revision 1.67 2007/05/15 21:57:16 cheshire
-<rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
-assuming that all negative values (or zero!) are invalid socket numbers
-
-Revision 1.66 2007/03/27 22:23:04 cheshire
-Add "dnssd_clientstub" prefix onto syslog messages
-
-Revision 1.65 2007/03/21 22:25:23 cheshire
-<rdar://problem/4172796> Remove client retry logic now that mDNSResponder uses launchd for its Unix Domain Socket
-
-Revision 1.64 2007/03/21 19:01:56 cheshire
-<rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits
-
-Revision 1.63 2007/03/12 21:48:21 cheshire
-<rdar://problem/5000162> Scary unlink errors in system.log
-Code was using memory after it had been freed
-
-Revision 1.62 2007/02/28 01:44:30 cheshire
-<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
-
-Revision 1.61 2007/02/09 03:09:42 cheshire
-<rdar://problem/3869251> Cleanup: Stop returning kDNSServiceErr_Unknown so often
-<rdar://problem/4177924> API: Should return kDNSServiceErr_ServiceNotRunning
-
-Revision 1.60 2007/02/08 20:33:44 cheshire
-<rdar://problem/4985095> Leak on error path in DNSServiceProcessResult
-
-Revision 1.59 2007/01/05 08:30:55 cheshire
-Trim excessive "Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.58 2006/10/27 00:38:22 cheshire
-Strip accidental trailing whitespace from lines
-
-Revision 1.57 2006/09/30 01:06:54 cheshire
-Protocol field should be uint32_t
-
-Revision 1.56 2006/09/27 00:44:16 herscher
-<rdar://problem/4249761> API: Need DNSServiceGetAddrInfo()
-
-Revision 1.55 2006/09/26 01:52:01 herscher
-<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
-
-Revision 1.54 2006/09/21 21:34:09 cheshire
-<rdar://problem/4100000> Allow empty string name when using kDNSServiceFlagsNoAutoRename
-
-Revision 1.53 2006/09/07 04:43:12 herscher
-Fix compile error on Win32 platform by moving inclusion of syslog.h
-
-Revision 1.52 2006/08/15 23:04:21 mkrochma
-<rdar://problem/4090354> Client should be able to specify service name w/o callback
-
-Revision 1.51 2006/07/24 23:45:55 cheshire
-<rdar://problem/4605276> DNSServiceReconfirmRecord() should return error code
-
-Revision 1.50 2006/06/28 08:22:27 cheshire
-<rdar://problem/4605264> dnssd_clientstub.c needs to report unlink failures in syslog
-
-Revision 1.49 2006/06/28 07:58:59 cheshire
-Minor textual tidying
-
-*/
+ */
#include <errno.h>
#include <stdlib.h>
@@ -345,6 +62,7 @@ Minor textual tidying
int len;
char * buffer;
DWORD err = WSAGetLastError();
+ (void) priority;
va_start( args, message );
len = _vscprintf( message, args ) + 1;
buffer = malloc( len * sizeof(char) );
@@ -394,25 +112,34 @@ typedef void (*ProcessReplyFn)(DNSServiceOp *const sdr, const CallbackHeader *co
// When using kDNSServiceFlagsShareConnection, there is one primary _DNSServiceOp_t, and zero or more subordinates
// For the primary, the 'next' field points to the first subordinate, and its 'next' field points to the next, and so on.
// For the primary, the 'primary' field is NULL; for subordinates the 'primary' field points back to the associated primary
+//
+// _DNS_SD_LIBDISPATCH is defined where libdispatch/GCD is available. This does not mean that the application will use the
+// DNSServiceSetDispatchQueue API. Hence any new code guarded with _DNS_SD_LIBDISPATCH should still be backwards compatible.
struct _DNSServiceRef_t
{
- DNSServiceOp *next; // For shared connection
- DNSServiceOp *primary; // For shared connection
- dnssd_sock_t sockfd; // Connected socket between client and daemon
- dnssd_sock_t validator; // Used to detect memory corruption, double disposals, etc.
- client_context_t uid; // For shared connection requests, each subordinate DNSServiceRef has its own ID,
+ DNSServiceOp *next; // For shared connection
+ DNSServiceOp *primary; // For shared connection
+ dnssd_sock_t sockfd; // Connected socket between client and daemon
+ dnssd_sock_t validator; // Used to detect memory corruption, double disposals, etc.
+ client_context_t uid; // For shared connection requests, each subordinate DNSServiceRef has its own ID,
// unique within the scope of the same shared parent DNSServiceRef
- uint32_t op; // request_op_t or reply_op_t
- uint32_t max_index; // Largest assigned record index - 0 if no additional records registered
- uint32_t logcounter; // Counter used to control number of syslog messages we write
- int *moreptr; // Set while DNSServiceProcessResult working on this particular DNSServiceRef
- ProcessReplyFn ProcessReply; // Function pointer to the code to handle received messages
- void *AppCallback; // Client callback function and context
- void *AppContext;
+ uint32_t op; // request_op_t or reply_op_t
+ uint32_t max_index; // Largest assigned record index - 0 if no additional records registered
+ uint32_t logcounter; // Counter used to control number of syslog messages we write
+ int *moreptr; // Set while DNSServiceProcessResult working on this particular DNSServiceRef
+ ProcessReplyFn ProcessReply; // Function pointer to the code to handle received messages
+ void *AppCallback; // Client callback function and context
+ void *AppContext;
+ DNSRecord *rec;
+#if _DNS_SD_LIBDISPATCH
+ dispatch_source_t disp_source;
+ dispatch_queue_t disp_queue;
+#endif
};
struct _DNSRecordRef_t
{
+ DNSRecord *recnext;
void *AppContext;
DNSServiceRegisterRecordReply AppCallback;
DNSRecordRef recref;
@@ -421,20 +148,35 @@ struct _DNSRecordRef_t
};
// Write len bytes. Return 0 on success, -1 on error
-static int write_all(dnssd_sock_t sd, char *buf, int len)
+static int write_all(dnssd_sock_t sd, char *buf, size_t len)
{
// Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
//if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
while (len)
{
- ssize_t num_written = send(sd, buf, len, 0);
- if (num_written < 0 || num_written > len)
+ ssize_t num_written = send(sd, buf, (long)len, 0);
+ if (num_written < 0 || (size_t)num_written > len)
{
// Should never happen. If it does, it indicates some OS bug,
// or that the mDNSResponder daemon crashed (which should never happen).
- syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %zd/%d %d %s", sd, num_written, len,
+ #if !defined(__ppc__) && defined(SO_ISDEFUNCT)
+ int defunct;
+ socklen_t dlen = sizeof (defunct);
+ if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
+ syslog(LOG_WARNING, "dnssd_clientstub write_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ if (!defunct)
+ syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
+ (long)num_written, (long)len,
+ (num_written < 0) ? dnssd_errno : 0,
+ (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
+ else
+ syslog(LOG_INFO, "dnssd_clientstub write_all(%d) DEFUNCT", sd);
+ #else
+ syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
+ (long)num_written, (long)len,
(num_written < 0) ? dnssd_errno : 0,
(num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
+ #endif
return -1;
}
buf += num_written;
@@ -445,7 +187,7 @@ static int write_all(dnssd_sock_t sd, char *buf, int len)
enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2 };
-// Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for
+// Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for
static int read_all(dnssd_sock_t sd, char *buf, int len)
{
// Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
@@ -456,11 +198,32 @@ static int read_all(dnssd_sock_t sd, char *buf, int len)
ssize_t num_read = recv(sd, buf, len, 0);
if ((num_read == 0) || (num_read < 0) || (num_read > len))
{
+ int printWarn = 0;
+ int defunct = 0;
// Should never happen. If it does, it indicates some OS bug,
// or that the mDNSResponder daemon crashed (which should never happen).
- syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %zd/%d %d %s", sd, num_read, len,
- (num_read < 0) ? dnssd_errno : 0,
- (num_read < 0) ? dnssd_strerror(dnssd_errno) : "");
+#if defined(WIN32)
+ // <rdar://problem/7481776> Suppress logs for "A non-blocking socket operation
+ // could not be completed immediately"
+ if (WSAGetLastError() != WSAEWOULDBLOCK)
+ printWarn = 1;
+#endif
+#if !defined(__ppc__) && defined(SO_ISDEFUNCT)
+ {
+ socklen_t dlen = sizeof (defunct);
+ if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
+ syslog(LOG_WARNING, "dnssd_clientstub read_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ }
+ if (!defunct)
+ printWarn = 1;
+#endif
+ if (printWarn)
+ syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %ld/%ld %d %s", sd,
+ (long)num_read, (long)len,
+ (num_read < 0) ? dnssd_errno : 0,
+ (num_read < 0) ? dnssd_strerror(dnssd_errno) : "");
+ else if (defunct)
+ syslog(LOG_INFO, "dnssd_clientstub read_all(%d) DEFUNCT", sd);
return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : read_all_fail;
}
buf += num_read;
@@ -474,9 +237,29 @@ static int more_bytes(dnssd_sock_t sd)
{
struct timeval tv = { 0, 0 };
fd_set readfds;
- FD_ZERO(&readfds);
- FD_SET(sd, &readfds);
- return(select(sd+1, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv) > 0);
+ fd_set *fs;
+ int ret;
+
+ if (sd < FD_SETSIZE)
+ {
+ fs = &readfds;
+ FD_ZERO(fs);
+ }
+ else
+ {
+ // Compute the number of integers needed for storing "sd". Internally fd_set is stored
+ // as an array of ints with one bit for each fd and hence we need to compute
+ // the number of ints needed rather than the number of bytes. If "sd" is 32, we need
+ // two ints and not just one.
+ int nfdbits = sizeof (int) * 8;
+ int nints = (sd/nfdbits) + 1;
+ fs = (fd_set *)calloc(nints, sizeof(int));
+ if (fs == NULL) { syslog(LOG_WARNING, "dnssd_clientstub more_bytes: malloc failed"); return 0; }
+ }
+ FD_SET(sd, fs);
+ ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv);
+ if (fs != &readfds) free(fs);
+ return (ret > 0);
}
/* create_hdr
@@ -503,11 +286,11 @@ static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int
#if defined(USE_TCP_LOOPBACK)
*len += 2; // Allocate space for two-byte port number
#elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
- struct timeval time;
- if (gettimeofday(&time, NULL) < 0)
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) < 0)
{ syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); return NULL; }
sprintf(ctrl_path, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(),
- (unsigned long)(time.tv_sec & 0xFFF), (unsigned long)(time.tv_usec));
+ (unsigned long)(tv.tv_sec & 0xFFF), (unsigned long)(tv.tv_usec));
*len += strlen(ctrl_path) + 1;
#else
*len += 1; // Allocate space for single zero byte (empty C string)
@@ -540,9 +323,20 @@ static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int
return hdr;
}
+static void FreeDNSRecords(DNSServiceOp *sdRef)
+ {
+ DNSRecord *rec = sdRef->rec;
+ while (rec)
+ {
+ DNSRecord *next = rec->recnext;
+ free(rec);
+ rec = next;
+ }
+ }
+
static void FreeDNSServiceOp(DNSServiceOp *x)
{
- // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed
+ // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed
// then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket)
if ((x->sockfd ^ x->validator) != ValidatorBits)
syslog(LOG_WARNING, "dnssd_clientstub attempt to dispose invalid DNSServiceRef %p %08X %08X", x, x->sockfd, x->validator);
@@ -559,6 +353,16 @@ static void FreeDNSServiceOp(DNSServiceOp *x)
x->ProcessReply = NULL;
x->AppCallback = NULL;
x->AppContext = NULL;
+ x->rec = NULL;
+#if _DNS_SD_LIBDISPATCH
+ if (x->disp_source) dispatch_release(x->disp_source);
+ x->disp_source = NULL;
+ x->disp_queue = NULL;
+#endif
+ // DNSRecords may have been added to subordinate sdRef e.g., DNSServiceRegister/DNSServiceAddRecord
+ // or on the main sdRef e.g., DNSServiceCreateConnection/DNSServiveRegisterRecord. DNSRecords may have
+ // been freed if the application called DNSRemoveRecord
+ FreeDNSRecords(x);
free(x);
}
}
@@ -619,6 +423,11 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
sdr->ProcessReply = ProcessReply;
sdr->AppCallback = AppCallback;
sdr->AppContext = AppContext;
+ sdr->rec = NULL;
+#if _DNS_SD_LIBDISPATCH
+ sdr->disp_source = NULL;
+ sdr->disp_queue = NULL;
+#endif
if (flags & kDNSServiceFlagsShareConnection)
{
@@ -659,6 +468,13 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
#else
saddr.sun_family = AF_LOCAL;
strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
+ #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
+ {
+ int defunct = 1;
+ if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ }
+ #endif
#endif
while (1)
@@ -758,6 +574,13 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
{
errsd = sp[0]; // We'll read our four-byte error code from sp[0]
listenfd = sp[1]; // We'll send sp[1] to the daemon
+ #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
+ {
+ int defunct = 1;
+ if (setsockopt(errsd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ }
+ #endif
}
}
#endif
@@ -932,6 +755,69 @@ int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
return (int) sdRef->sockfd;
}
+#if _DNS_SD_LIBDISPATCH
+static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error)
+ {
+ DNSServiceOp *sdr = sdRef;
+ DNSServiceOp *sdrNext;
+ DNSRecord *rec;
+ DNSRecord *recnext;
+ int morebytes;
+
+ while (sdr)
+ {
+ // We can't touch the sdr after the callback as it can be deallocated in the callback
+ sdrNext = sdr->next;
+ morebytes = 1;
+ sdr->moreptr = &morebytes;
+ switch (sdr->op)
+ {
+ case resolve_request:
+ if (sdr->AppCallback)((DNSServiceResolveReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, sdr->AppContext);
+ break;
+ case query_request:
+ if (sdr->AppCallback)((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, 0, sdr->AppContext);
+ break;
+ case addrinfo_request:
+ if (sdr->AppCallback)((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, NULL, 0, sdr->AppContext);
+ break;
+ case browse_request:
+ if (sdr->AppCallback)((DNSServiceBrowseReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, NULL, sdr->AppContext);
+ break;
+ case reg_service_request:
+ if (sdr->AppCallback)((DNSServiceRegisterReply) sdr->AppCallback)(sdr, 0, error, NULL, 0, NULL, sdr->AppContext);
+ break;
+ case enumeration_request:
+ if (sdr->AppCallback)((DNSServiceDomainEnumReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, sdr->AppContext);
+ break;
+ case connection_request:
+ // This means Register Record, walk the list of DNSRecords to do the callback
+ rec = sdr->rec;
+ while (rec)
+ {
+ recnext = rec->recnext;
+ if (rec->AppCallback) ((DNSServiceRegisterRecordReply)rec->AppCallback)(sdr, 0, 0, error, rec->AppContext);
+ // The Callback can call DNSServiceRefDeallocate which in turn frees sdr and all the records.
+ // Detect that and return early
+ if (!morebytes){syslog(LOG_WARNING, "dnssdclientstub:Record: CallbackwithError morebytes zero"); return;}
+ rec = recnext;
+ }
+ break;
+ case port_mapping_request:
+ if (sdr->AppCallback)((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, 0, 0, error, 0, 0, 0, 0, 0, sdr->AppContext);
+ break;
+ default:
+ syslog(LOG_WARNING, "dnssd_clientstub CallbackWithError called with bad op %d", sdr->op);
+ }
+ // If DNSServiceRefDeallocate was called in the callback, morebytes will be zero. It means
+ // all other sdrefs have been freed. This happens for shared connections where the
+ // DNSServiceRefDeallocate on the first sdRef frees all other sdrefs.
+ if (!morebytes){syslog(LOG_WARNING, "dnssdclientstub:sdRef: CallbackwithError morebytes zero"); return;}
+ sdr = sdrNext;
+ }
+ }
+#endif // _DNS_SD_LIBDISPATCH
+
// Handle reply from server, calling application client callback. If there is no reply
// from the daemon on the socket contained in sdRef, the call will block.
DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
@@ -968,11 +854,26 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
// return NoError on EWOULDBLOCK. This will handle the case
// where a non-blocking socket is told there is data, but it was a false positive.
// On error, read_all will write a message to syslog for us, so don't need to duplicate that here
- // Note: If we want to properly support using non-blocking sockets in the future
+ // Note: If we want to properly support using non-blocking sockets in the future
int result = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr));
if (result == read_all_fail)
{
+ // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
+ // in the callback.
sdRef->ProcessReply = NULL;
+#if _DNS_SD_LIBDISPATCH
+ // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
+ // is not called by the application and hence need to communicate the error. Cancel the
+ // source so that we don't get any more events
+ if (sdRef->disp_source)
+ {
+ dispatch_source_cancel(sdRef->disp_source);
+ dispatch_release(sdRef->disp_source);
+ sdRef->disp_source = NULL;
+ CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
+ }
+#endif
+ // Don't touch sdRef anymore as it might have been deallocated
return kDNSServiceErr_ServiceNotRunning;
}
else if (result == read_all_wouldblock)
@@ -997,8 +898,23 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
if (!data) return kDNSServiceErr_NoMemory;
if (read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen) < 0) // On error, read_all will write a message to syslog for us
{
- free(data);
+ // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
+ // in the callback.
sdRef->ProcessReply = NULL;
+#if _DNS_SD_LIBDISPATCH
+ // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
+ // is not called by the application and hence need to communicate the error. Cancel the
+ // source so that we don't get any more events
+ if (sdRef->disp_source)
+ {
+ dispatch_source_cancel(sdRef->disp_source);
+ dispatch_release(sdRef->disp_source);
+ sdRef->disp_source = NULL;
+ CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
+ }
+#endif
+ // Don't touch sdRef anymore as it might have been deallocated
+ free(data);
return kDNSServiceErr_ServiceNotRunning;
}
else
@@ -1056,16 +972,43 @@ void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
char *ptr;
size_t len = 0;
ipc_msg_hdr *hdr = create_hdr(cancel_request, &len, &ptr, 0, sdRef);
- ConvertHeaderBytes(hdr);
- write_all(sdRef->sockfd, (char *)hdr, len);
- free(hdr);
+ if (hdr)
+ {
+ ConvertHeaderBytes(hdr);
+ write_all(sdRef->sockfd, (char *)hdr, len);
+ free(hdr);
+ }
*p = sdRef->next;
FreeDNSServiceOp(sdRef);
}
}
else // else, make sure to terminate all subordinates as well
{
+#if _DNS_SD_LIBDISPATCH
+ // The cancel handler will close the fd if a dispatch source has been set
+ if (sdRef->disp_source)
+ {
+ // By setting the ProcessReply to NULL, we make sure that we never call
+ // the application callbacks ever, after returning from this function. We
+ // assume that DNSServiceRefDeallocate is called from the serial queue
+ // that was passed to DNSServiceSetDispatchQueue. Hence, dispatch_source_cancel
+ // should cancel all the blocks on the queue and hence there should be no more
+ // callbacks when we return from this function. Setting ProcessReply to NULL
+ // provides extra protection.
+ sdRef->ProcessReply = NULL;
+ dispatch_source_cancel(sdRef->disp_source);
+ dispatch_release(sdRef->disp_source);
+ sdRef->disp_source = NULL;
+ }
+ // if disp_queue is set, it means it used the DNSServiceSetDispatchQueue API. In that case,
+ // when the source was cancelled, the fd was closed in the handler. Currently the source
+ // is cancelled only when the mDNSResponder daemon dies
+ else if (!sdRef->disp_queue) dnssd_close(sdRef->sockfd);
+#else
dnssd_close(sdRef->sockfd);
+#endif
+ // Free DNSRecords added in DNSRegisterRecord if they have not
+ // been freed in DNSRemoveRecord
while (sdRef)
{
DNSServiceOp *p = sdRef;
@@ -1117,18 +1060,19 @@ static void handle_resolve_response(DNSServiceOp *const sdr, const CallbackHeade
get_string(&data, end, fullname, kDNSServiceMaxDomainName);
get_string(&data, end, target, kDNSServiceMaxDomainName);
- if (!data || data + 2 > end) data = NULL;
- else
- {
- port.b[0] = *data++;
- port.b[1] = *data++;
- }
+ if (!data || data + 2 > end) goto fail;
+
+ port.b[0] = *data++;
+ port.b[1] = *data++;
txtlen = get_uint16(&data, end);
txtrecord = (unsigned char *)get_rdata(&data, end, txtlen);
- if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
- else ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext);
+ if (!data) goto fail;
+ ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext);
+ return;
// MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+fail:
+ syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
}
DNSServiceErrorType DNSSD_API DNSServiceResolve
@@ -1375,6 +1319,7 @@ DNSServiceErrorType DNSSD_API DNSServiceBrowse
return err;
}
+DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain);
DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain)
{
DNSServiceOp *tmp;
@@ -1576,6 +1521,7 @@ DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
size_t len;
ipc_msg_hdr *hdr = NULL;
DNSRecordRef rref = NULL;
+ DNSRecord **p;
int f1 = (flags & kDNSServiceFlagsShared) != 0;
int f2 = (flags & kDNSServiceFlagsUnique) != 0;
if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
@@ -1620,10 +1566,15 @@ DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
rref->AppCallback = callBack;
rref->record_index = sdRef->max_index++;
rref->sdr = sdRef;
+ rref->recnext = NULL;
*RecordRef = rref;
hdr->client_context.context = rref;
hdr->reg_index = rref->record_index;
+ p = &(sdRef)->rec;
+ while (*p) p = &(*p)->recnext;
+ *p = rref;
+
return deliver_request(hdr, sdRef); // Will free hdr for us
}
@@ -1643,6 +1594,7 @@ DNSServiceErrorType DNSSD_API DNSServiceAddRecord
size_t len = 0;
char *ptr;
DNSRecordRef rref;
+ DNSRecord **p;
if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSRecordRef pointer"); return kDNSServiceErr_BadParam; }
@@ -1679,9 +1631,14 @@ DNSServiceErrorType DNSSD_API DNSServiceAddRecord
rref->AppCallback = NULL;
rref->record_index = sdRef->max_index++;
rref->sdr = sdRef;
+ rref->recnext = NULL;
*RecordRef = rref;
hdr->reg_index = rref->record_index;
+ p = &(sdRef)->rec;
+ while (*p) p = &(*p)->recnext;
+ *p = rref;
+
return deliver_request(hdr, sdRef); // Will free hdr for us
}
@@ -1753,7 +1710,15 @@ DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
hdr->reg_index = RecordRef->record_index;
put_flags(flags, &ptr);
err = deliver_request(hdr, sdRef); // Will free hdr for us
- if (!err) free(RecordRef);
+ if (!err)
+ {
+ // This RecordRef could have been allocated in DNSServiceRegisterRecord or DNSServiceAddRecord.
+ // If so, delink from the list before freeing
+ DNSRecord **p = &sdRef->rec;
+ while (*p && *p != RecordRef) p = &(*p)->recnext;
+ if (*p) *p = RecordRef->recnext;
+ free(RecordRef);
+ }
return err;
}
@@ -1800,29 +1765,31 @@ DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
static void handle_port_mapping_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
{
union { uint32_t l; u_char b[4]; } addr;
- uint8_t protocol = 0;
+ uint8_t protocol;
union { uint16_t s; u_char b[2]; } internalPort;
union { uint16_t s; u_char b[2]; } externalPort;
- uint32_t ttl = 0;
-
- if (!data || data + 13 > end) data = NULL;
- else
- {
- addr .b[0] = *data++;
- addr .b[1] = *data++;
- addr .b[2] = *data++;
- addr .b[3] = *data++;
- protocol = *data++;
- internalPort.b[0] = *data++;
- internalPort.b[1] = *data++;
- externalPort.b[0] = *data++;
- externalPort.b[1] = *data++;
- ttl = get_uint32(&data, end);
- }
+ uint32_t ttl;
- if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon");
- else ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, internalPort.s, externalPort.s, ttl, sdr->AppContext);
+ if (!data || data + 13 > end) goto fail;
+
+ addr .b[0] = *data++;
+ addr .b[1] = *data++;
+ addr .b[2] = *data++;
+ addr .b[3] = *data++;
+ protocol = *data++;
+ internalPort.b[0] = *data++;
+ internalPort.b[1] = *data++;
+ externalPort.b[0] = *data++;
+ externalPort.b[1] = *data++;
+ ttl = get_uint32(&data, end);
+ if (!data) goto fail;
+
+ ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, internalPort.s, externalPort.s, ttl, sdr->AppContext);
+ return;
// MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+
+fail:
+ syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon");
}
DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
@@ -1870,3 +1837,41 @@ DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
return err;
}
+
+#if _DNS_SD_LIBDISPATCH
+DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
+ (
+ DNSServiceRef service,
+ dispatch_queue_t queue
+ )
+ {
+ int dnssd_fd = DNSServiceRefSockFD(service);
+ if (dnssd_fd == dnssd_InvalidSocket) return kDNSServiceErr_BadParam;
+ if (!queue)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub: DNSServiceSetDispatchQueue dispatch queue NULL");
+ return kDNSServiceErr_BadParam;
+ }
+ if (service->disp_queue)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch queue set already");
+ return kDNSServiceErr_BadParam;
+ }
+ if (service->disp_source)
+ {
+ syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch source set already");
+ return kDNSServiceErr_BadParam;
+ }
+ service->disp_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, dnssd_fd, 0, queue);
+ if (!service->disp_source)
+ {
+ syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch_source_create failed");
+ return kDNSServiceErr_NoMemory;
+ }
+ service->disp_queue = queue;
+ dispatch_source_set_event_handler(service->disp_source, ^{DNSServiceProcessResult(service);});
+ dispatch_source_set_cancel_handler(service->disp_source, ^{dnssd_close(dnssd_fd);});
+ dispatch_resume(service->disp_source);
+ return kDNSServiceErr_NoError;
+ }
+#endif // _DNS_SD_LIBDISPATCH
diff --git a/external/apache2/mDNSResponder/dist/mDNSShared/dnssd_ipc.h b/external/apache2/mDNSResponder/dist/mDNSShared/dnssd_ipc.h
index f65674326c0..aa5b8473b0b 100644
--- a/external/apache2/mDNSResponder/dist/mDNSShared/dnssd_ipc.h
+++ b/external/apache2/mDNSResponder/dist/mDNSShared/dnssd_ipc.h
@@ -24,138 +24,6 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- Change History (most recent first):
-
-Log: dnssd_ipc.h,v $
-Revision 1.46 2009/05/27 22:20:44 cheshire
-Removed unused dnssd_errno_assign() (we have no business writing to errno -- we should only read it)
-
-Revision 1.45 2009/05/26 21:31:07 herscher
-Fix compile errors on Windows
-
-Revision 1.44 2009/02/12 20:28:31 cheshire
-Added some missing "const" declarations
-
-Revision 1.43 2008/10/23 23:21:31 cheshire
-Moved definition of dnssd_strerror() to be with the definition of dnssd_errno, in dnssd_ipc.h
-
-Revision 1.42 2008/10/23 23:06:17 cheshire
-Removed () from dnssd_errno macro definition -- it's not a function and doesn't need any arguments
-
-Revision 1.41 2008/09/27 01:04:09 cheshire
-Added "send_bpf" to list of request_op_t operation codes
-
-Revision 1.40 2007/09/07 20:56:03 cheshire
-Renamed uint32_t field in client_context_t from "ptr64" to more accurate name "u32"
-
-Revision 1.39 2007/08/18 01:02:04 mcguire
-<rdar://problem/5415593> No Bonjour services are getting registered at boot
-
-Revision 1.38 2007/08/08 22:34:59 mcguire
-<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
-
-Revision 1.37 2007/07/28 00:00:43 cheshire
-Renamed CompileTimeAssertionCheck structure for consistency with others
-
-Revision 1.36 2007/07/23 22:12:53 cheshire
-<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
-
-Revision 1.35 2007/05/23 18:59:22 cheshire
-Remove unnecessary IPC_FLAGS_REUSE_SOCKET
-
-Revision 1.34 2007/05/22 01:07:42 cheshire
-<rdar://problem/3563675> API: Need a way to get version/feature information
-
-Revision 1.33 2007/05/18 23:55:22 cheshire
-<rdar://problem/4454655> Allow multiple register/browse/resolve operations to share single Unix Domain Socket
-
-Revision 1.32 2007/05/18 20:31:20 cheshire
-Rename port_mapping_create_request to port_mapping_request
-
-Revision 1.31 2007/05/18 17:56:20 cheshire
-Rename port_mapping_create_reply_op to port_mapping_reply_op
-
-Revision 1.30 2007/05/16 01:06:52 cheshire
-<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
-
-Revision 1.29 2007/05/15 21:57:16 cheshire
-<rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
-assuming that all negative values (or zero!) are invalid socket numbers
-
-Revision 1.28 2007/03/21 19:01:57 cheshire
-<rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits
-
-Revision 1.27 2006/10/27 00:38:22 cheshire
-Strip accidental trailing whitespace from lines
-
-Revision 1.26 2006/09/27 00:44:36 herscher
-<rdar://problem/4249761> API: Need DNSServiceGetAddrInfo()
-
-Revision 1.25 2006/09/26 01:51:07 herscher
-<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
-
-Revision 1.24 2006/09/18 19:21:42 cheshire
-<rdar://problem/4737048> gcc's structure padding breaks Bonjour APIs on
-64-bit clients; need to declare ipc_msg_hdr structure "packed"
-
-Revision 1.23 2006/08/14 23:05:53 cheshire
-Added "tab-width" emacs header line
-
-Revision 1.22 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.21 2005/09/29 06:38:13 herscher
-Remove #define MSG_WAITALL on Windows. We don't use this macro anymore, and it's presence causes warnings to be emitted when compiling against the latest Microsoft Platform SDK.
-
-Revision 1.20 2005/03/21 00:39:31 shersche
-<rdar://problem/4021486> Fix build warnings on Win32 platform
-
-Revision 1.19 2005/02/02 02:25:22 cheshire
-<rdar://problem/3980388> /var/run/mDNSResponder should be /var/run/mdnsd on Linux
-
-Revision 1.18 2005/01/27 22:57:56 cheshire
-Fix compile errors on gcc4
-
-Revision 1.17 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.16 2004/11/12 03:21:41 rpantos
-rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
-
-Revision 1.15 2004/10/06 02:22:20 cheshire
-Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
-
-Revision 1.14 2004/10/01 22:15:55 rpantos
-rdar://problem/3824265: Replace APSL in client lib with BSD license.
-
-Revision 1.13 2004/09/16 23:14:25 cheshire
-Changes for Windows compatibility
-
-Revision 1.12 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.11 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.10 2004/07/07 17:39:25 shersche
-Change MDNS_SERVERPORT from 5533 to 5354.
-
-Revision 1.9 2004/06/25 00:26:27 rpantos
-Changes to fix the Posix build on Solaris.
-
-Revision 1.8 2004/06/18 04:56:51 rpantos
-Add layer for platform code
-
-Revision 1.7 2004/06/12 01:08:14 cheshire
-Changes for Windows compatibility
-
-Revision 1.6 2003/08/12 19:56:25 cheshire
-Update to APSL 2.0
-
*/
#ifndef DNSSD_IPC_H
@@ -179,6 +47,8 @@ Update to APSL 2.0
# define dnssd_strerror(X) win32_strerror(X)
# define ssize_t int
# define getpid _getpid
+# define unlink _unlink
+extern char *win32_strerror(int inErrorCode);
#else
# include <sys/types.h>
# include <unistd.h>
@@ -249,7 +119,7 @@ Update to APSL 2.0
typedef enum
{
request_op_none = 0, // No request yet received on this connection
- connection_request = 1, // connected socket via DNSServiceConnect()
+ connection_request = 1, // connected socket via DNSServiceCreateConnection()
reg_record_request, // reg/remove record only valid for connected sockets
remove_record_request,
enumeration_request,
@@ -303,7 +173,7 @@ typedef packedstruct
uint32_t op; // request_op_t or reply_op_t
client_context_t client_context; // context passed from client, returned by server in corresponding reply
uint32_t reg_index; // identifier for a record registered via DNSServiceRegisterRecord() on a
- // socket connected by DNSServiceConnect(). Must be unique in the scope of the connection, such that and
+ // socket connected by DNSServiceCreateConnection(). Must be unique in the scope of the connection, such that and
// index/socket pair uniquely identifies a record. (Used to select records for removal by DNSServiceRemoveRecord())
} ipc_msg_hdr;
diff --git a/external/apache2/mDNSResponder/dist/mDNSShared/uds_daemon.c b/external/apache2/mDNSResponder/dist/mDNSShared/uds_daemon.c
index d46f20e1564..ba46109c1b5 100644
--- a/external/apache2/mDNSResponder/dist/mDNSShared/uds_daemon.c
+++ b/external/apache2/mDNSResponder/dist/mDNSShared/uds_daemon.c
@@ -13,876 +13,7 @@
* 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.461 2009/06/19 23:15:07 cheshire
-<rdar://problem/6990066> Library: crash at handle_resolve_response + 183
-Made resolve_result_callback code more defensive and improved LogOperation messages
-
-Revision 1.460 2009/05/26 21:31:07 herscher
-Fix compile errors on Windows
-
-Revision 1.459 2009/04/30 20:07:51 mcguire
-<rdar://problem/6822674> Support multiple UDSs from launchd
-
-Revision 1.458 2009/04/25 00:59:06 mcguire
-Change a few stray LogInfo to LogOperation
-
-Revision 1.457 2009/04/22 01:19:57 jessic2
-<rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32
-
-Revision 1.456 2009/04/21 01:56:34 jessic2
-<rdar://problem/6803941> BTMM: Back out change for preventing other local users from sending packets to your BTMM machines
-
-Revision 1.455 2009/04/20 19:19:57 cheshire
-<rdar://problem/6803941> BTMM: If multiple local users are logged in to same BTMM account, all but one fail
-Don't need "empty info->u.browser.browsers list" debugging message, now that we expect this to be
-a case that can legitimately happen.
-
-Revision 1.454 2009/04/18 20:56:43 jessic2
-<rdar://problem/6803941> BTMM: If multiple local users are logged in to same BTMM account, all but one fail
-
-Revision 1.453 2009/04/11 00:20:29 jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.452 2009/04/07 01:17:42 jessic2
-<rdar://problem/6747917> BTMM: Multiple accounts lets me see others' remote services & send packets to others' remote hosts
-
-Revision 1.451 2009/04/02 22:34:26 jessic2
-<rdar://problem/6305347> Race condition: If fd has already been closed, SO_NOSIGPIPE returns errno 22 (Invalid argument)
-
-Revision 1.450 2009/04/01 21:11:28 herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows. Workaround use of recvmsg.
-
-Revision 1.449 2009/03/17 19:44:25 cheshire
-<rdar://problem/6688927> Don't let negative unicast answers block Multicast DNS responses
-
-Revision 1.448 2009/03/17 04:53:40 cheshire
-<rdar://problem/6688927> Don't let negative unicast answers block Multicast DNS responses
-
-Revision 1.447 2009/03/17 04:41:32 cheshire
-Moved LogOperation message to after check for "if (answer->RecordType == kDNSRecordTypePacketNegative)"
-
-Revision 1.446 2009/03/04 01:47:35 cheshire
-Include m->ProxyRecords in SIGINFO output
-
-Revision 1.445 2009/03/03 23:04:44 cheshire
-For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC)
-
-Revision 1.444 2009/03/03 22:51:55 cheshire
-<rdar://problem/6504236> Sleep Proxy: Waking on same network but different interface will cause conflicts
-
-Revision 1.443 2009/02/27 02:28:41 cheshire
-Need to declare "const AuthRecord *ar;"
-
-Revision 1.442 2009/02/27 00:58:17 cheshire
-Improved detail of SIGINFO logging for m->DuplicateRecords
-
-Revision 1.441 2009/02/24 22:18:59 cheshire
-Include interface name for interface-specific AuthRecords
-
-Revision 1.440 2009/02/21 01:38:08 cheshire
-Added report of m->SleepState value in SIGINFO output
-
-Revision 1.439 2009/02/18 23:38:44 cheshire
-<rdar://problem/6600780> Could not write data to client 13 - aborting connection
-Eliminated unnecessary "request_state *request" field from the reply_state structure.
-
-Revision 1.438 2009/02/18 23:23:14 cheshire
-Cleaned up debugging log messages
-
-Revision 1.437 2009/02/17 23:29:05 cheshire
-Throttle logging to a slower rate when running on SnowLeopard
-
-Revision 1.436 2009/02/13 06:28:02 cheshire
-Converted LogOperation messages to LogInfo
-
-Revision 1.435 2009/02/12 20:57:26 cheshire
-Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
-
-Revision 1.434 2009/02/12 20:28:31 cheshire
-Added some missing "const" declarations
-
-Revision 1.433 2009/02/10 01:44:39 cheshire
-<rdar://problem/6553729> DNSServiceUpdateRecord fails with kDNSServiceErr_BadReference for otherwise valid reference
-
-Revision 1.432 2009/02/10 01:38:56 cheshire
-Move regservice_termination_callback() earlier in file in preparation for subsequent work
-
-Revision 1.431 2009/02/07 01:48:55 cheshire
-In SIGINFO output include sequence number for proxied records
-
-Revision 1.430 2009/01/31 21:58:05 cheshire
-<rdar://problem/4786302> Implement logic to determine when to send dot-local lookups via Unicast
-Only want to do unicast dot-local lookups for address queries and conventional (RFC 2782) SRV queries
-
-Revision 1.429 2009/01/31 00:45:26 cheshire
-<rdar://problem/4786302> Implement logic to determine when to send dot-local lookups via Unicast
-Further refinements
-
-Revision 1.428 2009/01/30 19:52:31 cheshire
-Eliminated unnecessary duplicated "dnssd_sock_t sd" fields in service_instance and reply_state structures
-
-Revision 1.427 2009/01/24 01:48:43 cheshire
-<rdar://problem/4786302> Implement logic to determine when to send dot-local lookups via Unicast
-
-Revision 1.426 2009/01/16 21:07:08 cheshire
-In SIGINFO "Duplicate Records" list, show expiry time for Sleep Proxy records
-
-Revision 1.425 2009/01/16 20:53:16 cheshire
-Include information about Sleep Proxy records in SIGINFO output
-
-Revision 1.424 2009/01/12 22:43:50 cheshire
-Fixed "unused variable" warning when SO_NOSIGPIPE is not defined
-
-Revision 1.423 2009/01/10 22:54:42 mkrochma
-<rdar://problem/5797544> Fixes from Igor Seleznev to get mdnsd working on Linux
-
-Revision 1.422 2009/01/10 01:52:48 cheshire
-Include DuplicateRecords and LocalOnlyQuestions in SIGINFO output
-
-Revision 1.421 2008/12/17 05:05:26 cheshire
-Fixed alignment of NAT mapping syslog messages
-
-Revision 1.420 2008/12/12 00:52:05 cheshire
-mDNSPlatformSetBPF is now called mDNSPlatformReceiveBPF_fd
-
-Revision 1.419 2008/12/10 02:11:44 cheshire
-ARMv5 compiler doesn't like uncommented stuff after #endif
-
-Revision 1.418 2008/12/09 05:12:53 cheshire
-Updated debugging messages
-
-Revision 1.417 2008/12/04 03:38:12 cheshire
-Miscellaneous defensive coding changes and improvements to debugging log messages
-
-Revision 1.416 2008/12/02 22:02:12 cheshire
-<rdar://problem/6320621> Adding domains after TXT record updates registers stale TXT record data
-
-Revision 1.415 2008/11/26 20:35:59 cheshire
-Changed some "LogOperation" debugging messages to "debugf"
-
-Revision 1.414 2008/11/26 00:02:25 cheshire
-Improved SIGINFO output to list AutoBrowseDomains and AutoRegistrationDomains
-
-Revision 1.413 2008/11/25 04:48:58 cheshire
-Added logging to show whether Sleep Proxy Service is active
-
-Revision 1.412 2008/11/24 23:05:43 cheshire
-Additional checking in uds_validatelists()
-
-Revision 1.411 2008/11/05 21:41:39 cheshire
-Updated LogOperation message
-
-Revision 1.410 2008/11/04 20:06:20 cheshire
-<rdar://problem/6186231> Change MAX_DOMAIN_NAME to 256
-
-Revision 1.409 2008/10/31 23:44:22 cheshire
-Fixed compile error in Posix build
-
-Revision 1.408 2008/10/29 21:32:33 cheshire
-Align "DNSServiceEnumerateDomains ... RESULT" log messages
-
-Revision 1.407 2008/10/27 07:34:36 cheshire
-Additional sanity checks for debugging
-
-Revision 1.406 2008/10/23 23:55:56 cheshire
-Fixed some missing "const" declarations
-
-Revision 1.405 2008/10/23 23:21:31 cheshire
-Moved definition of dnssd_strerror() to be with the definition of dnssd_errno, in dnssd_ipc.h
-
-Revision 1.404 2008/10/23 23:06:17 cheshire
-Removed () from dnssd_errno macro definition -- it's not a function and doesn't need any arguments
-
-Revision 1.403 2008/10/23 22:33:25 cheshire
-Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
-
-Revision 1.402 2008/10/22 19:47:59 cheshire
-Instead of SameRData(), use equivalent IdenticalSameNameRecord() macro
-
-Revision 1.401 2008/10/22 17:20:40 cheshire
-Don't give up if setsockopt SO_NOSIGPIPE fails
-
-Revision 1.400 2008/10/21 01:06:57 cheshire
-Pass BPF fd to mDNSMacOSX.c using mDNSPlatformSetBPF() instead of just writing it into a shared global variable
-
-Revision 1.399 2008/10/20 22:06:42 cheshire
-Updated debugging log messages
-
-Revision 1.398 2008/10/03 18:25:17 cheshire
-Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);"
-
-Revision 1.397 2008/10/02 22:26:21 cheshire
-Moved declaration of BPF_fd from uds_daemon.c to mDNSMacOSX.c, where it really belongs
-
-Revision 1.396 2008/09/30 01:04:55 cheshire
-Made BPF code a bit more defensive, to ignore subsequent BPF fds if we get passed more than one
-
-Revision 1.395 2008/09/27 01:28:43 cheshire
-Added code to receive and store BPF fd when passed via a send_bpf message
-
-Revision 1.394 2008/09/23 04:12:40 cheshire
-<rdar://problem/6238774> Remove "local" from the end of _services._dns-sd._udp PTR records
-Added a special-case to massage these new records for Bonjour Browser's benefit
-
-Revision 1.393 2008/09/23 03:01:58 cheshire
-Added operation logging of domain enumeration results
-
-Revision 1.392 2008/09/18 22:30:06 cheshire
-<rdar://problem/6230679> device-info record not removed when last service deregisters
-
-Revision 1.391 2008/09/18 22:05:44 cheshire
-Fixed "DNSServiceRegister ... ADDED" message to have escaping consistent with
-the other DNSServiceRegister operation messages
-
-Revision 1.390 2008/09/16 21:06:56 cheshire
-Improved syslog output to show if q->LongLived flag is set for multicast questions
-
-Revision 1.389 2008/07/25 22:34:11 mcguire
-fix sizecheck issues for 64bit
-
-Revision 1.388 2008/07/01 01:40:02 mcguire
-<rdar://problem/5823010> 64-bit fixes
-
-Revision 1.387 2008/02/26 21:24:13 cheshire
-Fixed spelling mistake in comment
-
-Revision 1.386 2008/02/26 20:23:15 cheshire
-Updated comments
-
-Revision 1.385 2008/02/19 21:50:52 cheshire
-Shortened some overly-long lines
-
-Revision 1.384 2007/12/22 01:38:05 cheshire
-Improve display of "Auth Records" SIGINFO output
-
-Revision 1.383 2007/12/07 00:45:58 cheshire
-<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
-
-Revision 1.382 2007/11/30 20:11:48 cheshire
-Fixed compile warning: declaration of 'remove' shadows a global declaration
-
-Revision 1.381 2007/11/28 22:02:52 cheshire
-Remove pointless "if (!domain)" check (domain is an array on the stack, so its address can never be null)
-
-Revision 1.380 2007/11/28 18:38:41 cheshire
-Fixed typo in log message: "DNSServiceResolver" -> "DNSServiceResolve"
-
-Revision 1.379 2007/11/01 19:32:14 cheshire
-Added "DEBUG_64BIT_SCM_RIGHTS" debugging code
-
-Revision 1.378 2007/10/31 19:21:40 cheshire
-Don't show Expire time for records and services that aren't currently registered
-
-Revision 1.377 2007/10/30 23:48:20 cheshire
-Improved SIGINFO listing of question state
-
-Revision 1.376 2007/10/30 20:43:54 cheshire
-Fixed compiler warning when LogClientOperations is turned off
-
-Revision 1.375 2007/10/26 22:51:38 cheshire
-Improved SIGINFO output to show timers for AuthRecords and ServiceRegistrations
-
-Revision 1.374 2007/10/25 22:45:02 cheshire
-Tidied up code for DNSServiceRegister callback status messages
-
-Revision 1.373 2007/10/25 21:28:43 cheshire
-Add ServiceRegistrations to SIGINFO output
-
-Revision 1.372 2007/10/25 21:21:45 cheshire
-<rdar://problem/5496734> BTMM: Need to retry registrations after failures
-Don't unlink_and_free_service_instance at the first error
-
-Revision 1.371 2007/10/18 23:34:40 cheshire
-<rdar://problem/5532821> Need "considerable burden on the network" warning in uds_daemon.c
-
-Revision 1.370 2007/10/17 18:44:23 cheshire
-<rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
-
-Revision 1.369 2007/10/16 17:18:27 cheshire
-Fixed Posix compile errors
-
-Revision 1.368 2007/10/16 16:58:58 cheshire
-Improved debugging error messages in read_msg()
-
-Revision 1.367 2007/10/15 22:55:14 cheshire
-Make read_msg return "void" (since request_callback just ignores the redundant return value anyway)
-
-Revision 1.366 2007/10/10 00:48:54 cheshire
-<rdar://problem/5526379> Daemon spins in an infinite loop when it doesn't get the control message it's expecting
-
-Revision 1.365 2007/10/06 03:25:23 cheshire
-<rdar://problem/5525267> MacBuddy exits abnormally when clicking "Continue" in AppleConnect pane
-
-Revision 1.364 2007/10/06 03:20:16 cheshire
-Improved LogOperation debugging messages
-
-Revision 1.363 2007/10/05 23:24:52 cheshire
-Improved LogOperation messages about separate error return socket
-
-Revision 1.362 2007/10/05 22:11:58 cheshire
-Improved "send_msg ERROR" debugging message
-
-Revision 1.361 2007/10/04 20:45:18 cheshire
-<rdar://problem/5518381> Race condition in kDNSServiceFlagsShareConnection-mode call handling
-
-Revision 1.360 2007/10/01 23:24:46 cheshire
-SIGINFO output was mislabeling mDNSInterface_Any queries as unicast queries
-
-Revision 1.359 2007/09/30 00:09:27 cheshire
-<rdar://problem/5492315> Pass socket fd via SCM_RIGHTS sendmsg instead of using named UDS in the filesystem
-
-Revision 1.358 2007/09/29 20:08:06 cheshire
-Fixed typo in comment
-
-Revision 1.357 2007/09/27 22:10:04 cheshire
-Add LogOperation line for DNSServiceRegisterRecord callbacks
-
-Revision 1.356 2007/09/26 21:29:30 cheshire
-Improved question list SIGINFO output
-
-Revision 1.355 2007/09/26 01:54:34 mcguire
-Debugging: In SIGINFO output, show ClientTunnel query interval, which is how we determine whether a query is still active
-
-Revision 1.354 2007/09/26 01:26:31 cheshire
-<rdar://problem/5501567> BTMM: mDNSResponder crashes in free_service_instance enabling/disabling BTMM
-Need to call SendServiceRemovalNotification *before* backpointer is cleared
-
-Revision 1.353 2007/09/25 20:46:33 cheshire
-Include DNSServiceRegisterRecord operations in SIGINFO output
-
-Revision 1.352 2007/09/25 20:23:40 cheshire
-<rdar://problem/5501567> BTMM: mDNSResponder crashes in free_service_instance enabling/disabling BTMM
-Need to clear si->request backpointer before calling mDNS_DeregisterService(&mDNSStorage, &si->srs);
-
-Revision 1.351 2007/09/25 18:20:34 cheshire
-Changed name of "free_service_instance" to more accurate "unlink_and_free_service_instance"
-
-Revision 1.350 2007/09/24 23:54:52 mcguire
-Additional list checking in uds_validatelists()
-
-Revision 1.349 2007/09/24 06:01:00 cheshire
-Debugging: In SIGINFO output, show NAT Traversal time values in seconds rather than platform ticks
-
-Revision 1.348 2007/09/24 05:02:41 cheshire
-Debugging: In SIGINFO output, indicate explicitly when a given section is empty
-
-Revision 1.347 2007/09/21 02:04:33 cheshire
-<rdar://problem/5440831> BTMM: mDNSResponder crashes in free_service_instance enabling/disabling BTMM
-
-Revision 1.346 2007/09/19 22:47:25 cheshire
-<rdar://problem/5490182> Memory corruption freeing a "no such service" service record
-
-Revision 1.345 2007/09/19 20:32:29 cheshire
-<rdar://problem/5482322> BTMM: Don't advertise SMB with BTMM because it doesn't support IPv6
-
-Revision 1.344 2007/09/19 19:27:50 cheshire
-<rdar://problem/5492182> Improved diagnostics when daemon can't connect to error return path socket
-
-Revision 1.343 2007/09/18 21:42:30 cheshire
-To reduce programming mistakes, renamed ExtPort to RequestedPort
-
-Revision 1.342 2007/09/14 22:38:20 cheshire
-Additional list checking in uds_validatelists()
-
-Revision 1.341 2007/09/13 00:16:43 cheshire
-<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
-
-Revision 1.340 2007/09/12 23:03:08 cheshire
-<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
-
-Revision 1.339 2007/09/12 19:22:21 cheshire
-Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
-Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
-
-Revision 1.338 2007/09/12 01:22:13 cheshire
-Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
-
-Revision 1.337 2007/09/07 23:05:04 cheshire
-Add display of client_context field in handle_cancel_request() LogOperation message
-While loop was checking client_context.u32[2] instead of client_context.u32[1]
-
-Revision 1.336 2007/09/07 20:56:03 cheshire
-Renamed uint32_t field in client_context_t from "ptr64" to more accurate name "u32"
-
-Revision 1.335 2007/09/05 22:25:01 vazquez
-<rdar://problem/5400521> update_record mDNSResponder leak
-
-Revision 1.334 2007/09/05 20:43:57 cheshire
-Added LogOperation message showing fd of socket listening for incoming Unix Domain Socket client requests
-
-Revision 1.333 2007/08/28 23:32:35 cheshire
-Added LogOperation messages for DNSServiceNATPortMappingCreate() operations
-
-Revision 1.332 2007/08/27 22:59:31 cheshire
-Show reg_index in DNSServiceRegisterRecord/DNSServiceRemoveRecord messages
-
-Revision 1.331 2007/08/27 20:29:57 cheshire
-Added SIGINFO listing of TunnelClients
-
-Revision 1.330 2007/08/24 23:46:50 cheshire
-Added debugging messages and SIGINFO listing of DomainAuthInfo records
-
-Revision 1.329 2007/08/18 01:02:04 mcguire
-<rdar://problem/5415593> No Bonjour services are getting registered at boot
-
-Revision 1.328 2007/08/15 20:18:28 vazquez
-<rdar://problem/5400521> update_record mDNSResponder leak
-Make sure we free all ExtraResourceRecords
-
-Revision 1.327 2007/08/08 22:34:59 mcguire
-<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
-
-Revision 1.326 2007/08/01 16:09:14 cheshire
-Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
-
-Revision 1.325 2007/07/31 21:29:41 cheshire
-<rdar://problem/5372207> System Default registration domain(s) not listed in Domain Enumeration ("dns-sd -E")
-
-Revision 1.324 2007/07/31 01:56:21 cheshire
-Corrected function name in log message
-
-Revision 1.323 2007/07/27 23:57:23 cheshire
-Added compile-time structure size checks
-
-Revision 1.322 2007/07/27 19:37:19 cheshire
-Moved AutomaticBrowseDomainQ into main mDNS object
-
-Revision 1.321 2007/07/27 19:30:41 cheshire
-Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
-to properly reflect tri-state nature of the possible responses
-
-Revision 1.320 2007/07/27 00:48:27 cheshire
-<rdar://problem/4700198> BTMM: Services should only get registered in .Mac domain of current user
-<rdar://problem/4731180> BTMM: Only browse in the current user's .Mac domain by default
-
-Revision 1.319 2007/07/24 17:23:33 cheshire
-<rdar://problem/5357133> Add list validation checks for debugging
-
-Revision 1.318 2007/07/23 23:09:51 cheshire
-<rdar://problem/5351997> Reject oversized client requests
-
-Revision 1.317 2007/07/23 22:24:47 cheshire
-<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
-Additional refinements
-
-Revision 1.316 2007/07/23 22:12:53 cheshire
-<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
-
-Revision 1.315 2007/07/21 01:36:13 cheshire
-Need to also add ".local" as automatic browsing domain
-
-Revision 1.314 2007/07/20 20:12:37 cheshire
-Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
-
-Revision 1.313 2007/07/20 00:54:21 cheshire
-<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-
-Revision 1.312 2007/07/11 03:06:43 cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-
-Revision 1.311 2007/07/06 21:19:18 cheshire
-Add list of NAT traversals to SIGINFO output
-
-Revision 1.310 2007/07/03 19:56:50 cheshire
-Add LogOperation message for DNSServiceSetDefaultDomainForUser
-
-Revision 1.309 2007/06/29 23:12:49 vazquez
-<rdar://problem/5294103> Stop using generate_final_fatal_reply_with_garbage
-
-Revision 1.308 2007/06/29 00:10:07 vazquez
-<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-
-Revision 1.307 2007/05/25 00:25:44 cheshire
-<rdar://problem/5227737> Need to enhance putRData to output all current known types
-
-Revision 1.306 2007/05/24 22:31:35 vazquez
-Bug #: 4272956
-Reviewed by: Stuart Cheshire
-<rdar://problem/4272956> WWDC API: Return ADD/REMOVE events in registration callback
-
-Revision 1.305 2007/05/23 18:59:22 cheshire
-Remove unnecessary IPC_FLAGS_REUSE_SOCKET
-
-Revision 1.304 2007/05/22 01:07:42 cheshire
-<rdar://problem/3563675> API: Need a way to get version/feature information
-
-Revision 1.303 2007/05/22 00:32:58 cheshire
-Make a send_all() subroutine -- will be helpful for implementing DNSServiceGetProperty(DaemonVersion)
-
-Revision 1.302 2007/05/21 18:54:54 cheshire
-Add "Cancel" LogOperation message when we get a cancel_request command over the UDS
-
-Revision 1.301 2007/05/18 23:55:22 cheshire
-<rdar://problem/4454655> Allow multiple register/browse/resolve operations to share single Unix Domain Socket
-
-Revision 1.300 2007/05/18 21:27:11 cheshire
-Rename connected_registration_termination to connection_termination
-
-Revision 1.299 2007/05/18 21:24:34 cheshire
-Rename rstate to request
-
-Revision 1.298 2007/05/18 21:22:35 cheshire
-Convert uint16_t etc. to their locally-defined equivalents, like the rest of the core code
-
-Revision 1.297 2007/05/18 20:33:11 cheshire
-Avoid declaring lots of uninitialized variables in read_rr_from_ipc_msg
-
-Revision 1.296 2007/05/18 19:04:19 cheshire
-Rename msgdata to msgptr (may be modified); rename (currently unused) bufsize to msgend
-
-Revision 1.295 2007/05/18 17:57:13 cheshire
-Reorder functions in file to arrange them in logical groups; added "#pragma mark" headers for each group
-
-Revision 1.294 2007/05/17 20:58:22 cheshire
-<rdar://problem/4647145> DNSServiceQueryRecord should return useful information with NXDOMAIN
-
-Revision 1.293 2007/05/17 19:46:20 cheshire
-Routine name deliver_async_error() is misleading. What it actually does is write a message header
-(containing an error code) followed by 256 bytes of garbage zeroes onto a client connection,
-thereby trashing it and making it useless for any subsequent communication. It's destructive,
-and not very useful. Changing name to generate_final_fatal_reply_with_garbage().
-
-Revision 1.292 2007/05/16 01:06:52 cheshire
-<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
-
-Revision 1.291 2007/05/15 21:57:16 cheshire
-<rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
-assuming that all negative values (or zero!) are invalid socket numbers
-
-Revision 1.290 2007/05/10 23:30:57 cheshire
-<rdar://problem/4084490> Only one browse gets remove events when disabling browse domain
-
-Revision 1.289 2007/05/02 22:18:08 cheshire
-Renamed NATTraversalInfo_struct context to NATTraversalContext
-
-Revision 1.288 2007/04/30 21:33:39 cheshire
-Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
-is iterating through the m->ServiceRegistrations list
-
-Revision 1.287 2007/04/27 19:03:22 cheshire
-Check q->LongLived not q->llq to tell if a query is LongLived
-
-Revision 1.286 2007/04/26 16:00:01 cheshire
-Show interface number in DNSServiceBrowse RESULT output
-
-Revision 1.285 2007/04/22 19:03:39 cheshire
-Minor code tidying
-
-Revision 1.284 2007/04/22 06:02:03 cheshire
-<rdar://problem/4615977> Query should immediately return failure when no server
-
-Revision 1.283 2007/04/21 21:47:47 cheshire
-<rdar://problem/4376383> Daemon: Add watchdog timer
-
-Revision 1.282 2007/04/20 21:17:24 cheshire
-For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
-
-Revision 1.281 2007/04/19 23:25:20 cheshire
-Added debugging message
-
-Revision 1.280 2007/04/17 19:21:29 cheshire
-<rdar://problem/5140339> Domain discovery not working over VPN
-
-Revision 1.279 2007/04/16 21:53:49 cheshire
-Improve display of negative cache entries
-
-Revision 1.278 2007/04/16 20:49:40 cheshire
-Fix compile errors for mDNSPosix build
-
-Revision 1.277 2007/04/05 22:55:36 cheshire
-<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
-
-Revision 1.276 2007/04/05 19:20:13 cheshire
-Non-blocking mode not being set correctly -- was clobbering other flags
-
-Revision 1.275 2007/04/04 21:21:25 cheshire
-<rdar://problem/4546810> Fix crash: In regservice_callback service_instance was being referenced after being freed
-
-Revision 1.274 2007/04/04 01:30:42 cheshire
-<rdar://problem/5075200> DNSServiceAddRecord is failing to advertise NULL record
-Add SIGINFO output lising our advertised Authoritative Records
-
-Revision 1.273 2007/04/04 00:03:27 cheshire
-<rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
-
-Revision 1.272 2007/04/03 20:10:32 cheshire
-Show ADD/RMV in DNSServiceQueryRecord log message instead of just "RESULT"
-
-Revision 1.271 2007/04/03 19:22:32 cheshire
-Use mDNSSameIPv4Address (and similar) instead of accessing internal fields directly
-
-Revision 1.270 2007/03/30 21:55:30 cheshire
-Added comments
-
-Revision 1.269 2007/03/29 01:31:44 cheshire
-Faulty logic was incorrectly suppressing some NAT port mapping callbacks
-
-Revision 1.268 2007/03/29 00:13:58 cheshire
-Remove unnecessary fields from service_instance structure: autoname, autorename, allowremotequery, name
-
-Revision 1.267 2007/03/28 20:59:27 cheshire
-<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
-
-Revision 1.266 2007/03/28 15:56:37 cheshire
-<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
-
-Revision 1.265 2007/03/27 22:52:07 cheshire
-Fix crash in udsserver_automatic_browse_domain_changed
-
-Revision 1.264 2007/03/27 00:49:40 cheshire
-Should use mallocL, not plain malloc
-
-Revision 1.263 2007/03/27 00:45:01 cheshire
-Removed unnecessary "void *termination_context" pointer
-
-Revision 1.262 2007/03/27 00:40:43 cheshire
-Eliminate resolve_termination_t as a separately-allocated structure, and make it part of the request_state union
-
-Revision 1.261 2007/03/27 00:29:00 cheshire
-Eliminate queryrecord_request data as a separately-allocated structure, and make it part of the request_state union
-
-Revision 1.260 2007/03/27 00:18:42 cheshire
-Eliminate enum_termination_t and domain_enum_t as separately-allocated structures,
-and make them part of the request_state union
-
-Revision 1.259 2007/03/26 23:48:16 cheshire
-<rdar://problem/4848295> Advertise model information via Bonjour
-Refinements to reduce unnecessary transmissions of the DeviceInfo TXT record
-
-Revision 1.258 2007/03/24 00:40:04 cheshire
-Minor code cleanup
-
-Revision 1.257 2007/03/24 00:23:12 cheshire
-Eliminate port_mapping_info_t as a separately-allocated structure, and make it part of the request_state union
-
-Revision 1.256 2007/03/24 00:07:18 cheshire
-Eliminate addrinfo_info_t as a separately-allocated structure, and make it part of the request_state union
-
-Revision 1.255 2007/03/23 23:56:14 cheshire
-Move list of record registrations into the request_state union
-
-Revision 1.254 2007/03/23 23:48:56 cheshire
-Eliminate service_info as a separately-allocated structure, and make it part of the request_state union
-
-Revision 1.253 2007/03/23 23:04:29 cheshire
-Eliminate browser_info_t as a separately-allocated structure, and make it part of request_state
-
-Revision 1.252 2007/03/23 22:59:58 cheshire
-<rdar://problem/4848295> Advertise model information via Bonjour
-Use kStandardTTL, not kHostNameTTL
-
-Revision 1.251 2007/03/23 22:44:07 cheshire
-Instead of calling AbortUnlinkAndFree() haphazardly all over the place, make the handle* routines
-return an error code, and then request_callback() does all necessary cleanup in one place.
-
-Revision 1.250 2007/03/22 20:30:07 cheshire
-Remove pointless "if (request->ts != t_complete) ..." checks
-
-Revision 1.249 2007/03/22 20:13:27 cheshire
-Delete unused client_context field
-
-Revision 1.248 2007/03/22 20:03:37 cheshire
-Rename variables for clarity: instead of using variable rs for both request_state
-and reply_state, use req for request_state and rep for reply_state
-
-Revision 1.247 2007/03/22 19:31:42 cheshire
-<rdar://problem/4848295> Advertise model information via Bonjour
-Add missing "model=" at start of DeviceInfo data
-
-Revision 1.246 2007/03/22 18:31:48 cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.245 2007/03/22 00:49:20 cheshire
-<rdar://problem/4848295> Advertise model information via Bonjour
-
-Revision 1.244 2007/03/21 21:01:48 cheshire
-<rdar://problem/4789793> Leak on error path in regrecord_callback, uds_daemon.c
-
-Revision 1.243 2007/03/21 19:01:57 cheshire
-<rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits
-
-Revision 1.242 2007/03/21 18:51:21 cheshire
-<rdar://problem/4549320> Code in uds_daemon.c passes function name instead of type name to mallocL/freeL
-
-Revision 1.241 2007/03/20 00:04:50 cheshire
-<rdar://problem/4837929> Should allow "udp" or "tcp" for protocol command-line arg
-Fix LogOperation("DNSServiceNATPortMappingCreate(...)") message to actually show client arguments
-
-Revision 1.240 2007/03/16 23:25:35 cheshire
-<rdar://problem/5067001> NAT-PMP: Parameter validation not working correctly
-
-Revision 1.239 2007/03/10 02:29:36 cheshire
-Added comment about port_mapping_create_reply()
-
-Revision 1.238 2007/03/07 00:26:48 cheshire
-<rdar://problem/4426754> DNSServiceRemoveRecord log message should include record type
-
-Revision 1.237 2007/02/28 01:44:29 cheshire
-<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
-
-Revision 1.236 2007/02/14 01:58:19 cheshire
-<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
-
-Revision 1.235 2007/02/08 21:12:28 cheshire
-<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
-
-Revision 1.234 2007/02/06 19:06:49 cheshire
-<rdar://problem/3956518> Need to go native with launchd
-
-Revision 1.233 2007/01/10 20:49:37 cheshire
-Remove unnecessary setting of q->Private fields
-
-Revision 1.232 2007/01/09 00:03:23 cheshire
-Call udsserver_handle_configchange() once at the end of udsserver_init()
-to set up the automatic registration and browsing domains.
-
-Revision 1.231 2007/01/06 02:50:19 cheshire
-<rdar://problem/4632919> Instead of copying SRV and TXT record data, just store pointers to cache entities
-
-Revision 1.230 2007/01/06 01:00:35 cheshire
-Improved SIGINFO output
-
-Revision 1.229 2007/01/05 08:30:56 cheshire
-Trim excessive "Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.228 2007/01/05 08:09:05 cheshire
-Reorder code into functional sections, with "#pragma mark" headers
-
-Revision 1.227 2007/01/05 07:04:24 cheshire
-Minor code tidying
-
-Revision 1.226 2007/01/05 05:44:35 cheshire
-Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
-so that mDNSPosix embedded clients will compile again
-
-Revision 1.225 2007/01/04 23:11:15 cheshire
-<rdar://problem/4720673> uDNS: Need to start caching unicast records
-When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
-
-Revision 1.224 2007/01/04 20:57:49 cheshire
-Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
-
-Revision 1.223 2006/12/21 01:25:49 cheshire
-Tidy up SIGINFO state log
-
-Revision 1.222 2006/12/21 00:15:22 cheshire
-Get rid of gmDNS macro; fixed a crash in udsserver_info()
-
-Revision 1.221 2006/12/20 04:07:38 cheshire
-Remove uDNS_info substructure from AuthRecord_struct
-
-Revision 1.220 2006/12/19 22:49:25 cheshire
-Remove uDNS_info substructure from ServiceRecordSet_struct
-
-Revision 1.219 2006/12/14 03:02:38 cheshire
-<rdar://problem/4838433> Tools: dns-sd -G 0 only returns IPv6 when you have a routable IPv6 address
-
-Revision 1.218 2006/11/18 05:01:33 cheshire
-Preliminary support for unifying the uDNS and mDNS code,
-including caching of uDNS answers
-
-Revision 1.217 2006/11/15 19:27:53 mkrochma
-<rdar://problem/4838433> Tools: dns-sd -G 0 only returns IPv6 when you have a routable IPv6 address
-
-Revision 1.216 2006/11/10 00:54:16 cheshire
-<rdar://problem/4816598> Changing case of Computer Name doesn't work
-
-Revision 1.215 2006/10/27 01:30:23 cheshire
-Need explicitly to set ReturnIntermed = mDNSfalse
-
-Revision 1.214 2006/10/20 05:37:23 herscher
-Display question list information in udsserver_info()
-
-Revision 1.213 2006/10/05 03:54:31 herscher
-Remove embedded uDNS_info struct from DNSQuestion_struct
-
-Revision 1.212 2006/09/30 01:22:35 cheshire
-Put back UTF-8 curly quotes in log messages
-
-Revision 1.211 2006/09/27 00:44:55 herscher
-<rdar://problem/4249761> API: Need DNSServiceGetAddrInfo()
-
-Revision 1.210 2006/09/26 01:52:41 herscher
-<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
-
-Revision 1.209 2006/09/21 21:34:09 cheshire
-<rdar://problem/4100000> Allow empty string name when using kDNSServiceFlagsNoAutoRename
-
-Revision 1.208 2006/09/21 21:28:24 cheshire
-Code cleanup to make it consistent with daemon.c: change rename_on_memfree to renameonmemfree
-
-Revision 1.207 2006/09/15 21:20:16 cheshire
-Remove uDNS_info substructure from mDNS_struct
-
-Revision 1.206 2006/08/14 23:24:56 cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.205 2006/07/20 22:07:30 mkrochma
-<rdar://problem/4633196> Wide-area browsing is currently broken in TOT
-More fixes for uninitialized variables
-
-Revision 1.204 2006/07/15 02:01:33 cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Fix broken "empty string" browsing
-
-Revision 1.203 2006/07/07 01:09:13 cheshire
-<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
-
-Revision 1.202 2006/07/05 22:00:10 cheshire
-Wide-area cleanup: Rename mDNSPlatformGetRegDomainList() to uDNS_GetDefaultRegDomainList()
-
-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
-
-*/
+ */
#if defined(_WIN32)
#include <process.h>
@@ -912,6 +43,23 @@ Revision 1.189 2006/01/06 00:56:31 cheshire
#endif
#endif
+#if APPLE_OSX_mDNSResponder
+#include <WebFilterDNS/WebFilterDNS.h>
+
+#if ! NO_WCF
+
+int WCFIsServerRunning(WCFConnection *conn) __attribute__((weak_import));
+int WCFNameResolvesToAddr(WCFConnection *conn, char* domainName, struct sockaddr* address, uid_t userid) __attribute__((weak_import));
+int WCFNameResolvesToName(WCFConnection *conn, char* fromName, char* toName, uid_t userid) __attribute__((weak_import));
+
+// Do we really need to define a macro for "if"?
+#define CHECK_WCF_FUNCTION(X) if (X)
+#endif // ! NO_WCF
+
+#else
+#define NO_WCF 1
+#endif // APPLE_OSX_mDNSResponder
+
// User IDs 0-500 are system-wide processes, not actual users in the usual sense
// User IDs for real user accounts start at 501 and count up from there
#define SystemUID(X) ((X) <= 500)
@@ -939,9 +87,11 @@ typedef struct registered_record_entry
{
struct registered_record_entry *next;
mDNSu32 key;
- AuthRecord *rr; // Pointer to variable-sized AuthRecord
client_context_t regrec_client_context;
request_state *request;
+ mDNSBool external_advertise;
+ mDNSInterfaceID origInterfaceID;
+ AuthRecord *rr; // Pointer to variable-sized AuthRecord (Why a pointer? Why not just embed it here?)
} registered_record_entry;
// A single registered service: ServiceRecordSet + bookkeeping
@@ -955,6 +105,7 @@ typedef struct service_instance
mDNSBool renameonmemfree; // Set on config change when we deregister original name
mDNSBool clientnotified; // Has client been notified of successful registration yet?
mDNSBool default_local; // is this the "local." from an empty-string registration?
+ mDNSBool external_advertise; // is this is being advertised externally?
domainname domain;
ServiceRecordSet srs; // note -- variable-sized object -- must be last field in struct
} service_instance;
@@ -971,10 +122,11 @@ struct request_state
{
request_state *next;
request_state *primary; // If this operation is on a shared socket, pointer to primary
- // request_state for the original DNSServiceConnect() operation
+ // request_state for the original DNSServiceCreateConnection() operation
dnssd_sock_t sd;
dnssd_sock_t errsd;
mDNSu32 uid;
+ void * platform_data;
// Note: On a shared connection these fields in the primary structure, including hdr, are re-used
// for each new request. This is because, until we've read the ipc_msg_hdr to find out what the
@@ -989,7 +141,8 @@ struct request_state
// 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
+ mDNSs32 time_blocked; // record time of a blocked client
+ int unresponsiveness_reports;
struct reply_state *replies; // corresponding (active) reply list
req_termination_fn terminate;
@@ -1054,6 +207,7 @@ struct request_state
const ResourceRecord *txt;
const ResourceRecord *srv;
mDNSs32 ReportTime;
+ mDNSBool external_advertise;
} resolve;
} u;
};
@@ -1091,12 +245,21 @@ mDNSexport const char ProgramName[] = PROGRAM_NAME;
static dnssd_sock_t listenfd = dnssd_InvalidSocket;
static request_state *all_requests = NULL;
+// Note asymmetry here between registration and browsing.
+// For service registrations we only automatically register in domains that explicitly appear in local configuration data
+// (so AutoRegistrationDomains could equally well be called SCPrefRegDomains)
+// For service browsing we also learn automatic browsing domains from the network, so for that case we have:
+// 1. SCPrefBrowseDomains (local configuration data)
+// 2. LocalDomainEnumRecords (locally-generated local-only PTR records -- equivalent to slElem->AuthRecs in uDNS.c)
+// 3. AutoBrowseDomains, which is populated by tracking add/rmv events in AutomaticBrowseDomainChange, the callback function for our mDNS_GetDomains call.
+// By creating and removing our own LocalDomainEnumRecords, we trigger AutomaticBrowseDomainChange callbacks just like domains learned from the network would.
+
+mDNSexport DNameListElem *AutoRegistrationDomains; // Domains where we automatically register for empty-string registrations
+
static DNameListElem *SCPrefBrowseDomains; // List of automatic browsing domains read from SCPreferences for "empty string" browsing
static ARListElem *LocalDomainEnumRecords; // List of locally-generated PTR records to augment those we learn from the network
mDNSexport DNameListElem *AutoBrowseDomains; // List created from those local-only PTR records plus records we get from the network
-mDNSexport DNameListElem *AutoRegistrationDomains; // Domains where we automatically register for empty-string registrations
-
#define MSG_PAD_BYTES 5 // pad message buffer (read from client) with n zero'd bytes to guarantee
// n get_string() calls w/o buffer overrun
// initialization, setup/teardown functions
@@ -1139,6 +302,8 @@ mDNSlocal void abort_request(request_state *req)
{ LogMsg("abort_request: ERROR: Attempt to abort operation %p with req->terminate %p", req, req->terminate); return; }
// First stop whatever mDNSCore operation we were doing
+ // If this is actually a shared connection operation, then its req->terminate function will scan
+ // the all_requests list and terminate any subbordinate operations sharing this file descriptor
if (req->terminate) req->terminate(req);
if (!dnssd_SocketValid(req->sd))
@@ -1149,7 +314,7 @@ mDNSlocal void abort_request(request_state *req)
{
if (req->errsd != req->sd) LogOperation("%3d: Removing FD and closing errsd %d", req->sd, req->errsd);
else LogOperation("%3d: Removing FD", req->sd);
- udsSupportRemoveFDFromEventLoop(req->sd); // Note: This also closes file descriptor req->sd for us
+ udsSupportRemoveFDFromEventLoop(req->sd, req->platform_data); // Note: This also closes file descriptor req->sd for us
if (req->errsd != req->sd) { dnssd_close(req->errsd); req->errsd = req->sd; }
while (req->replies) // free pending replies
@@ -1195,11 +360,11 @@ mDNSlocal reply_state *create_reply(const reply_op_t op, const size_t datalen, r
if (!reply) FatalError("ERROR: malloc");
reply->next = mDNSNULL;
- reply->totallen = datalen + sizeof(ipc_msg_hdr);
+ reply->totallen = (mDNSu32)datalen + sizeof(ipc_msg_hdr);
reply->nwriten = 0;
reply->mhdr->version = VERSION;
- reply->mhdr->datalen = datalen;
+ reply->mhdr->datalen = (mDNSu32)datalen;
reply->mhdr->ipc_flags = 0;
reply->mhdr->op = op;
reply->mhdr->client_context = request->hdr.client_context;
@@ -1413,6 +578,58 @@ mDNSlocal mDNSBool AuthorizedDomain(const request_state * const request, const d
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
+#pragma mark - external helpers
+#endif
+
+mDNSlocal void external_start_advertising_helper(service_instance *const instance)
+ {
+ AuthRecord *st = instance->subtypes;
+ ExtraResourceRecord *e;
+ int i;
+
+ if (mDNSIPPortIsZero(instance->request->u.servicereg.port))
+ {
+ LogInfo("external_start_advertising_helper: Not registering service with port number zero");
+ return;
+ }
+
+ if (instance->external_advertise) LogMsg("external_start_advertising_helper: external_advertise already set!");
+
+ for ( i = 0; i < instance->request->u.servicereg.num_subtypes; i++)
+ external_start_advertising_service(&st[i].resrec);
+
+ external_start_advertising_service(&instance->srs.RR_PTR.resrec);
+ external_start_advertising_service(&instance->srs.RR_TXT.resrec);
+
+ for (e = instance->srs.Extras; e; e = e->next)
+ external_start_advertising_service(&e->r.resrec);
+
+ instance->external_advertise = mDNStrue;
+ }
+
+mDNSlocal void external_stop_advertising_helper(service_instance *const instance)
+ {
+ AuthRecord *st = instance->subtypes;
+ ExtraResourceRecord *e;
+ int i;
+
+ if (!instance->external_advertise) return;
+
+ for ( i = 0; i < instance->request->u.servicereg.num_subtypes; i++)
+ external_start_advertising_service(&st[i].resrec);
+
+ external_stop_advertising_service(&instance->srs.RR_PTR.resrec);
+ external_stop_advertising_service(&instance->srs.RR_TXT.resrec);
+
+ for (e = instance->srs.Extras; e; e = e->next)
+ external_stop_advertising_service(&e->r.resrec);
+
+ instance->external_advertise = mDNSfalse;
+ }
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
#pragma mark - DNSServiceRegister
#endif
@@ -1434,6 +651,8 @@ mDNSlocal void unlink_and_free_service_instance(service_instance *srv)
{
ExtraResourceRecord *e = srv->srs.Extras, *tmp;
+ external_stop_advertising_helper(srv);
+
// clear pointers from parent struct
if (srv->request)
{
@@ -1468,16 +687,11 @@ mDNSexport int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs
int count = 0;
ResourceRecord *r = &srs->RR_SRV.resrec;
AuthRecord *rr;
- ServiceRecordSet *s;
for (rr = m->ResourceRecords; rr; rr=rr->next)
if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !IdenticalSameNameRecord(&rr->resrec, r))
count++;
- for (s = m->ServiceRegistrations; s; s = s->uDNS_next)
- if (s->state != regState_Unregistered && SameDomainName(s->RR_SRV.resrec.name, r->name) && !IdenticalSameNameRecord(&s->RR_SRV.resrec, r))
- count++;
-
verbosedebugf("%d peer registrations for %##s", count, r->name->c);
return(count);
}
@@ -1509,16 +723,13 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
{
mStatus err;
mDNSBool SuppressError = mDNSfalse;
- service_instance *instance = srs->ServiceContext;
+ service_instance *instance;
reply_state *rep;
- char *fmt = "";
- if (mDNS_LoggingEnabled)
- fmt = (result == mStatus_NoError) ? "%3d: DNSServiceRegister(%##s, %u) REGISTERED" :
- (result == mStatus_MemFree) ? "%3d: DNSServiceRegister(%##s, %u) DEREGISTERED" :
- (result == mStatus_NameConflict) ? "%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT" :
- "%3d: DNSServiceRegister(%##s, %u) %s %d";
(void)m; // Unused
+
if (!srs) { LogMsg("regservice_callback: srs is NULL %d", result); return; }
+
+ instance = srs->ServiceContext;
if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; }
// don't send errors up to client for wide-area, empty-string registrations
@@ -1527,8 +738,18 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
!instance->default_local)
SuppressError = mDNStrue;
- LogOperation(fmt, instance->request ? instance->request->sd : -99,
- srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), SuppressError ? "suppressed error" : "CALLBACK", result);
+ if (mDNS_LoggingEnabled)
+ {
+ const char *const fmt =
+ (result == mStatus_NoError) ? "%s DNSServiceRegister(%##s, %u) REGISTERED" :
+ (result == mStatus_MemFree) ? "%s DNSServiceRegister(%##s, %u) DEREGISTERED" :
+ (result == mStatus_NameConflict) ? "%s DNSServiceRegister(%##s, %u) NAME CONFLICT" :
+ "%s DNSServiceRegister(%##s, %u) %s %d";
+ char prefix[16] = "---:";
+ if (instance->request) mDNS_snprintf(prefix, sizeof(prefix), "%3d:", instance->request->sd);
+ LogOperation(fmt, prefix, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port),
+ SuppressError ? "suppressed error" : "CALLBACK", result);
+ }
if (!instance->request && result != mStatus_MemFree) { LogMsg("regservice_callback: instance->request is NULL %d", result); return; }
@@ -1548,6 +769,8 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c);
else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
+ if (instance->request->u.servicereg.InterfaceID == mDNSInterface_P2P || (!instance->request->u.servicereg.InterfaceID && SameDomainName(&instance->domain, &localdomain)))
+ external_start_advertising_helper(instance);
if (instance->request->u.servicereg.autoname && CountPeerRegistrations(m, srs) == 0)
RecordUpdatedNiceLabel(m, 0); // Successfully got new name, tell user immediately
}
@@ -1555,6 +778,7 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
{
if (instance->request && instance->renameonmemfree)
{
+ external_stop_advertising_helper(instance);
instance->renameonmemfree = 0;
err = mDNS_RenameAndReregisterService(m, srs, &instance->request->u.servicereg.name);
if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err);
@@ -1567,6 +791,7 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
{
if (instance->request->u.servicereg.autorename)
{
+ external_stop_advertising_helper(instance);
if (instance->request->u.servicereg.autoname && CountPeerRegistrations(m, srs) == 0)
{
// On conflict for an autoname service, rename and reregister *all* autoname services
@@ -1590,7 +815,7 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
unlink_and_free_service_instance(instance);
}
}
- else
+ else // Not mStatus_NoError, mStatus_MemFree, or mStatus_NameConflict
{
if (!SuppressError)
{
@@ -1607,7 +832,7 @@ mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
if (!rr->RecordContext) // parent struct already freed by termination callback
{
if (result == mStatus_NoError)
- LogMsg("Error: regrecord_callback: successful registration of orphaned record");
+ LogMsg("Error: regrecord_callback: successful registration of orphaned record %s", ARDisplayString(m, rr));
else
{
if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
@@ -1618,14 +843,27 @@ mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
{
registered_record_entry *re = rr->RecordContext;
request_state *request = re->request;
- int len = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + sizeof(DNSServiceErrorType);
- reply_state *reply = create_reply(reg_record_reply_op, len, request);
- reply->mhdr->client_context = re->regrec_client_context;
- reply->rhdr->flags = dnssd_htonl(0);
- reply->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, rr->resrec.InterfaceID));
- reply->rhdr->error = dnssd_htonl(result);
-
- LogOperation("%3d: DNSServiceRegisterRecord(%u) result %d", request->sd, request->hdr.reg_index, result);
+
+ if (mDNS_LoggingEnabled)
+ {
+ char *fmt = (result == mStatus_NoError) ? "%3d: DNSServiceRegisterRecord(%u %s) REGISTERED" :
+ (result == mStatus_MemFree) ? "%3d: DNSServiceRegisterRecord(%u %s) DEREGISTERED" :
+ (result == mStatus_NameConflict) ? "%3d: DNSServiceRegisterRecord(%u %s) NAME CONFLICT" :
+ "%3d: DNSServiceRegisterRecord(%u %s) %d";
+ LogOperation(fmt, request->sd, re->key, RRDisplayString(m, &rr->resrec), result);
+ }
+
+ if (result != mStatus_MemFree)
+ {
+ int len = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + sizeof(DNSServiceErrorType);
+ reply_state *reply = create_reply(reg_record_reply_op, len, request);
+ reply->mhdr->client_context = re->regrec_client_context;
+ reply->rhdr->flags = dnssd_htonl(0);
+ reply->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, rr->resrec.InterfaceID));
+ reply->rhdr->error = dnssd_htonl(result);
+ append_reply(request, reply);
+ }
+
if (result)
{
// unlink from list, free memory
@@ -1636,13 +874,26 @@ mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
freeL("registered_record_entry AuthRecord regrecord_callback", re->rr);
freeL("registered_record_entry regrecord_callback", re);
}
- append_reply(request, reply);
+ else
+ {
+ if (re->external_advertise) LogMsg("regrecord_callback: external_advertise already set!");
+ if (re->origInterfaceID == mDNSInterface_P2P || (!re->origInterfaceID && IsLocalDomain(&rr->namestorage)))
+ {
+ external_start_advertising_service(&rr->resrec);
+ re->external_advertise = mDNStrue;
+ }
+ }
}
}
mDNSlocal void connection_termination(request_state *request)
{
+ // When terminating a shared connection, we need to scan the all_requests list
+ // and terminate any subbordinate operations sharing this file descriptor
request_state **req = &all_requests;
+
+ LogOperation("%3d: DNSServiceCreateConnection STOP", request->sd);
+
while (*req)
{
if ((*req)->primary == request)
@@ -1662,8 +913,14 @@ mDNSlocal void connection_termination(request_state *request)
while (request->u.reg_recs)
{
registered_record_entry *ptr = request->u.reg_recs;
+ LogOperation("%3d: DNSServiceRegisterRecord(%u %s) STOP", request->sd, ptr->key, RRDisplayString(&mDNSStorage, &ptr->rr->resrec));
request->u.reg_recs = request->u.reg_recs->next;
ptr->rr->RecordContext = NULL;
+ if (ptr->external_advertise)
+ {
+ ptr->external_advertise = mDNSfalse;
+ external_stop_advertising_service(&ptr->rr->resrec);
+ }
mDNS_Deregister(&mDNSStorage, ptr->rr); // Will free ptr->rr for us
freeL("registered_record_entry/connection_termination", ptr);
}
@@ -1699,22 +956,26 @@ mDNSlocal mStatus handle_regrecord_request(request_state *request)
// allocate registration entry, link into list
registered_record_entry *re = mallocL("registered_record_entry", sizeof(registered_record_entry));
if (!re) FatalError("ERROR: malloc");
- re->key = request->hdr.reg_index;
- re->rr = rr;
- re->request = request;
+ re->key = request->hdr.reg_index;
+ re->rr = rr;
re->regrec_client_context = request->hdr.client_context;
- rr->RecordContext = re;
- rr->RecordCallback = regrecord_callback;
+ re->request = request;
+ re->external_advertise = mDNSfalse;
+ rr->RecordContext = re;
+ rr->RecordCallback = regrecord_callback;
+
re->next = request->u.reg_recs;
request->u.reg_recs = re;
-
+
+ re->origInterfaceID = rr->resrec.InterfaceID;
+ if (rr->resrec.InterfaceID == mDNSInterface_P2P) rr->resrec.InterfaceID = mDNSInterface_Any;
#if 0
if (!AuthorizedDomain(request, rr->resrec.name, AutoRegistrationDomains)) return (mStatus_NoError);
#endif
if (rr->resrec.rroriginalttl == 0)
rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
- LogOperation("%3d: DNSServiceRegisterRecord(%u %s)", request->sd, request->hdr.reg_index, RRDisplayString(&mDNSStorage, &rr->resrec));
+ LogOperation("%3d: DNSServiceRegisterRecord(%u %s) START", request->sd, re->key, RRDisplayString(&mDNSStorage, &rr->resrec));
err = mDNS_Register(&mDNSStorage, rr);
}
return(err);
@@ -1732,6 +993,8 @@ mDNSlocal void regservice_termination_callback(request_state *request)
// only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP",
request->sd, p->srs.RR_SRV.resrec.name->c, mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port));
+
+ external_stop_advertising_helper(p);
// Clear backpointer *before* calling mDNS_DeregisterService/unlink_and_free_service_instance
// We don't need unlink_and_free_service_instance to cut its element from the list, because we're already advancing
@@ -1780,6 +1043,8 @@ mDNSlocal mStatus add_record_to_service(request_state *request, service_instance
if (result) { freeL("ExtraResourceRecord/add_record_to_service", extra); return result; }
extra->ClientID = request->hdr.reg_index;
+ if (instance->external_advertise && (instance->request->u.servicereg.InterfaceID == mDNSInterface_P2P || (!instance->request->u.servicereg.InterfaceID && SameDomainName(&instance->domain, &localdomain))))
+ external_start_advertising_service(&extra->r.resrec);
return result;
}
@@ -1816,21 +1081,37 @@ mDNSlocal mStatus handle_add_request(request_state *request)
return(result);
}
-mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
+mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd, mDNSu16 oldrdlen)
{
+ mDNSBool external_advertise = (rr->UpdateContext) ? *((mDNSBool *)rr->UpdateContext) : mDNSfalse;
(void)m; // Unused
+
+ // There are three cases.
+ //
+ // 1. We have updated the primary TXT record of the service
+ // 2. We have updated the TXT record that was added to the service using DNSServiceAddRecord
+ // 3. We have updated the TXT record that was registered using DNSServiceRegisterRecord
+ //
+ // external_advertise is set if we have advertised at least once during the initial addition
+ // of the record in all of the three cases above. We should have checked for InterfaceID/LocalDomain
+ // checks during the first time and hence we don't do any checks here
+ if (external_advertise)
+ {
+ ResourceRecord ext = rr->resrec;
+ if (ext.rdlength == oldrdlen && mDNSPlatformMemSame(&ext.rdata->u, &oldrd->u, oldrdlen)) goto exit;
+ SetNewRData(&ext, oldrd, oldrdlen);
+ external_stop_advertising_service(&ext);
+ external_start_advertising_service(&rr->resrec);
+ }
+exit:
if (oldrd != &rr->rdatastorage) freeL("RData/update_callback", oldrd);
}
-mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, const char *rdata, mDNSu32 ttl)
+mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, const char *rdata, mDNSu32 ttl, const mDNSBool *const external_advertise)
{
- int rdsize;
- RData *newrd;
mStatus result;
-
- if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
- else rdsize = sizeof(RDataBody);
- newrd = mallocL("RData/update_record", sizeof(RData) - sizeof(RDataBody) + rdsize);
+ const int rdsize = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
+ RData *newrd = mallocL("RData/update_record", sizeof(RData) - sizeof(RDataBody) + rdsize);
if (!newrd) FatalError("ERROR: malloc");
newrd->MaxRDLength = (mDNSu16) rdsize;
mDNSPlatformMemCopy(&newrd->u, rdata, rdlen);
@@ -1839,9 +1120,11 @@ mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, const char *rdata
// 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.
if (rr->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; }
-
+
+ if (external_advertise) rr->UpdateContext = (void *)external_advertise;
+
result = mDNS_Update(&mDNSStorage, rr, ttl, rdlen, newrd, update_callback);
- if (result) { LogMsg("ERROR: mDNS_Update - %d", result); freeL("RData/update_record", newrd); }
+ if (result) { LogMsg("update_record: Error %d for %s", (int)result, ARDisplayString(&mDNSStorage, rr)); freeL("RData/update_record", newrd); }
return result;
}
@@ -1872,7 +1155,9 @@ mDNSlocal mStatus handle_update_request(request_state *request)
{
if (reptr->key == hdr->reg_index)
{
- result = update_record(reptr->rr, rdlen, rdata, ttl);
+ result = update_record(reptr->rr, rdlen, rdata, ttl, &reptr->external_advertise);
+ LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)",
+ request->sd, reptr->rr->resrec.name->c, reptr->rr ? DNSTypeName(reptr->rr->resrec.rrtype) : "<NONE>");
goto end;
}
}
@@ -1894,8 +1179,7 @@ mDNSlocal mStatus handle_update_request(request_state *request)
if (!request->u.servicereg.txtdata) FatalError("ERROR: handle_update_request - malloc");
mDNSPlatformMemCopy(request->u.servicereg.txtdata, rdata, rdlen);
}
- else
- request->u.servicereg.txtdata = NULL;
+ request->u.servicereg.txtlen = rdlen;
}
// update a record from a service record set
@@ -1910,7 +1194,7 @@ mDNSlocal mStatus handle_update_request(request_state *request)
}
if (!rr) { result = mStatus_BadReferenceErr; goto end; }
- result = update_record(rr, rdlen, rdata, ttl);
+ result = update_record(rr, rdlen, rdata, ttl, &i->external_advertise);
if (result && i->default_local) goto end;
else result = mStatus_NoError; // suppress non-local default errors
}
@@ -1935,14 +1219,20 @@ mDNSlocal mStatus remove_record(request_state *request)
e = *ptr;
*ptr = e->next; // unlink
- LogOperation("%3d: DNSServiceRemoveRecord(%u %s)", request->sd, request->hdr.reg_index, RRDisplayString(&mDNSStorage, &e->rr->resrec));
+ LogOperation("%3d: DNSServiceRemoveRecord(%u %s)", request->sd, e->key, RRDisplayString(&mDNSStorage, &e->rr->resrec));
e->rr->RecordContext = NULL;
- err = mDNS_Deregister(&mDNSStorage, e->rr);
+ if (e->external_advertise)
+ {
+ external_stop_advertising_service(&e->rr->resrec);
+ e->external_advertise = mDNSfalse;
+ }
+ err = mDNS_Deregister(&mDNSStorage, e->rr); // Will free e->rr for us; we're responsible for freeing e
if (err)
{
LogMsg("ERROR: remove_record, mDNS_Deregister: %d", err);
freeL("registered_record_entry AuthRecord remove_record", e->rr);
}
+
freeL("registered_record_entry remove_record", e);
return err;
}
@@ -1957,7 +1247,9 @@ mDNSlocal mStatus remove_extra(const request_state *const request, service_insta
if (ptr->ClientID == request->hdr.reg_index) // found match
{
*rrtype = ptr->r.resrec.rrtype;
- return mDNS_RemoveRecordFromService(&mDNSStorage, &serv->srs, ptr, FreeExtraRR, ptr);
+ if (serv->external_advertise) external_stop_advertising_service(&ptr->r.resrec);
+ err = mDNS_RemoveRecordFromService(&mDNSStorage, &serv->srs, ptr, FreeExtraRR, ptr);
+ break;
}
}
return err;
@@ -2069,8 +1361,19 @@ mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain)
{
service_instance **ptr, *instance;
- int instance_size;
+ const int extra_size = (request->u.servicereg.txtlen > sizeof(RDataBody)) ? (request->u.servicereg.txtlen - sizeof(RDataBody)) : 0;
+ const mDNSBool DomainIsLocal = SameDomainName(domain, &localdomain);
mStatus result;
+ mDNSInterfaceID interfaceID = request->u.servicereg.InterfaceID;
+
+ if (interfaceID == mDNSInterface_P2P) interfaceID = mDNSInterface_Any;
+
+ // If the client specified an interface, but no domain, then we honor the specified interface for the "local" (mDNS)
+ // registration but for the wide-area registrations we don't (currently) have any concept of a wide-area unicast
+ // registrations scoped to a specific interface, so for the automatic domains we add we must *not* specify an interface.
+ // (Specifying an interface with an apparently wide-area domain (i.e. something other than "local")
+ // currently forces the registration to use mDNS multicast despite the apparently wide-area domain.)
+ if (request->u.servicereg.default_domain && !DomainIsLocal) interfaceID = mDNSInterface_Any;
for (ptr = &request->u.servicereg.instances; *ptr; ptr = &(*ptr)->next)
{
@@ -2082,26 +1385,28 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain
}
}
- // Special-case hack: We don't advertise SMB service in AutoTunnel domains, because AutoTunnel
- // services have to support IPv6, and our SMB server does not
- // <rdar://problem/5482322> BTMM: Don't advertise SMB with BTMM because it doesn't support IPv6
- if (SameDomainName(&request->u.servicereg.type, (const domainname *) "\x4" "_smb" "\x4" "_tcp"))
+ if (mDNSStorage.KnownBugs & mDNS_KnownBug_LimitedIPv6)
{
- DomainAuthInfo *AuthInfo = GetAuthInfoForName(&mDNSStorage, domain);
- if (AuthInfo && AuthInfo->AutoTunnel) return(kDNSServiceErr_Unsupported);
+ // Special-case hack: On Mac OS X 10.6.x and earlier we don't advertise SMB service in AutoTunnel domains,
+ // because AutoTunnel services have to support IPv6, and in Mac OS X 10.6.x the SMB server does not.
+ // <rdar://problem/5482322> BTMM: Don't advertise SMB with BTMM because it doesn't support IPv6
+ if (SameDomainName(&request->u.servicereg.type, (const domainname *) "\x4" "_smb" "\x4" "_tcp"))
+ {
+ DomainAuthInfo *AuthInfo = GetAuthInfoForName(&mDNSStorage, domain);
+ if (AuthInfo && AuthInfo->AutoTunnel) return(kDNSServiceErr_Unsupported);
+ }
}
- instance_size = sizeof(*instance);
- if (request->u.servicereg.txtlen > sizeof(RDataBody)) instance_size += (request->u.servicereg.txtlen - sizeof(RDataBody));
- instance = mallocL("service_instance", instance_size);
+ instance = mallocL("service_instance", sizeof(*instance) + extra_size);
if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
- instance->next = mDNSNULL;
- instance->request = request;
- instance->subtypes = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string);
- instance->renameonmemfree = 0;
- instance->clientnotified = mDNSfalse;
- instance->default_local = (request->u.servicereg.default_domain && SameDomainName(domain, &localdomain));
+ instance->next = mDNSNULL;
+ instance->request = request;
+ instance->subtypes = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string);
+ instance->renameonmemfree = 0;
+ instance->clientnotified = mDNSfalse;
+ instance->default_local = (request->u.servicereg.default_domain && DomainIsLocal);
+ instance->external_advertise = mDNSfalse;
AssignDomainName(&instance->domain, domain);
if (request->u.servicereg.num_subtypes && !instance->subtypes)
@@ -2113,7 +1418,7 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain
request->u.servicereg.port,
request->u.servicereg.txtdata, request->u.servicereg.txtlen,
instance->subtypes, request->u.servicereg.num_subtypes,
- request->u.servicereg.InterfaceID, regservice_callback, instance);
+ interfaceID, regservice_callback, instance);
if (!result)
{
@@ -2234,7 +1539,6 @@ mDNSlocal mStatus handle_regservice_request(request_state *request)
if (!request->u.servicereg.txtdata) FatalError("ERROR: handle_regservice_request - malloc");
mDNSPlatformMemCopy(request->u.servicereg.txtdata, get_rdata(&request->msgptr, request->msgend, request->u.servicereg.txtlen), request->u.servicereg.txtlen);
}
- else request->u.servicereg.txtdata = NULL;
if (!request->msgptr) { LogMsg("%3d: DNSServiceRegister(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
@@ -2398,6 +1702,12 @@ mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d
b->next = info->u.browser.browsers;
info->u.browser.browsers = b;
LogOperation("%3d: DNSServiceBrowse(%##s) START", info->sd, b->q.qname.c);
+ if (info->u.browser.interface_id == mDNSInterface_P2P || (!info->u.browser.interface_id && SameDomainName(&b->domain, &localdomain)))
+ {
+ domainname tmp;
+ ConstructServiceName(&tmp, NULL, &info->u.browser.regtype, &b->domain);
+ external_start_browsing_for_service(&mDNSStorage, &tmp, kDNSType_PTR);
+ }
}
return err;
}
@@ -2407,6 +1717,14 @@ mDNSlocal void browse_termination_callback(request_state *info)
while (info->u.browser.browsers)
{
browser_t *ptr = info->u.browser.browsers;
+
+ if (info->u.browser.interface_id == mDNSInterface_P2P || (!info->u.browser.interface_id && SameDomainName(&ptr->domain, &localdomain)))
+ {
+ domainname tmp;
+ ConstructServiceName(&tmp, NULL, &info->u.browser.regtype, &ptr->domain);
+ external_stop_browsing_for_service(&mDNSStorage, &tmp, kDNSType_PTR);
+ }
+
info->u.browser.browsers = ptr->next;
LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info->sd, ptr->q.qname.c);
mDNS_StopBrowse(&mDNSStorage, &ptr->q); // no need to error-check result
@@ -2468,13 +1786,20 @@ mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus r
// On shutdown, mDNS_Close automatically deregisters all records
// Since in this case no one has called DeregisterLocalOnlyDomainEnumPTR to cut the record
// from the LocalDomainEnumRecords list, we do this here before we free the memory.
+ // (This should actually no longer be necessary, now that we do the proper cleanup in
+ // udsserver_exit. To confirm this, we'll log an error message if we do find a record that
+ // hasn't been cut from the list yet. If these messages don't appear, we can delete this code.)
ARListElem **ptr = &LocalDomainEnumRecords;
while (*ptr && &(*ptr)->ar != rr) ptr = &(*ptr)->next;
- if (*ptr) *ptr = (*ptr)->next;
+ if (*ptr) { *ptr = (*ptr)->next; LogMsg("FreeARElemCallback: Have to cut %s", ARDisplayString(m, rr)); }
mDNSPlatformMemFree(rr->RecordContext);
}
}
+// RegisterLocalOnlyDomainEnumPTR and DeregisterLocalOnlyDomainEnumPTR largely duplicate code in
+// "FoundDomain" in uDNS.c for creating and destroying these special mDNSInterface_LocalOnly records.
+// We may want to turn the common code into a subroutine.
+
mDNSlocal void RegisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, int type)
{
// allocate/register legacy and non-legacy _browse PTR record
@@ -2624,8 +1949,9 @@ mDNSexport void udsserver_handle_configchange(mDNS *const m)
{
ptr->renameonmemfree = 1;
if (ptr->clientnotified) SendServiceRemovalNotification(&ptr->srs);
- if (mDNS_DeregisterService(m, &ptr->srs)) // If service was deregistered already
- regservice_callback(m, &ptr->srs, mStatus_MemFree); // we can re-register immediately
+ LogInfo("udsserver_handle_configchange: Calling deregister for Service %##s", ptr->srs.RR_PTR.resrec.name->c);
+ if (mDNS_DeregisterService_drt(m, &ptr->srs, mDNS_Dereg_rapid))
+ regservice_callback(m, &ptr->srs, mStatus_MemFree); // If service deregistered already, we can re-register immediately
}
}
@@ -2836,6 +2162,7 @@ mDNSlocal void resolve_termination_callback(request_state *request)
LogOperation("%3d: DNSServiceResolve(%##s) STOP", request->sd, request->u.resolve.qtxt.qname.c);
mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qtxt);
mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
+ if (request->u.resolve.external_advertise) external_stop_resolving_service(&request->u.resolve.qsrv.qname);
}
mDNSlocal mStatus handle_resolve_request(request_state *request)
@@ -2847,7 +2174,13 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
// extract the data from the message
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
- mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+ mDNSInterfaceID InterfaceID;
+ mDNSBool wasP2P = (interfaceIndex == kDNSServiceInterfaceIndexP2P);
+
+
+ if (wasP2P) interfaceIndex = kDNSServiceInterfaceIndexAny;
+
+ InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
if (interfaceIndex && !InterfaceID)
{ LogMsg("ERROR: handle_resolve_request bad interfaceIndex %d", interfaceIndex); return(mStatus_BadParamErr); }
@@ -2885,11 +2218,14 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
request->u.resolve.qtxt.ExpectUnique = mDNStrue;
request->u.resolve.qtxt.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
request->u.resolve.qtxt.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+ request->u.resolve.qtxt.SuppressUnusable = mDNSfalse;
request->u.resolve.qtxt.QuestionCallback = resolve_result_callback;
request->u.resolve.qtxt.QuestionContext = request;
request->u.resolve.ReportTime = NonZeroTime(mDNS_TimeNow(&mDNSStorage) + 130 * mDNSPlatformOneSecond);
+ request->u.resolve.external_advertise = mDNSfalse;
+
#if 0
if (!AuthorizedDomain(request, &fqdn, AutoBrowseDomains)) return(mStatus_NoError);
#endif
@@ -2901,7 +2237,13 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
{
err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qtxt);
if (err) mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
- else request->terminate = resolve_termination_callback;
+ else
+ {
+ request->terminate = resolve_termination_callback;
+ // If the user explicitly passed in P2P, we don't restrict the domain in which we resolve.
+ if (wasP2P || (!InterfaceID && IsLocalDomain(&fqdn)))
+ { request->u.resolve.external_advertise = mDNStrue; external_start_resolving_service(&fqdn);}
+ }
}
return(err);
@@ -2929,21 +2271,19 @@ mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question,
(void)m; // Unused
#if APPLE_OSX_mDNSResponder
- if (question == &req->u.queryrecord.q2)
+ if (question == &req->u.queryrecord.q2 && question->qtype != req->u.queryrecord.q.qtype && !SameDomainName(&question->qname, &req->u.queryrecord.q.qname))
{
mDNS_StopQuery(&mDNSStorage, question);
+ question->QuestionCallback = mDNSNULL;
// If we got a non-negative answer for our "local SOA" test query, start an additional parallel unicast query
- if (answer->RecordType == kDNSRecordTypePacketNegative ||
- (question->qtype == req->u.queryrecord.q.qtype && SameDomainName(&question->qname, &req->u.queryrecord.q.qname)))
- question->QuestionCallback = mDNSNULL;
- else
+ if (answer->RecordType != kDNSRecordTypePacketNegative)
{
*question = req->u.queryrecord.q;
question->InterfaceID = mDNSInterface_Unicast;
question->ExpectUnique = mDNStrue;
+ LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast", req->sd, question->qname.c, DNSTypeName(question->qtype));
mStatus err = mDNS_StartQuery(&mDNSStorage, question);
- if (!err) LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast", req->sd, question->qname.c, DNSTypeName(question->qtype));
- else LogMsg("%3d: ERROR: queryrecord_result_callback %##s %s mDNS_StartQuery: %d", req->sd, question->qname.c, DNSTypeName(question->qtype), (int)err);
+ if (err) LogMsg("%3d: ERROR: queryrecord_result_callback %##s %s mDNS_StartQuery: %d", req->sd, question->qname.c, DNSTypeName(question->qtype), (int)err);
}
return;
}
@@ -2995,6 +2335,77 @@ mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question,
put_uint32(AddRecord ? answer->rroriginalttl : 0, &data);
append_reply(req, rep);
+#if APPLE_OSX_mDNSResponder
+#if ! NO_WCF
+ CHECK_WCF_FUNCTION(WCFIsServerRunning)
+ {
+ struct xucred x;
+ socklen_t xucredlen = sizeof(x);
+
+ if (WCFIsServerRunning((WCFConnection *)m->WCF) && answer->rdlength != 0)
+ {
+ if (getsockopt(req->sd, 0, LOCAL_PEERCRED, &x, &xucredlen) >= 0 &&
+ (x.cr_version == XUCRED_VERSION))
+ {
+ struct sockaddr_storage addr;
+ const RDataBody2 *const rdb = (RDataBody2 *)answer->rdata->u.data;
+ addr.ss_len = 0;
+ if (answer->rrtype == kDNSType_A || answer->rrtype == kDNSType_AAAA)
+ {
+ if (answer->rrtype == kDNSType_A)
+ {
+ struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
+ sin->sin_port = 0;
+ if (!putRData(mDNSNULL, (mDNSu8 *)&sin->sin_addr, (mDNSu8 *)(&sin->sin_addr + sizeof(rdb->ipv4)), answer))
+ LogMsg("queryrecord_result_callback: WCF AF_INET putRData failed");
+ else
+ {
+ addr.ss_len = sizeof (struct sockaddr_in);
+ addr.ss_family = AF_INET;
+ }
+ }
+ else if (answer->rrtype == kDNSType_AAAA)
+ {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
+ sin6->sin6_port = 0;
+ if (!putRData(mDNSNULL, (mDNSu8 *)&sin6->sin6_addr, (mDNSu8 *)(&sin6->sin6_addr + sizeof(rdb->ipv6)), answer))
+ LogMsg("queryrecord_result_callback: WCF AF_INET6 putRData failed");
+ else
+ {
+ addr.ss_len = sizeof (struct sockaddr_in6);
+ addr.ss_family = AF_INET6;
+ }
+ }
+ if (addr.ss_len)
+ {
+ debugf("queryrecord_result_callback: Name %s, uid %u, addr length %d", name, x.cr_uid, addr.ss_len);
+ CHECK_WCF_FUNCTION((WCFConnection *)WCFNameResolvesToAddr)
+ {
+ WCFNameResolvesToAddr(m->WCF, name, (struct sockaddr *)&addr, x.cr_uid);
+ }
+ }
+ }
+ else if (answer->rrtype == kDNSType_CNAME)
+ {
+ domainname cname;
+ char cname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+ if (!putRData(mDNSNULL, cname.c, (mDNSu8 *)(cname.c + MAX_DOMAIN_NAME), answer))
+ LogMsg("queryrecord_result_callback: WCF CNAME putRData failed");
+ else
+ {
+ ConvertDomainNameToCString(&cname, cname_cstr);
+ CHECK_WCF_FUNCTION((WCFConnection *)WCFNameResolvesToAddr)
+ {
+ WCFNameResolvesToName(m->WCF, name, cname_cstr, x.cr_uid);
+ }
+ }
+ }
+ }
+ else my_perror("queryrecord_result_callback: ERROR: getsockopt LOCAL_PEERCRED");
+ }
+ }
+#endif
+#endif
}
mDNSlocal void queryrecord_termination_callback(request_state *request)
@@ -3002,6 +2413,8 @@ mDNSlocal void queryrecord_termination_callback(request_state *request)
LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP",
request->sd, request->u.queryrecord.q.qname.c, DNSTypeName(request->u.queryrecord.q.qtype));
mDNS_StopQuery(&mDNSStorage, &request->u.queryrecord.q); // no need to error check
+ if (request->u.queryrecord.q.InterfaceID == mDNSInterface_P2P || (!request->u.queryrecord.q.InterfaceID && SameDomainName((const domainname *)LastLabel(&request->u.queryrecord.q.qname), &localdomain)))
+ external_stop_browsing_for_service(&mDNSStorage, &request->u.queryrecord.q.qname, request->u.queryrecord.q.qtype);
if (request->u.queryrecord.q2.QuestionCallback) mDNS_StopQuery(&mDNSStorage, &request->u.queryrecord.q2);
}
@@ -3038,13 +2451,19 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request)
q->ExpectUnique = mDNSfalse;
q->ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
q->ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+ q->SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable) != 0;
q->QuestionCallback = queryrecord_result_callback;
q->QuestionContext = request;
- LogOperation("%3d: DNSServiceQueryRecord(%##s, %s, %X) START", request->sd, q->qname.c, DNSTypeName(q->qtype), flags);
+ LogOperation("%3d: DNSServiceQueryRecord(%X, %d, %##s, %s) START", request->sd, flags, interfaceIndex, q->qname.c, DNSTypeName(q->qtype));
err = mDNS_StartQuery(&mDNSStorage, q);
if (err) LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q->qname.c, DNSTypeName(q->qtype), (int)err);
- else request->terminate = queryrecord_termination_callback;
+ else
+ {
+ request->terminate = queryrecord_termination_callback;
+ if (q->InterfaceID == mDNSInterface_P2P || (!q->InterfaceID && SameDomainName((const domainname *)LastLabel(&q->qname), &localdomain)))
+ external_start_browsing_for_service(&mDNSStorage, &q->qname, q->qtype);
+ }
#if APPLE_OSX_mDNSResponder
// Workaround for networks using Microsoft Active Directory using "local" as a private internal top-level domain
@@ -3068,6 +2487,8 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request)
// then that's a hint that it's worth doing a unicast query. Otherwise, we first check to see if the
// site's DNS server claims there's an SOA record for "local", and if so, that's also a hint that queries
// for names in the "local" domain will be safely answered privately before they hit the root name servers.
+ // Note that in the "my-small-company.local" example above there will typically be an SOA record for
+ // "my-small-company.local" but *not* for "local", which is why the "local SOA" check would fail in that case.
if (labels == 2 && !SameDomainName(&q->qname, &ActiveDirectoryPrimaryDomain))
{
AssignDomainName(&q2->qname, &localdomain);
@@ -3076,9 +2497,9 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request)
q2->ForceMCast = mDNSfalse;
q2->ReturnIntermed = mDNStrue;
}
+ LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast", request->sd, q2->qname.c, DNSTypeName(q2->qtype));
err = mDNS_StartQuery(&mDNSStorage, q2);
- if (!err) LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast", request->sd, q2->qname.c, DNSTypeName(q2->qtype));
- else LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q2->qname.c, DNSTypeName(q2->qtype), (int)err);
+ if (err) LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q2->qname.c, DNSTypeName(q2->qtype), (int)err);
}
#endif // APPLE_OSX_mDNSResponder
@@ -3247,7 +2668,7 @@ typedef packedstruct
mDNSlocal void handle_getproperty_request(request_state *request)
{
- const mStatus BadParamErr = dnssd_htonl(mStatus_BadParamErr);
+ const mStatus BadParamErr = dnssd_htonl((mDNSu32)mStatus_BadParamErr);
char prop[256];
if (get_string(&request->msgptr, request->msgend, prop, sizeof(prop)) >= 0)
{
@@ -3332,7 +2753,7 @@ mDNSlocal mStatus handle_port_mapping_request(request_state *request)
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
- mDNSu8 protocol = get_uint32(&request->msgptr, request->msgend);
+ mDNSu8 protocol = (mDNSu8)get_uint32(&request->msgptr, request->msgend);
(void)flags; // Unused
if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
if (request->msgptr + 8 > request->msgend) request->msgptr = NULL;
@@ -3382,6 +2803,8 @@ mDNSlocal mStatus handle_port_mapping_request(request_state *request)
mDNSlocal void addrinfo_termination_callback(request_state *request)
{
+ LogOperation("%3d: DNSServiceGetAddrInfo(%##s) STOP", request->sd, request->u.addrinfo.q4.qname.c);
+
if (request->u.addrinfo.q4.QuestionContext)
{
mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q4);
@@ -3401,7 +2824,7 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request)
domainname d;
mStatus err = 0;
- DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+ DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
mDNSPlatformMemZero(&request->u.addrinfo, sizeof(request->u.addrinfo));
@@ -3425,39 +2848,25 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request)
if (!request->u.addrinfo.protocol)
{
- NetworkInterfaceInfo *i;
- if (IsLocalDomain(&d))
- {
- for (i = mDNSStorage.HostInterfaces; i; i = i->next)
- {
- if ((i->ip.type == mDNSAddrType_IPv4) && !mDNSIPv4AddressIsZero(i->ip.ip.v4)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv4;
- else if ((i->ip.type == mDNSAddrType_IPv6) && !mDNSIPv6AddressIsZero(i->ip.ip.v6)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv6;
- }
- }
- else
- {
- for (i = mDNSStorage.HostInterfaces; i; i = i->next)
- {
- if ((i->ip.type == mDNSAddrType_IPv4) && !mDNSv4AddressIsLinkLocal(&i->ip.ip.v4)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv4;
- else if ((i->ip.type == mDNSAddrType_IPv6) && !mDNSv4AddressIsLinkLocal(&i->ip.ip.v6)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv6;
- }
- }
+ flags |= kDNSServiceFlagsSuppressUnusable;
+ request->u.addrinfo.protocol = (kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6);
}
+ request->u.addrinfo.q4.InterfaceID = request->u.addrinfo.q6.InterfaceID = request->u.addrinfo.interface_id;
+ request->u.addrinfo.q4.Target = request->u.addrinfo.q6.Target = zeroAddr;
+ request->u.addrinfo.q4.qname = request->u.addrinfo.q6.qname = d;
+ request->u.addrinfo.q4.qclass = request->u.addrinfo.q6.qclass = kDNSServiceClass_IN;
+ request->u.addrinfo.q4.LongLived = request->u.addrinfo.q6.LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0;
+ request->u.addrinfo.q4.ExpectUnique = request->u.addrinfo.q6.ExpectUnique = mDNSfalse;
+ request->u.addrinfo.q4.ForceMCast = request->u.addrinfo.q6.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
+ request->u.addrinfo.q4.ReturnIntermed = request->u.addrinfo.q6.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+ request->u.addrinfo.q4.SuppressUnusable = request->u.addrinfo.q6.SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable ) != 0;
+
if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4)
{
- request->u.addrinfo.q4.InterfaceID = request->u.addrinfo.interface_id;
- request->u.addrinfo.q4.Target = zeroAddr;
- request->u.addrinfo.q4.qname = d;
request->u.addrinfo.q4.qtype = kDNSServiceType_A;
- request->u.addrinfo.q4.qclass = kDNSServiceClass_IN;
- request->u.addrinfo.q4.LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0;
- request->u.addrinfo.q4.ExpectUnique = mDNSfalse;
- request->u.addrinfo.q4.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
- request->u.addrinfo.q4.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
request->u.addrinfo.q4.QuestionCallback = queryrecord_result_callback;
request->u.addrinfo.q4.QuestionContext = request;
-
err = mDNS_StartQuery(&mDNSStorage, &request->u.addrinfo.q4);
if (err != mStatus_NoError)
{
@@ -3468,29 +2877,25 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request)
if (!err && (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv6))
{
- request->u.addrinfo.q6.InterfaceID = request->u.addrinfo.interface_id;
- request->u.addrinfo.q6.Target = zeroAddr;
- request->u.addrinfo.q6.qname = d;
request->u.addrinfo.q6.qtype = kDNSServiceType_AAAA;
- request->u.addrinfo.q6.qclass = kDNSServiceClass_IN;
- request->u.addrinfo.q6.LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0;
- request->u.addrinfo.q6.ExpectUnique = mDNSfalse;
- request->u.addrinfo.q6.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
- request->u.addrinfo.q6.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
request->u.addrinfo.q6.QuestionCallback = queryrecord_result_callback;
request->u.addrinfo.q6.QuestionContext = request;
-
err = mDNS_StartQuery(&mDNSStorage, &request->u.addrinfo.q6);
if (err != mStatus_NoError)
{
LogMsg("ERROR: mDNS_StartQuery: %d", (int)err);
request->u.addrinfo.q6.QuestionContext = mDNSNULL;
- if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4) // If we started a query for IPv4,
- addrinfo_termination_callback(request); // we need to cancel it
+ if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4)
+ {
+ // If we started a query for IPv4, we need to cancel it
+ mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q4);
+ request->u.addrinfo.q4.QuestionContext = mDNSNULL;
+ }
}
}
- LogOperation("%3d: DNSServiceGetAddrInfo(%##s) START", request->sd, d.c);
+ LogOperation("%3d: DNSServiceGetAddrInfo(%X, %d, %d, %##s) START",
+ request->sd, flags, interfaceIndex, request->u.addrinfo.protocol, d.c);
if (!err) request->terminate = addrinfo_termination_callback;
@@ -3523,7 +2928,7 @@ mDNSlocal void read_msg(request_state *req)
if (req->ts == t_complete) // this must be death or something is wrong
{
char buf[4]; // dummy for death notification
- int nread = recv(req->sd, buf, 4, 0);
+ int nread = udsSupportReadFD(req->sd, buf, 4, 0, req->platform_data);
if (!nread) { req->ts = t_terminated; return; }
if (nread < 0) goto rerror;
LogMsg("%3d: ERROR: read data from a completed request", req->sd);
@@ -3537,7 +2942,7 @@ mDNSlocal void read_msg(request_state *req)
if (req->hdr_bytes < sizeof(ipc_msg_hdr))
{
mDNSu32 nleft = sizeof(ipc_msg_hdr) - req->hdr_bytes;
- int nread = recv(req->sd, (char *)&req->hdr + req->hdr_bytes, nleft, 0);
+ int nread = udsSupportReadFD(req->sd, (char *)&req->hdr + req->hdr_bytes, nleft, 0, req->platform_data);
if (nread == 0) { req->ts = t_terminated; return; }
if (nread < 0) goto rerror;
req->hdr_bytes += nread;
@@ -3555,7 +2960,7 @@ mDNSlocal void read_msg(request_state *req)
// with 64kB of rdata. Adding 1009 byte for a maximal domain name, plus a safety margin
// for other overhead, this means any message above 70kB is definitely bogus.
if (req->hdr.datalen > 70000)
- { LogMsg("%3d: ERROR: read_msg - hdr.datalen %lu (%X) > 70000", req->sd, req->hdr.datalen, req->hdr.datalen); req->ts = t_error; return; }
+ { LogMsg("%3d: ERROR: read_msg: hdr.datalen %u (0x%X) > 70000", req->sd, req->hdr.datalen, req->hdr.datalen); req->ts = t_error; return; }
req->msgbuf = mallocL("request_state msgbuf", req->hdr.datalen + MSG_PAD_BYTES);
if (!req->msgbuf) { my_perror("ERROR: malloc"); req->ts = t_error; return; }
req->msgptr = req->msgbuf;
@@ -3586,7 +2991,7 @@ mDNSlocal void read_msg(request_state *req)
msg.msg_flags = 0;
nread = recvmsg(req->sd, &msg, 0);
#else
- nread = recv(req->sd, (char *)req->msgbuf + req->data_bytes, nleft, 0);
+ nread = udsSupportReadFD(req->sd, (char *)req->msgbuf + req->data_bytes, nleft, 0, req->platform_data);
#endif
if (nread == 0) { req->ts = t_terminated; return; }
if (nread < 0) goto rerror;
@@ -3642,7 +3047,7 @@ mDNSlocal void read_msg(request_state *req)
dnssd_sockaddr_t cliaddr;
#if defined(USE_TCP_LOOPBACK)
mDNSOpaque16 port;
- int opt = 1;
+ u_long opt = 1;
port.b[0] = req->msgptr[0];
port.b[1] = req->msgptr[1];
req->msgptr += 2;
@@ -3684,7 +3089,9 @@ mDNSlocal void read_msg(request_state *req)
return;
}
+#if !defined(USE_TCP_LOOPBACK)
got_errfd:
+#endif
LogOperation("%3d: Error socket %d created %08X %08X", req->sd, req->errsd, req->hdr.client_context.u32[1], req->hdr.client_context.u32[0]);
#if defined(_WIN32)
if (ioctlsocket(req->errsd, FIONBIO, &opt) != 0)
@@ -3720,9 +3127,6 @@ mDNSlocal void request_callback(int fd, short filter, void *info)
{
mStatus err = 0;
request_state *req = info;
-#if defined(_WIN32)
- u_long opt = 1;
-#endif
mDNSs32 min_size = sizeof(DNSServiceFlags);
(void)fd; // Unused
(void)filter; // Unused
@@ -3852,9 +3256,7 @@ mDNSlocal void connect_callback(int fd, short filter, void *info)
dnssd_sockaddr_t cliaddr;
dnssd_socklen_t len = (dnssd_socklen_t) sizeof(cliaddr);
dnssd_sock_t sd = accept(fd, (struct sockaddr*) &cliaddr, &len);
-#if defined(SO_NOSIGPIPE)
- int optval = 1;
-#elif defined(_WIN32)
+#if defined(SO_NOSIGPIPE) || defined(_WIN32)
unsigned long optval = 1;
#endif
@@ -3897,7 +3299,7 @@ mDNSlocal void connect_callback(int fd, short filter, void *info)
debugf("LOCAL_PEERCRED %d %u %u %d", xucredlen, x.cr_version, x.cr_uid, x.cr_ngroups);
#endif // APPLE_OSX_mDNSResponder
LogOperation("%3d: Adding FD for uid %u", request->sd, request->uid);
- udsSupportAddFDToEventLoop(sd, request_callback, request);
+ udsSupportAddFDToEventLoop(sd, request_callback, request, &request->platform_data);
}
}
@@ -3930,7 +3332,7 @@ mDNSlocal mDNSBool uds_socket_setup(dnssd_sock_t skt)
return mDNSfalse;
}
- if (mStatus_NoError != udsSupportAddFDToEventLoop(skt, connect_callback, (void *) NULL))
+ if (mStatus_NoError != udsSupportAddFDToEventLoop(skt, connect_callback, (void *) NULL, (void **) NULL))
{
my_perror("ERROR: could not add listen socket to event loop");
return mDNSfalse;
@@ -3945,9 +3347,6 @@ mDNSexport int udsserver_init(dnssd_sock_t skts[], mDNSu32 count)
dnssd_sockaddr_t laddr;
int ret;
mDNSu32 i = 0;
-#if defined(_WIN32)
- u_long opt = 1;
-#endif
LogInfo("udsserver_init");
@@ -4039,8 +3438,8 @@ mDNSexport int udsserver_init(dnssd_sock_t skts[], mDNSu32 count)
#endif
// We start a "LocalOnly" query looking for Automatic Browse Domain records.
- // When Domain Enumeration in uDNS.c finds an "lb" record from the network, it creates a
- // "LocalOnly" record, which results in our AutomaticBrowseDomainChange callback being invoked
+ // When Domain Enumeration in uDNS.c finds an "lb" record from the network, its "FoundDomain" routine
+ // creates a "LocalOnly" record, which results in our AutomaticBrowseDomainChange callback being invoked
mDNS_GetDomains(&mDNSStorage, &mDNSStorage.AutomaticBrowseDomainQ, mDNS_DomainTypeBrowseAutomatic,
mDNSNULL, mDNSInterface_LocalOnly, AutomaticBrowseDomainChange, mDNSNULL);
@@ -4060,6 +3459,18 @@ error:
mDNSexport int udsserver_exit(void)
{
+ // Cancel all outstanding client requests
+ while (all_requests) AbortUnlinkAndFree(all_requests);
+
+ // Clean up any special mDNSInterface_LocalOnly records we created, both the entries for "local" we
+ // created in udsserver_init, and others we created as a result of reading local configuration data
+ while (LocalDomainEnumRecords)
+ {
+ ARListElem *rem = LocalDomainEnumRecords;
+ LocalDomainEnumRecords = LocalDomainEnumRecords->next;
+ mDNS_Deregister(&mDNSStorage, &rem->ar);
+ }
+
// If the launching environment created no listening socket,
// that means we created it ourselves, so we should clean it up on exit
if (dnssd_SocketValid(listenfd))
@@ -4079,39 +3490,53 @@ mDNSexport int udsserver_exit(void)
return 0;
}
-mDNSlocal void LogClientInfo(mDNS *const m, request_state *req)
+mDNSlocal void LogClientInfo(mDNS *const m, const request_state *req)
{
+ char prefix[16];
+ if (req->primary) mDNS_snprintf(prefix, sizeof(prefix), " -> ");
+ else mDNS_snprintf(prefix, sizeof(prefix), "%3d:", req->sd);
+
+ usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
+
if (!req->terminate)
- LogMsgNoIdent("%3d: No operation yet on this socket", req->sd);
+ LogMsgNoIdent("%s No operation yet on this socket", prefix);
else if (req->terminate == connection_termination)
{
- registered_record_entry *p;
- LogMsgNoIdent("%3d: DNSServiceCreateConnection", req->sd);
+ int num_records = 0, num_ops = 0;
+ const registered_record_entry *p;
+ const request_state *r;
+ for (p = req->u.reg_recs; p; p=p->next) num_records++;
+ for (r = req->next; r; r=r->next) if (r->primary == req) num_ops++;
+ LogMsgNoIdent("%s DNSServiceCreateConnection: %d registered record%s, %d kDNSServiceFlagsShareConnection operation%s", prefix,
+ num_records, num_records != 1 ? "s" : "",
+ num_ops, num_ops != 1 ? "s" : "");
for (p = req->u.reg_recs; p; p=p->next)
LogMsgNoIdent(" -> DNSServiceRegisterRecord %3d %s", p->key, ARDisplayString(m, p->rr));
+ for (r = req->next; r; r=r->next) if (r->primary == req) LogClientInfo(m, r);
}
else if (req->terminate == regservice_termination_callback)
{
service_instance *ptr;
for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
- LogMsgNoIdent("%3d: DNSServiceRegister %##s %u/%u",
- req->sd, ptr->srs.RR_SRV.resrec.name->c, mDNSVal16(req->u.servicereg.port), SRS_PORT(&ptr->srs));
+ LogMsgNoIdent("%s DNSServiceRegister %##s %u/%u",
+ (ptr == req->u.servicereg.instances) ? prefix : " ",
+ ptr->srs.RR_SRV.resrec.name->c, mDNSVal16(req->u.servicereg.port), SRS_PORT(&ptr->srs));
}
else if (req->terminate == browse_termination_callback)
{
browser_t *blist;
for (blist = req->u.browser.browsers; blist; blist = blist->next)
- LogMsgNoIdent("%3d: DNSServiceBrowse %##s", req->sd, blist->q.qname.c);
+ LogMsgNoIdent("%s DNSServiceBrowse %##s", (blist == req->u.browser.browsers) ? prefix : " ", blist->q.qname.c);
}
else if (req->terminate == resolve_termination_callback)
- LogMsgNoIdent("%3d: DNSServiceResolve %##s", req->sd, req->u.resolve.qsrv.qname.c);
+ LogMsgNoIdent("%s DNSServiceResolve %##s", prefix, req->u.resolve.qsrv.qname.c);
else if (req->terminate == queryrecord_termination_callback)
- LogMsgNoIdent("%3d: DNSServiceQueryRecord %##s (%s)", req->sd, req->u.queryrecord.q.qname.c, DNSTypeName(req->u.queryrecord.q.qtype));
+ LogMsgNoIdent("%s DNSServiceQueryRecord %##s (%s)", prefix, req->u.queryrecord.q.qname.c, DNSTypeName(req->u.queryrecord.q.qtype));
else if (req->terminate == enum_termination_callback)
- LogMsgNoIdent("%3d: DNSServiceEnumerateDomains %##s", req->sd, req->u.enumeration.q_all.qname.c);
+ LogMsgNoIdent("%s DNSServiceEnumerateDomains %##s", prefix, req->u.enumeration.q_all.qname.c);
else if (req->terminate == port_mapping_termination_callback)
- LogMsgNoIdent("%3d: DNSServiceNATPortMapping %.4a %s%s Int %d Req %d Ext %d Req TTL %d Granted TTL %d",
- req->sd,
+ LogMsgNoIdent("%s DNSServiceNATPortMapping %.4a %s%s Int %d Req %d Ext %d Req TTL %d Granted TTL %d",
+ prefix,
&req->u.pm.NATinfo.ExternalAddress,
req->u.pm.NATinfo.Protocol & NATOp_MapTCP ? "TCP" : " ",
req->u.pm.NATinfo.Protocol & NATOp_MapUDP ? "UDP" : " ",
@@ -4121,35 +3546,35 @@ mDNSlocal void LogClientInfo(mDNS *const m, request_state *req)
req->u.pm.NATinfo.NATLease,
req->u.pm.NATinfo.Lifetime);
else if (req->terminate == addrinfo_termination_callback)
- LogMsgNoIdent("%3d: DNSServiceGetAddrInfo %s%s %##s", req->sd,
+ LogMsgNoIdent("%s DNSServiceGetAddrInfo %s%s %##s", prefix,
req->u.addrinfo.protocol & kDNSServiceProtocol_IPv4 ? "v4" : " ",
req->u.addrinfo.protocol & kDNSServiceProtocol_IPv6 ? "v6" : " ",
req->u.addrinfo.q4.qname.c);
else
- LogMsgNoIdent("%3d: Unrecognized operation %p", req->sd, req->terminate);
+ LogMsgNoIdent("%s Unrecognized operation %p", prefix, req->terminate);
}
mDNSlocal void LogAuthRecords(mDNS *const m, const mDNSs32 now, AuthRecord *ResourceRecords, int *proxy)
{
- if (!ResourceRecords) LogMsgNoIdent("<None>");
- else
+ mDNSBool showheader = mDNStrue;
+ const AuthRecord *ar;
+ OwnerOptData owner = zeroOwner;
+ for (ar = ResourceRecords; ar; ar=ar->next)
{
- const AuthRecord *ar;
- mDNSEthAddr owner = zeroEthAddr;
- LogMsgNoIdent(" Int Next Expire State");
- for (ar = ResourceRecords; ar; ar=ar->next)
+ const char *const ifname = InterfaceNameForID(m, ar->resrec.InterfaceID);
+ if ((ar->WakeUp.HMAC.l[0] != 0) == (proxy != mDNSNULL))
{
- NetworkInterfaceInfo *info = (NetworkInterfaceInfo *)ar->resrec.InterfaceID;
- if (ar->WakeUp.HMAC.l[0]) (*proxy)++;
- if (!mDNSSameEthAddress(&owner, &ar->WakeUp.HMAC))
+ if (showheader) { showheader = mDNSfalse; LogMsgNoIdent(" Int Next Expire State"); }
+ if (proxy) (*proxy)++;
+ if (!mDNSPlatformMemSame(&owner, &ar->WakeUp, sizeof(owner)))
{
- owner = ar->WakeUp.HMAC;
- if (ar->WakeUp.password.l[0])
- LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &ar->WakeUp.HMAC, &ar->WakeUp.IMAC, &ar->WakeUp.password, ar->WakeUp.seq);
- else if (!mDNSSameEthAddress(&ar->WakeUp.HMAC, &ar->WakeUp.IMAC))
- LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a seq %d", &ar->WakeUp.HMAC, &ar->WakeUp.IMAC, ar->WakeUp.seq);
+ owner = ar->WakeUp;
+ if (owner.password.l[0])
+ LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner.HMAC, &owner.IMAC, &owner.password, owner.seq);
+ else if (!mDNSSameEthAddress(&owner.HMAC, &owner.IMAC))
+ LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a seq %d", &owner.HMAC, &owner.IMAC, owner.seq);
else
- LogMsgNoIdent("Proxying for %.6a seq %d", &ar->WakeUp.HMAC, ar->WakeUp.seq);
+ LogMsgNoIdent("Proxying for %.6a seq %d", &owner.HMAC, owner.seq);
}
if (AuthRecord_uDNS(ar))
LogMsgNoIdent("%7d %7d %7d %7d %s",
@@ -4157,18 +3582,21 @@ mDNSlocal void LogAuthRecords(mDNS *const m, const mDNSs32 now, AuthRecord *Reso
(ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond,
ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0,
ar->state, ARDisplayString(m, ar));
- else if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly)
+ else if (ar->resrec.InterfaceID == mDNSInterface_LocalOnly)
+ LogMsgNoIdent(" LO %s", ARDisplayString(m, ar));
+ else if (ar->resrec.InterfaceID == mDNSInterface_P2P)
+ LogMsgNoIdent(" PP %s", ARDisplayString(m, ar));
+ else
LogMsgNoIdent("%7d %7d %7d %7s %s",
ar->ThisAPInterval / mDNSPlatformOneSecond,
ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0,
ar->TimeExpire ? (ar->TimeExpire - now) / mDNSPlatformOneSecond : 0,
- info ? info->ifname : "ALL",
+ ifname ? ifname : "ALL",
ARDisplayString(m, ar));
- else
- LogMsgNoIdent(" LO %s", ARDisplayString(m, ar));
usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
}
}
+ if (showheader) LogMsgNoIdent("<None>");
}
mDNSexport void udsserver_info(mDNS *const m)
@@ -4180,10 +3608,11 @@ mDNSexport void udsserver_info(mDNS *const m)
const CacheRecord *cr;
const DNSQuestion *q;
const DNameListElem *d;
+ const SearchListElem *s;
LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32)now, now);
- LogMsgNoIdent("------------ Cache -------------");
+ LogMsgNoIdent("------------ Cache -------------");
LogMsgNoIdent("Slt Q TTL if U Type rdlen");
for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
@@ -4191,15 +3620,19 @@ mDNSexport void udsserver_info(mDNS *const m)
CacheUsed++; // Count one cache entity for the CacheGroup object
for (cr = cg->members; cr; cr=cr->next)
{
- mDNSs32 remain = cr->resrec.rroriginalttl - (now - cr->TimeRcvd) / mDNSPlatformOneSecond;
- NetworkInterfaceInfo *info = (NetworkInterfaceInfo *)cr->resrec.InterfaceID;
+ const mDNSs32 remain = cr->resrec.rroriginalttl - (now - cr->TimeRcvd) / mDNSPlatformOneSecond;
+ const char *ifname;
+ mDNSInterfaceID InterfaceID = cr->resrec.InterfaceID;
+ if (!InterfaceID && cr->resrec.rDNSServer)
+ InterfaceID = cr->resrec.rDNSServer->interface;
+ ifname = InterfaceNameForID(m, InterfaceID);
CacheUsed++;
if (cr->CRActiveQuestion) CacheActive++;
LogMsgNoIdent("%3d %s%8ld %-7s%s %-6s%s",
slot,
cr->CRActiveQuestion ? "*" : " ",
remain,
- info ? info->ifname : "-U-",
+ ifname ? ifname : "-U-",
(cr->resrec.RecordType == kDNSRecordTypePacketNegative) ? "-" :
(cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+",
DNSTypeName(cr->resrec.rrtype),
@@ -4215,24 +3648,16 @@ mDNSexport void udsserver_info(mDNS *const m)
LogMsgNoIdent("Cache currently contains %lu entities; %lu referenced by active questions", CacheUsed, CacheActive);
LogMsgNoIdent("--------- Auth Records ---------");
- LogAuthRecords(m, now, m->ResourceRecords, &ProxyA);
+ LogAuthRecords(m, now, m->ResourceRecords, mDNSNULL);
LogMsgNoIdent("------ Duplicate Records -------");
- LogAuthRecords(m, now, m->DuplicateRecords, &ProxyD);
+ LogAuthRecords(m, now, m->DuplicateRecords, mDNSNULL);
- LogMsgNoIdent("----- ServiceRegistrations -----");
- if (!m->ServiceRegistrations) LogMsgNoIdent("<None>");
- else
- {
- ServiceRecordSet *s;
- LogMsgNoIdent(" Int Next Expire State");
- for (s = m->ServiceRegistrations; s; s = s->uDNS_next)
- LogMsgNoIdent("%7d %7d %7d %7d %s",
- s->RR_SRV.ThisAPInterval / mDNSPlatformOneSecond,
- (s->RR_SRV.LastAPTime + s->RR_SRV.ThisAPInterval - now) / mDNSPlatformOneSecond,
- s->RR_SRV.expire ? (s->RR_SRV.expire - now) / mDNSPlatformOneSecond : 0,
- s->state, ARDisplayString(m, &s->RR_SRV));
- }
+ LogMsgNoIdent("----- Auth Records Proxied -----");
+ LogAuthRecords(m, now, m->ResourceRecords, &ProxyA);
+
+ LogMsgNoIdent("-- Duplicate Records Proxied ---");
+ LogAuthRecords(m, now, m->DuplicateRecords, &ProxyD);
LogMsgNoIdent("---------- Questions -----------");
if (!m->Questions) LogMsgNoIdent("<None>");
@@ -4240,21 +3665,21 @@ mDNSexport void udsserver_info(mDNS *const m)
{
CacheUsed = 0;
CacheActive = 0;
- LogMsgNoIdent(" Int Next if T NumAns Type Name");
+ LogMsgNoIdent(" Int Next if T NumAns VDNS Qptr DupOf SU SQ Type Name");
for (q = m->Questions; q; q=q->next)
{
mDNSs32 i = q->ThisQInterval / mDNSPlatformOneSecond;
- mDNSs32 n = (q->LastQTime + q->ThisQInterval - now) / mDNSPlatformOneSecond;
- NetworkInterfaceInfo *info = (NetworkInterfaceInfo *)q->InterfaceID;
+ mDNSs32 n = (NextQSendTime(q) - now) / mDNSPlatformOneSecond;
+ char *ifname = InterfaceNameForID(m, q->InterfaceID);
CacheUsed++;
if (q->ThisQInterval) CacheActive++;
- LogMsgNoIdent("%6d%6d %-7s%s%s %5d %-6s%##s%s",
+ LogMsgNoIdent("%6d%6d %-7s%s%s %5d 0x%x%x 0x%p 0x%p %1d %2d %-5s%##s%s",
i, n,
- info ? info->ifname : mDNSOpaque16IsZero(q->TargetQID) ? "" : "-U-",
+ ifname ? ifname : mDNSOpaque16IsZero(q->TargetQID) ? "" : "-U-",
mDNSOpaque16IsZero(q->TargetQID) ? (q->LongLived ? "l" : " ") : (q->LongLived ? "L" : "O"),
- q->AuthInfo ? "P" : " ",
- q->CurrentAnswers,
- DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : "");
+ PrivateQuery(q) ? "P" : " ",
+ q->CurrentAnswers, q->validDNSServers.l[1], q->validDNSServers.l[0], q, q->DuplicateOf,
+ q->SuppressUnusable, q->SuppressQuery, DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : "");
usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
}
LogMsgNoIdent("%lu question%s; %lu active", CacheUsed, CacheUsed > 1 ? "s" : "", CacheActive);
@@ -4270,17 +3695,25 @@ mDNSexport void udsserver_info(mDNS *const m)
if (!all_requests) LogMsgNoIdent("<None>");
else
{
- request_state *req;
+ const request_state *req, *r;
for (req = all_requests; req; req=req->next)
+ {
+ if (req->primary) // If this is a subbordinate operation, check that the parent is in the list
+ {
+ for (r = all_requests; r && r != req; r=r->next) if (r == req->primary) goto foundparent;
+ LogMsgNoIdent("%3d: Orhpan operation %p; parent %p not found in request list", req->sd);
+ }
+ // For non-subbordinate operations, and subbordinate operations that have lost their parent, write out their info
LogClientInfo(m, req);
- usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
+ foundparent:;
+ }
}
LogMsgNoIdent("-------- NAT Traversals --------");
if (!m->NATTraversals) LogMsgNoIdent("<None>");
else
{
- NATTraversalInfo *nat;
+ const NATTraversalInfo *nat;
for (nat = m->NATTraversals; nat; nat=nat->next)
{
if (nat->Protocol)
@@ -4302,7 +3735,7 @@ mDNSexport void udsserver_info(mDNS *const m)
if (!m->AuthInfoList) LogMsgNoIdent("<None>");
else
{
- DomainAuthInfo *a;
+ const DomainAuthInfo *a;
for (a = m->AuthInfoList; a; a = a->next)
LogMsgNoIdent("%##s %##s%s", a->domain.c, a->keyname.c, a->AutoTunnel ? " AutoTunnel" : "");
}
@@ -4312,10 +3745,10 @@ mDNSexport void udsserver_info(mDNS *const m)
if (!m->TunnelClients) LogMsgNoIdent("<None>");
else
{
- ClientTunnel *c;
+ const ClientTunnel *c;
for (c = m->TunnelClients; c; c = c->next)
- LogMsgNoIdent("%##s local %.16a %.4a remote %.16a %.4a %5d interval %d",
- c->dstname.c, &c->loc_inner, &c->loc_outer, &c->rmt_inner, &c->rmt_outer, mDNSVal16(c->rmt_outer_port), c->q.ThisQInterval);
+ LogMsgNoIdent("%##s local %.16a %.4a %.16a remote %.16a %.4a %5d %.16a interval %d",
+ c->dstname.c, &c->loc_inner, &c->loc_outer, &c->loc_outer6, &c->rmt_inner, &c->rmt_outer, mDNSVal16(c->rmt_outer_port), &c->rmt_outer6, c->q.ThisQInterval);
}
#endif // APPLE_OSX_mDNSResponder
@@ -4343,6 +3776,68 @@ mDNSexport void udsserver_info(mDNS *const m)
LogMsgNoIdent("--- Auto Registration Domains --");
if (!AutoRegistrationDomains) LogMsgNoIdent("<None>");
else for (d=AutoRegistrationDomains; d; d=d->next) LogMsgNoIdent("%##s", d->name.c);
+
+ LogMsgNoIdent("--- Search Domains --");
+ if (!SearchList) LogMsgNoIdent("<None>");
+ else
+ {
+ for (s=SearchList; s; s=s->next)
+ {
+ LogMsgNoIdent("%##s", s->domain.c);
+ }
+ }
+ LogMsgNoIdent("---- Task Scheduling Timers ----");
+
+ if (!m->NewQuestions)
+ LogMsgNoIdent("NewQuestion <NONE>");
+ else
+ LogMsgNoIdent("NewQuestion DelayAnswering %d %d %##s (%s)",
+ m->NewQuestions->DelayAnswering, m->NewQuestions->DelayAnswering-now,
+ m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
+
+ if (!m->NewLocalOnlyQuestions)
+ LogMsgNoIdent("NewLocalOnlyQuestions <NONE>");
+ else
+ LogMsgNoIdent("NewLocalOnlyQuestions %##s (%s)",
+ m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
+
+ if (!m->NewLocalRecords)
+ LogMsgNoIdent("NewLocalRecords <NONE>");
+ else
+ LogMsgNoIdent("NewLocalRecords %02X %s", m->NewLocalRecords->resrec.RecordType, ARDisplayString(m, m->NewLocalRecords));
+
+ LogMsgNoIdent("SPSProxyListChanged%s", m->SPSProxyListChanged ? "" : " <NONE>");
+ LogMsgNoIdent("LocalRemoveEvents%s", m->LocalRemoveEvents ? "" : " <NONE>");
+
+#define LogTimer(MSG,T) LogMsgNoIdent( MSG " %08X %11d %08X %11d", (T), (T), (T)-now, (T)-now)
+
+ LogMsgNoIdent(" ABS (hex) ABS (dec) REL (hex) REL (dec)");
+ LogMsgNoIdent("m->timenow %08X %11d", now, now);
+ LogMsgNoIdent("m->timenow_adjust %08X %11d", m->timenow_adjust, m->timenow_adjust);
+ LogTimer("m->NextScheduledEvent ", m->NextScheduledEvent);
+
+#ifndef UNICAST_DISABLED
+ LogTimer("m->NextuDNSEvent ", m->NextuDNSEvent);
+ LogTimer("m->NextSRVUpdate ", m->NextSRVUpdate);
+ LogTimer("m->NextScheduledNATOp ", m->NextScheduledNATOp);
+ LogTimer("m->retryGetAddr ", m->retryGetAddr);
+#endif
+
+ LogTimer("m->NextCacheCheck ", m->NextCacheCheck);
+ LogTimer("m->NextScheduledSPS ", m->NextScheduledSPS);
+ LogTimer("m->NextScheduledSPRetry ", m->NextScheduledSPRetry);
+ LogTimer("m->DelaySleep ", m->DelaySleep);
+
+ LogTimer("m->NextScheduledQuery ", m->NextScheduledQuery);
+ LogTimer("m->NextScheduledProbe ", m->NextScheduledProbe);
+ LogTimer("m->NextScheduledResponse", m->NextScheduledResponse);
+
+ LogTimer("m->SuppressSending ", m->SuppressSending);
+ LogTimer("m->SuppressProbes ", m->SuppressProbes);
+ LogTimer("m->ProbeFailTime ", m->ProbeFailTime);
+ LogTimer("m->DelaySleep ", m->DelaySleep);
+ LogTimer("m->SleepLimit ", m->SleepLimit);
+ LogMsgNoIdent("m->RegisterAutoTunnel6 %08X", m->RegisterAutoTunnel6);
}
#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
@@ -4475,6 +3970,7 @@ mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent)
r->replies = r->replies->next;
freeL("reply_state/udsserver_idle", fptr);
r->time_blocked = 0; // reset failure counter after successful send
+ r->unresponsiveness_reports = 0;
continue;
}
else if (result == t_terminated || result == t_error)
@@ -4488,15 +3984,24 @@ mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent)
if (r->replies) // If we failed to send everything, check our time_blocked timer
{
- if (!r->time_blocked) r->time_blocked = NonZeroTime(now);
- if (now - r->time_blocked >= 60 * mDNSPlatformOneSecond)
+ if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond;
+
+ if (mDNSStorage.SleepState != SleepState_Awake) r->time_blocked = 0;
+ else if (!r->time_blocked) r->time_blocked = NonZeroTime(now);
+ else if (now - r->time_blocked >= 10 * mDNSPlatformOneSecond * (r->unresponsiveness_reports+1))
{
- LogMsg("%3d: Could not write data to client after %ld seconds - aborting connection", r->sd,
- (now - r->time_blocked) / mDNSPlatformOneSecond);
- LogClientInfo(&mDNSStorage, r);
- abort_request(r);
+ int num = 0;
+ struct reply_state *x = r->replies;
+ while (x) { num++; x=x->next; }
+ LogMsg("%3d: Could not write data to client after %ld seconds, %d repl%s waiting",
+ r->sd, (now - r->time_blocked) / mDNSPlatformOneSecond, num, num == 1 ? "y" : "ies");
+ if (++r->unresponsiveness_reports >= 60)
+ {
+ LogMsg("%3d: Client unresponsive; aborting connection", r->sd);
+ LogClientInfo(&mDNSStorage, r);
+ abort_request(r);
+ }
}
- else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond;
}
if (!dnssd_SocketValid(r->sd)) // If this request is finished, unlink it from the list and free the memory
@@ -4516,10 +4021,10 @@ struct CompileTimeAssertionChecks_uds_daemon
// Check our structures are reasonable sizes. Including overly-large buffers, or embedding
// other overly-large structures instead of having a pointer to them, can inadvertently
// cause structure sizes (and therefore memory usage) to balloon unreasonably.
- char sizecheck_request_state [(sizeof(request_state) <= 1760) ? 1 : -1];
- char sizecheck_registered_record_entry[(sizeof(registered_record_entry) <= 40) ? 1 : -1];
+ char sizecheck_request_state [(sizeof(request_state) <= 2000) ? 1 : -1];
+ char sizecheck_registered_record_entry[(sizeof(registered_record_entry) <= 60) ? 1 : -1];
char sizecheck_service_instance [(sizeof(service_instance) <= 6552) ? 1 : -1];
- char sizecheck_browser_t [(sizeof(browser_t) <= 992) ? 1 : -1];
+ char sizecheck_browser_t [(sizeof(browser_t) <= 1016) ? 1 : -1];
char sizecheck_reply_hdr [(sizeof(reply_hdr) <= 12) ? 1 : -1];
char sizecheck_reply_state [(sizeof(reply_state) <= 64) ? 1 : -1];
};