diff options
author | Toomas Soome <tsoome@me.com> | 2020-01-07 15:42:59 +0200 |
---|---|---|
committer | Toomas Soome <tsoome@me.com> | 2020-02-20 22:29:32 +0200 |
commit | 3b436d06bb95fd180ef7416b2b1b9972e2f2a513 (patch) | |
tree | 77190298b1f22f87516f5cfe89e14faad8fac20e | |
parent | 6d2858e77c6082a751ff9e66da7408d885792785 (diff) | |
download | illumos-joyent-3b436d06bb95fd180ef7416b2b1b9972e2f2a513.tar.gz |
12168 mDNSResponder update to mDNSResponder-878.260.1
Reviewed by: Ken Mays <kmays2000@gmail.com>
Approved by: Robert Mustacchi <rm@fingolfin.org>
22 files changed, 1099 insertions, 559 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.lib/mdnsd/Makefile b/usr/src/cmd/cmd-inet/usr.lib/mdnsd/Makefile index 5424242b0d..80ab750e70 100644 --- a/usr/src/cmd/cmd-inet/usr.lib/mdnsd/Makefile +++ b/usr/src/cmd/cmd-inet/usr.lib/mdnsd/Makefile @@ -40,7 +40,7 @@ MDNSFLAGS= -DNOT_HAVE_SA_LEN \ -D_XPG4_2 -D__EXTENSIONS__ -DHAVE_BROKEN_RECVIF_NAME \ -DHAVE_IPV6=1 -Dasm=__asm -DMDNSD_NOROOT \ -DPID_FILE=\"\" -DMDNSD_USER=\"noaccess\" \ - -DmDNSResponderVersion=878.1.1 + -DmDNSResponderVersion=878.260.1 include ../../../Makefile.cmd diff --git a/usr/src/contrib/mDNSResponder/Clients/dns-sd.c b/usr/src/contrib/mDNSResponder/Clients/dns-sd.c index f99482be04..b9fe853ce8 100644 --- a/usr/src/contrib/mDNSResponder/Clients/dns-sd.c +++ b/usr/src/contrib/mDNSResponder/Clients/dns-sd.c @@ -174,10 +174,6 @@ static const char kFilePathSep = '/'; #include "../mDNSShared/dnssd_clientstub.c" #endif -#if _DNS_SD_LIBDISPATCH -#include <dispatch/private.h> -#endif - //************************************************************************************************************* // Globals @@ -416,46 +412,36 @@ static unsigned int keytag(unsigned char *key, unsigned int keysize) return ac & 0xFFFF; } -static void base64Encode(char *buffer, int buflen, void *rdata, unsigned int rdlen) +// Base 64 encoding according to <https://tools.ietf.org/html/rfc4648#section-4>. +#define kBase64EncodingTable "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + +static void base64Encode(char *buffer, size_t buflen, void *rdata, size_t rdlen) { -#if _DNS_SD_LIBDISPATCH - const void *result = NULL; - size_t size; - dispatch_data_t src_data = NULL, dest_data = NULL, null_str = NULL, data = NULL, map = NULL; - - src_data = dispatch_data_create(rdata, rdlen, dispatch_get_global_queue(0, 0), ^{}); - if (!src_data) - goto done; - - dest_data = dispatch_data_create_with_transform(src_data, DISPATCH_DATA_FORMAT_TYPE_NONE, DISPATCH_DATA_FORMAT_TYPE_BASE64); - if (!dest_data) - goto done; - - null_str = dispatch_data_create("", 1, dispatch_get_global_queue(0, 0), ^{}); - if (!null_str) - goto done; - - data = dispatch_data_create_concat(dest_data, null_str); - if (!data) - goto done; - - map = dispatch_data_create_map(data, &result, &size); - if (!map) - goto done; - - snprintf(buffer, buflen, " %s", (char *)result); - -done: - if (src_data) dispatch_release(src_data); - if (dest_data) dispatch_release(dest_data); - if (data) dispatch_release(data); - if (null_str) dispatch_release(null_str); - if (map) dispatch_release(map); - return; -#else //_DNS_SD_LIBDISPATCH - snprintf(buffer, buflen, " %s", "."); - return; -#endif //_DNS_SD_LIBDISPATCH + const uint8_t *src = (const uint8_t *)rdata; + const uint8_t *const end = &src[rdlen]; + char *dst = buffer; + const char *lim; + + if (buflen == 0) return; + lim = &buffer[buflen - 1]; + while ((src < end) && (dst < lim)) + { + uint32_t i; + const size_t rem = (size_t)(end - src); + + // Form a 24-bit input group. If less than 24 bits remain, pad with zero bits. + if ( rem >= 3) i = (src[0] << 16) | (src[1] << 8) | src[2]; // 24 bits are equal to 4 6-bit groups. + else if (rem == 2) i = (src[0] << 16) | (src[1] << 8); // 16 bits are treated as 3 6-bit groups + 1 pad + else i = src[0] << 16; // 8 bits are treated as 2 6-bit groups + 2 pads + + // Encode each 6-bit group. + *dst++ = kBase64EncodingTable[(i >> 18) & 0x3F]; + if (dst < lim) *dst++ = kBase64EncodingTable[(i >> 12) & 0x3F]; + if (dst < lim) *dst++ = (rem >= 2) ? kBase64EncodingTable[(i >> 6) & 0x3F] : '='; + if (dst < lim) *dst++ = (rem >= 3) ? kBase64EncodingTable[ i & 0x3F] : '='; + src += (rem > 3) ? 3 : rem; + } + *dst = '\0'; } static DNSServiceProtocol GetProtocol(const char *s) @@ -924,10 +910,10 @@ static int snprintd(char *p, int max, const unsigned char **rd) return(p-buf); } -static void ParseDNSSECRecords(uint16_t rrtype, char *rdb, char *p, unsigned const char *rd, uint16_t rdlen) +static void ParseDNSSECRecords(uint16_t rrtype, char *rdb, size_t rdb_size, unsigned const char *rd, uint16_t rdlen) { - int rdb_size = 1000; - switch (rrtype) + char *p = rdb; + switch (rrtype) { case kDNSServiceType_DS: { @@ -945,7 +931,7 @@ static void ParseDNSSECRecords(uint16_t rrtype, char *rdb, char *p, unsigned con case kDNSServiceType_DNSKEY: { rdataDNSKey *rrkey = (rdataDNSKey *)rd; - p += snprintf(p, rdb + rdb_size - p, "%d %d %d %u", swap16(rrkey->flags), rrkey->proto, + p += snprintf(p, rdb + rdb_size - p, "%d %d %d %u ", swap16(rrkey->flags), rrkey->proto, rrkey->alg, (unsigned int)keytag((unsigned char *)rrkey, rdlen)); base64Encode(p, rdb + rdb_size - p, (unsigned char *)(rd + DNSKEY_FIXED_SIZE), rdlen - DNSKEY_FIXED_SIZE); break; @@ -1026,7 +1012,12 @@ static void ParseDNSSECRecords(uint16_t rrtype, char *rdb, char *p, unsigned con k = p; p += snprintd(p, rdb + rdb_size - p, &q); len = p - k + 1; - + + if ((&rdb[rdb_size] - p) >= 2) + { + *p++ = ' '; + *p = '\0'; + } base64Encode(p, rdb + rdb_size - p, (unsigned char *)(rd + len + RRSIG_FIXED_SIZE), rdlen - (len + RRSIG_FIXED_SIZE)); break; } @@ -1056,9 +1047,9 @@ static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags, if (num_printed++ == 0) { if (operation == 'D') - printf("Timestamp A/R if %-30s%-6s%-7s%-18s Rdata\n", "Name", "Type", "Class", "DNSSECStatus"); + printf("Timestamp A/R if %-30s%-6s%-7s%-18s Rdata\n", "Name", "Type", "Class", "DNSSECStatus"); else - printf("Timestamp A/R Flags if %-30s%-6s%-7s Rdata\n", "Name", "Type", "Class"); + printf("Timestamp A/R Flags if %-30s%-6s%-7s Rdata\n", "Name", "Type", "Class"); } printtimestamp(); @@ -1115,7 +1106,7 @@ static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags, case kDNSServiceType_DNSKEY: case kDNSServiceType_NSEC: case kDNSServiceType_RRSIG: - ParseDNSSECRecords(rrtype, rdb, p, rd, rdlen); + ParseDNSSECRecords(rrtype, rdb, sizeof(rdb), rd, rdlen); break; default: @@ -1143,7 +1134,7 @@ static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags, if (operation == 'D') printf("%s%3d %-30s%-6s%-7s%-18s %s", op, ifIndex, fullname, rr_type, rr_class, dnssec_status, rdb); else - printf("%s%6X%3d %-30s%-7s%-6s %s", op, flags, ifIndex, fullname, rr_type, rr_class, rdb); + printf("%s%9X%3d %-30s%-7s%-6s %s", op, flags, ifIndex, fullname, rr_type, rr_class, rdb); if (unknowntype) { while (rd < end) @@ -1208,7 +1199,7 @@ static void DNSSD_API addrinfo_reply(DNSServiceRef sdref, const DNSServiceFlags if (operation == 'g') printf("Timestamp A/R if %-25s %-44s %-18s\n", "Hostname", "Address", "DNSSECStatus"); else - printf("Timestamp A/R Flags if %-38s %-44s %s\n", "Hostname", "Address", "TTL"); + printf("Timestamp A/R Flags if %-38s %-44s %s\n", "Hostname", "Address", "TTL"); } printtimestamp(); @@ -1248,7 +1239,7 @@ static void DNSSD_API addrinfo_reply(DNSServiceRef sdref, const DNSServiceFlags if (operation == 'g') printf("%s%3d %-25s %-44s %-18s", op, interfaceIndex, hostname, addr, dnssec_status); else - printf("%s%6X%3d %-38s %-44s %d", op, flags, interfaceIndex, hostname, addr, ttl); + printf("%s%9X%3d %-38s %-44s %d", op, flags, interfaceIndex, hostname, addr, ttl); if (errorCode) { if (errorCode == kDNSServiceErr_NoSuchRecord) @@ -1513,12 +1504,6 @@ static int API_string_limit_test() return 0; } -// local prototypes for routines that don't have prototypes in dns_sd.h -#if APPLE_OSX_mDNSResponder -DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain); -DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid); -#endif - static int API_NULL_input_test() { printf("Running basic API input range tests with various pointer parameters set to NULL:\n"); @@ -1915,7 +1900,15 @@ int main(int argc, char **argv) argv++; opinterface = kDNSServiceInterfaceIndexBLE; } - + + if (argc > 1 && !strcasecmp(argv[1], "-allowexpired")) + { + argc--; + argv++; + flags |= kDNSServiceFlagsAllowExpiredAnswers; + printf("Setting kDNSServiceFlagsAllowExpiredAnswers\n"); + } + if (argc > 1 && !strcasecmp(argv[1], "-includep2p")) { argc--; @@ -2288,7 +2281,11 @@ Fail: // NOT static -- otherwise the compiler may optimize it out // The "@(#) " pattern is a special prefix the "what" command looks for +#ifndef MDNS_VERSIONSTR_NODTS +const char VersionString_SCCS[] = "@(#) dns-sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; +#else const char VersionString_SCCS[] = "@(#) dns-sd " STRINGIFY(mDNSResponderVersion); +#endif #if _BUILDING_XCODE_PROJECT_ // If the process crashes, then this string will be magically included in the automatically-generated crash log diff --git a/usr/src/contrib/mDNSResponder/README b/usr/src/contrib/mDNSResponder/README index ea5d4d4740..73c8188fba 100644 --- a/usr/src/contrib/mDNSResponder/README +++ b/usr/src/contrib/mDNSResponder/README @@ -24,6 +24,7 @@ The mdns vendor source repository is at https://github.com/illumos/mdns/. +Updated from upstream version mDNSResponder-878.260.1 Updated from upstream version mDNSResponder-878.1.1 Updated from upstream version mDNSResponder-625.41.2 Updated from upstream version mDNSResponder-576.30.4 diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.c b/usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.c index 323974cb45..35d4e2649c 100644 --- a/usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.c +++ b/usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2002-2015 Apple Inc. All rights reserved. + * Copyright (c) 2002-2018 Apple Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -2770,7 +2770,9 @@ mDNSexport const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 case 0x80: debugf("getDomainName: Illegal label length 0x%X in domain name %##s", len, name->c); return(mDNSNULL); - case 0xC0: offset = (mDNSu16)((((mDNSu16)(len & 0x3F)) << 8) | *ptr++); + case 0xC0: if (ptr >= end) + { debugf("getDomainName: Malformed compression label (overruns packet end)"); return(mDNSNULL); } + offset = (mDNSu16)((((mDNSu16)(len & 0x3F)) << 8) | *ptr++); if (!nextbyte) nextbyte = ptr; // Record where we got to before we started following pointers ptr = (mDNSu8 *)msg + offset; if (ptr < (mDNSu8*)msg || ptr >= end) @@ -3335,7 +3337,7 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con AssignDomainName(&name, (domainname *)ptr); ptr += DomainNameLength(&name); } - if (!ptr) + if (!ptr || ptr >= end) { LogInfo("SetRData: Malformed name for TSIG/TKEY type %d", rr->resrec.rrtype); goto fail; @@ -3448,7 +3450,6 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage 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 SetNextCacheCheckTimeForRecord() - rr->LastUsed = m ? m->timenow : 0; rr->CRActiveQuestion = mDNSNULL; rr->UnansweredQueries = 0; rr->LastUnansweredTime= 0; @@ -3466,16 +3467,15 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage rr->resrec.rrtype = (mDNSu16) ((mDNSu16)ptr[0] << 8 | ptr[1]); rr->resrec.rrclass = (mDNSu16)(((mDNSu16)ptr[2] << 8 | ptr[3]) & kDNSClass_Mask); rr->resrec.rroriginalttl = (mDNSu32) ((mDNSu32)ptr[4] << 24 | (mDNSu32)ptr[5] << 16 | (mDNSu32)ptr[6] << 8 | ptr[7]); - if (rr->resrec.rroriginalttl > 0x70000000UL / mDNSPlatformOneSecond && (mDNSs32)rr->resrec.rroriginalttl != -1) - rr->resrec.rroriginalttl = 0x70000000UL / mDNSPlatformOneSecond; + if (rr->resrec.rroriginalttl > mDNSMaximumTTLSeconds && (mDNSs32)rr->resrec.rroriginalttl != -1) + rr->resrec.rroriginalttl = mDNSMaximumTTLSeconds; // Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for // us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly. pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]); // If mDNS record has cache-flush bit set, we mark it unique - // For uDNS records, all are implicitly deemed unique (a single DNS server is always - // authoritative for the entire RRSet), unless this is a truncated response - if (ptr[2] & (kDNSClass_UniqueRRSet >> 8) || (!InterfaceID && !(msg->h.flags.b[0] & kDNSFlag0_TC))) + // For uDNS records, all are implicitly deemed unique (a single DNS server is always authoritative for the entire RRSet) + if (ptr[2] & (kDNSClass_UniqueRRSet >> 8) || !InterfaceID) RecordType |= kDNSRecordTypePacketUniqueMask; ptr += 10; if (ptr + pktrdlength > end) { debugf("GetLargeResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); } @@ -3629,25 +3629,6 @@ mDNSexport mDNSBool GetPktLease(mDNS *const m, const DNSMessage *const msg, cons return mDNSfalse; } -mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end, int count, char *label) -{ - int i; - LogInfo("%2d %s", count, label); - for (i = 0; i < count && ptr; i++) - { - // This puts a LargeCacheRecord on the stack instead of using the shared m->rec storage, - // but since it's only used for debugging (and probably only on OS X, not on - // 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) - LogInfo("%2d TTL%8d %s", i, largecr.r.resrec.rroriginalttl, CRDisplayString(m, &largecr.r)); - } - if (!ptr) - LogInfo("DumpRecords: ERROR: Premature end of packet data"); - return(ptr); -} - #define DNS_OP_Name(X) ( \ (X) == kDNSFlag0_OP_StdQuery ? "" : \ (X) == kDNSFlag0_OP_Iquery ? "Iquery " : \ @@ -3671,52 +3652,198 @@ mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg, (X) == kDNSFlag1_RC_NotAuth ? "NotAuth" : \ (X) == kDNSFlag1_RC_NotZone ? "NotZone" : "??" ) -// Note: DumpPacket expects the packet header fields in host byte order, not network byte order -mDNSexport void DumpPacket(mDNS *const m, mStatus status, mDNSBool sent, char *transport, - const mDNSAddr *srcaddr, mDNSIPPort srcport, - const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end) +mDNSlocal void mDNS_snprintf_add(char **ptr, const char *lim, const char *fmt, ...) { - mDNSBool IsUpdate = ((msg->h.flags.b[0] & kDNSFlag0_OP_Mask) == kDNSFlag0_OP_Update); - const mDNSu8 *ptr = msg->data; - int i; - DNSQuestion q; - char tbuffer[64], sbuffer[64], dbuffer[64] = ""; - if (!status) tbuffer[mDNS_snprintf(tbuffer, sizeof(tbuffer), sent ? "Sent" : "Received" )] = 0; - else tbuffer[mDNS_snprintf(tbuffer, sizeof(tbuffer), "ERROR %d %sing", status, sent ? "Send" : "Receive")] = 0; - if (sent) sbuffer[mDNS_snprintf(sbuffer, sizeof(sbuffer), "port " )] = 0; - else sbuffer[mDNS_snprintf(sbuffer, sizeof(sbuffer), "%#a:", srcaddr)] = 0; - if (dstaddr || !mDNSIPPortIsZero(dstport)) - dbuffer[mDNS_snprintf(dbuffer, sizeof(dbuffer), " to %#a:%d", dstaddr, mDNSVal16(dstport))] = 0; - - LogInfo("-- %s %s DNS %s%s (flags %02X%02X) RCODE: %s (%d) %s%s%s%s%s%sID: %d %d bytes from %s%d%s%s --", - tbuffer, transport, + va_list args; + mDNSu32 buflen, n; + char *const dst = *ptr; + + buflen = (mDNSu32)(lim - dst); + if (buflen > 0) + { + va_start(args, fmt); + n = mDNS_vsnprintf(dst, buflen, fmt, args); + va_end(args); + *ptr = dst + n; + } +} + +#define DNSTypeString(X) (((X) == kDNSType_A) ? "A" : DNSTypeName(X)) + +#define ReadField16(PTR) ((mDNSu16)((((mDNSu16)((mDNSu8 *)(PTR))[0]) << 8) | ((mDNSu16)((mDNSu8 *)(PTR))[1]))) +#define ReadField32(PTR) \ + ((mDNSu32)( \ + (((mDNSu32)((mDNSu8 *)(PTR))[0]) << 24) | \ + (((mDNSu32)((mDNSu8 *)(PTR))[1]) << 16) | \ + (((mDNSu32)((mDNSu8 *)(PTR))[2]) << 8) | \ + ((mDNSu32)((mDNSu8 *)(PTR))[3]))) + +mDNSlocal void DNSMessageDump(const DNSMessage *const msg, const mDNSu8 *const end, char *buffer, mDNSu32 buflen) +{ + domainname *name; + const mDNSu8 *ptr; + domainname nameStorage[2]; + char *dst = buffer; + const char *const lim = &buffer[buflen]; + mDNSu32 i; + const mDNSu32 rrcount = msg->h.numAnswers + msg->h.numAuthorities + msg->h.numAdditionals; + + mDNS_snprintf_add(&dst, lim, "DNS %s%s (%lu) (flags %02X%02X) RCODE: %s (%d)%s%s%s%s%s%s ID: %u:", DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask), - msg->h.flags.b[0] & kDNSFlag0_QR_Response ? "Response" : "Query", + (msg->h.flags.b[0] & kDNSFlag0_QR_Response) ? "Response" : "Query", + (unsigned long)(end - (const mDNSu8 *)msg), msg->h.flags.b[0], msg->h.flags.b[1], DNS_RC_Name(msg->h.flags.b[1] & kDNSFlag1_RC_Mask), msg->h.flags.b[1] & kDNSFlag1_RC_Mask, - msg->h.flags.b[0] & kDNSFlag0_AA ? "AA " : "", - msg->h.flags.b[0] & kDNSFlag0_TC ? "TC " : "", - msg->h.flags.b[0] & kDNSFlag0_RD ? "RD " : "", - msg->h.flags.b[1] & kDNSFlag1_RA ? "RA " : "", - msg->h.flags.b[1] & kDNSFlag1_AD ? "AD " : "", - msg->h.flags.b[1] & kDNSFlag1_CD ? "CD " : "", - mDNSVal16(msg->h.id), - end - msg->data, - sbuffer, mDNSVal16(srcport), dbuffer, - (msg->h.flags.b[0] & kDNSFlag0_TC) ? " (truncated)" : "" - ); - - LogInfo("%2d %s", msg->h.numQuestions, IsUpdate ? "Zone" : "Questions"); - for (i = 0; i < msg->h.numQuestions && ptr; i++) + (msg->h.flags.b[0] & kDNSFlag0_AA) ? " AA" : "", + (msg->h.flags.b[0] & kDNSFlag0_TC) ? " TC" : "", + (msg->h.flags.b[0] & kDNSFlag0_RD) ? " RD" : "", + (msg->h.flags.b[1] & kDNSFlag1_RA) ? " RA" : "", + (msg->h.flags.b[1] & kDNSFlag1_AD) ? " AD" : "", + (msg->h.flags.b[1] & kDNSFlag1_CD) ? " CD" : "", + mDNSVal16(msg->h.id)); + + name = mDNSNULL; + ptr = msg->data; + for (i = 0; i < msg->h.numQuestions; i++) + { + mDNSu16 qtype, qclass; + + name = &nameStorage[0]; + ptr = getDomainName(msg, ptr, end, name); + if (!ptr) goto exit; + + if ((end - ptr) < 4) goto exit; + qtype = ReadField16(&ptr[0]); + qclass = ReadField16(&ptr[2]); + ptr += 4; + + mDNS_snprintf_add(&dst, lim, " %##s %s", name->c, DNSTypeString(qtype)); + if (qclass != kDNSClass_IN) mDNS_snprintf_add(&dst, lim, "/%u", qclass); + mDNS_snprintf_add(&dst, lim, "?"); + } + + mDNS_snprintf_add(&dst, lim, " %u/%u/%u", msg->h.numAnswers, msg->h.numAuthorities, msg->h.numAdditionals); + for (i = 0; i < rrcount; i++) { - ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &q); - if (ptr) LogInfo("%2d %##s %s", i, q.qname.c, DNSTypeName(q.qtype)); + mDNSu16 rrtype, rrclass, rdlength; + mDNSu32 ttl; + int handled; + const mDNSu8 *rdata; + const domainname *const previousName = name; + + name = &nameStorage[(name == &nameStorage[0]) ? 1 : 0]; + ptr = getDomainName(msg, ptr, end, name); + if (!ptr) goto exit; + + if ((end - ptr) < 10) goto exit; + rrtype = ReadField16(&ptr[0]); + rrclass = ReadField16(&ptr[2]); + ttl = ReadField32(&ptr[4]); + rdlength = ReadField16(&ptr[8]); + ptr += 10; + + if ((end - ptr) < rdlength) goto exit; + rdata = ptr; + + if (i > 0) mDNS_snprintf_add(&dst, lim, ","); + if (!previousName || !SameDomainName(name, previousName)) mDNS_snprintf_add(&dst, lim, " %##s", name); + + mDNS_snprintf_add(&dst, lim, " %s", DNSTypeString(rrtype)); + if (rrclass != kDNSClass_IN) mDNS_snprintf_add(&dst, lim, "/%u", rrclass); + mDNS_snprintf_add(&dst, lim, " "); + + handled = mDNSfalse; + switch (rrtype) + { + case kDNSType_A: + if (rdlength == 4) + { + mDNS_snprintf_add(&dst, lim, "%.4a", rdata); + handled = mDNStrue; + } + break; + + case kDNSType_AAAA: + if (rdlength == 16) + { + mDNS_snprintf_add(&dst, lim, "%.16a", rdata); + handled = mDNStrue; + } + break; + + case kDNSType_CNAME: + ptr = getDomainName(msg, rdata, end, name); + if (!ptr) goto exit; + + mDNS_snprintf_add(&dst, lim, "%##s", name); + handled = mDNStrue; + break; + + case kDNSType_SOA: + { + mDNSu32 serial, refresh, retry, expire, minimum; + domainname *const mname = &nameStorage[0]; + domainname *const rname = &nameStorage[1]; + name = mDNSNULL; + + ptr = getDomainName(msg, rdata, end, mname); + if (!ptr) goto exit; + + ptr = getDomainName(msg, ptr, end, rname); + if (!ptr) goto exit; + + if ((end - ptr) < 20) goto exit; + serial = ReadField32(&ptr[0]); + refresh = ReadField32(&ptr[4]); + retry = ReadField32(&ptr[8]); + expire = ReadField32(&ptr[12]); + minimum = ReadField32(&ptr[16]); + + mDNS_snprintf_add(&dst, lim, "%##s %##s %lu %lu %lu %lu %lu", mname, rname, (unsigned long)serial, + (unsigned long)refresh, (unsigned long)retry, (unsigned long)expire, (unsigned long)minimum); + + handled = mDNStrue; + break; + } + + default: + break; + } + if (!handled) mDNS_snprintf_add(&dst, lim, "RDATA[%u]: %.*H", rdlength, rdlength, rdata); + mDNS_snprintf_add(&dst, lim, " (%lu)", (unsigned long)ttl); + ptr = rdata + rdlength; } - ptr = DumpRecords(m, msg, ptr, end, msg->h.numAnswers, IsUpdate ? "Prerequisites" : "Answers"); - ptr = DumpRecords(m, msg, ptr, end, msg->h.numAuthorities, IsUpdate ? "Updates" : "Authorities"); - DumpRecords(m, msg, ptr, end, msg->h.numAdditionals, "Additionals"); - LogInfo("--------------"); + +exit: + return; +} + +// Note: DumpPacket expects the packet header fields in host byte order, not network byte order +mDNSexport void DumpPacket(mStatus status, mDNSBool sent, char *transport, + const mDNSAddr *srcaddr, mDNSIPPort srcport, + const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end) +{ + char buffer[512]; + char *dst = buffer; + const char *const lim = &buffer[512]; + + buffer[0] = '\0'; + if (!status) mDNS_snprintf_add(&dst, lim, sent ? "Sent" : "Received"); + else mDNS_snprintf_add(&dst, lim, "ERROR %d %sing", status, sent ? "Send" : "Receiv"); + + mDNS_snprintf_add(&dst, lim, " %s DNS Message %u bytes from ", transport, (unsigned long)(end - (const mDNSu8 *)msg)); + + if (sent) mDNS_snprintf_add(&dst, lim, "port %d", mDNSVal16(srcport)); + else mDNS_snprintf_add(&dst, lim, "%#a:%d", srcaddr, mDNSVal16(srcport)); + + if (dstaddr || !mDNSIPPortIsZero(dstport)) mDNS_snprintf_add(&dst, lim, " to %#a:%d", dstaddr, mDNSVal16(dstport)); + + LogInfo("%s", buffer); + + buffer[0] = '\0'; + DNSMessageDump(msg, end, buffer, (mDNSu32)sizeof(buffer)); + LogInfo("%s", buffer); } // *************************************************************************** @@ -3823,7 +3950,7 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS // Dump the packet with the HINFO and TSIG if (mDNS_PacketLoggingEnabled && !mDNSOpaque16IsZero(msg->h.id)) - DumpPacket(m, status, mDNStrue, sock && (sock->flags & kTCPSocketFlags_UseTLS) ? "TLS" : sock ? "TCP" : "UDP", mDNSNULL, src ? src->port : MulticastDNSPort, dst, dstport, msg, end); + DumpPacket(status, mDNStrue, sock && (sock->flags & kTCPSocketFlags_UseTLS) ? "TLS" : sock ? "TCP" : "UDP", mDNSNULL, src ? src->port : MulticastDNSPort, dst, dstport, msg, end); // put the number of additionals back the way it was msg->h.numAdditionals = numAdditionals; @@ -4052,6 +4179,9 @@ static const struct mDNSprintf_format unsigned int precision; } mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +#define kHexDigitsLowercase "0123456789abcdef" +#define kHexDigitsUppercase "0123456789ABCDEF"; + mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg) { mDNSu32 nwritten = 0; @@ -4063,6 +4193,7 @@ mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt for (c = *fmt; c != 0; c = *++fmt) { unsigned long n; + int hexdump = mDNSfalse; if (c != '%') { *sbuffer++ = (char)c; @@ -4189,10 +4320,63 @@ decimal: if (!F.havePrecision) a[0], a[1], a[2], a[3]); break; case 6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X", a[0], a[1], a[2], a[3], a[4], a[5]); break; - case 16: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), - "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X", - a[0x0], a[0x1], a[0x2], a[0x3], a[0x4], a[0x5], a[0x6], a[0x7], - a[0x8], a[0x9], a[0xA], a[0xB], a[0xC], a[0xD], a[0xE], a[0xF]); break; + case 16: { + // Print IPv6 addresses according to RFC 5952, A Recommendation for IPv6 Address Text + // Representation. See <https://tools.ietf.org/html/rfc5952>. + + int idx, runLen = 0, runStart = 0, maxRunLen = 0, maxRunStart = 0, maxRunEnd; + + // Find the leftmost longest run of consecutive zero hextets. + for (idx = 0; idx < 8; ++idx) + { + const unsigned int hextet = (a[idx * 2] << 8) | a[(idx * 2) + 1]; + if (hextet == 0) + { + if (runLen++ == 0) runStart = idx; + if (runLen > maxRunLen) + { + maxRunStart = runStart; + maxRunLen = runLen; + } + } + else + { + // If the number of remaining hextets is less than or equal to the length of the longest + // run so far, then we've found the leftmost longest run. + if ((8 - (idx + 1)) <= maxRunLen) break; + runLen = 0; + } + } + + // Compress the leftmost longest run of two or more consecutive zero hextets as "::". + // For each reminaing hextet, suppress zeros leading up to the least-significant nibble, which + // is always written, even if it's zero. Because of this requirement, it's easier to write the + // IPv6 address in reverse. Also, write a colon separator before each hextet except for the + // first one. + s = mDNS_VACB_Lim; + maxRunEnd = (maxRunLen >= 2) ? (maxRunStart + maxRunLen - 1) : -1; + for (idx = 7; idx >= 0; --idx) + { + if (idx == maxRunEnd) + { + if (idx == 7) *--s = ':'; + idx = maxRunStart; + *--s = ':'; + } + else + { + unsigned int hextet = (a[idx * 2] << 8) | a[(idx * 2) + 1]; + do { + *--s = kHexDigitsLowercase[hextet % 16]; + hextet /= 16; + } while (hextet); + if (idx > 0) *--s = ':'; + } + } + i = (unsigned int)(mDNS_VACB_Lim - s); + } + break; + default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify" " address size (i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break; } @@ -4203,9 +4387,9 @@ decimal: if (!F.havePrecision) case 'p': F.havePrecision = F.lSize = 1; F.precision = sizeof(void*) * 2; // 8 characters on 32-bit; 16 characters on 64-bit /* FALLTHROUGH */ - case 'X': digits = "0123456789ABCDEF"; + case 'X': digits = kHexDigitsUppercase; goto hexadecimal; - case 'x': digits = "0123456789abcdef"; + case 'x': digits = kHexDigitsLowercase; hexadecimal: if (F.lSize) n = va_arg(arg, unsigned long); else n = va_arg(arg, unsigned int); if (F.hSize) n = (unsigned short) n; @@ -4288,6 +4472,12 @@ hexadecimal: if (F.lSize) n = va_arg(arg, unsigned long); { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--;} break; + case 'H': { + s = va_arg(arg, char *); + hexdump = mDNStrue; + } + break; + case 'n': s = va_arg(arg, char *); if (F.hSize) *(short *) s = (short)nwritten; else if (F.lSize) *(long *) s = (long)nwritten; @@ -4309,14 +4499,34 @@ hexadecimal: if (F.lSize) n = va_arg(arg, unsigned long); if (++nwritten >= buflen) goto exit; } while (i < --F.fieldWidth); - // Make sure we don't truncate in the middle of a UTF-8 character. - // Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the - // allowed output. If s[i] is a UTF-8 continuation character, then we've cut a unicode character in half, - // so back up 'i' until s[i] is no longer a UTF-8 continuation character. (if the input was proprly - // formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated). - if (i > buflen - nwritten) - { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--;} - for (j=0; j<i; j++) *sbuffer++ = *s++; // Write the converted result + if (hexdump) + { + char *dst = sbuffer; + const char *const lim = &sbuffer[buflen - nwritten]; + if (F.havePrecision) + { + for (i = 0; (i < F.precision) && (dst < lim); i++) + { + const unsigned int b = (unsigned int) *s++; + if (i > 0) *dst++ = ' '; + if (dst < lim) *dst++ = kHexDigitsLowercase[(b >> 4) & 0xF]; + if (dst < lim) *dst++ = kHexDigitsLowercase[ b & 0xF]; + } + } + i = (unsigned int)(dst - sbuffer); + sbuffer = dst; + } + else + { + // Make sure we don't truncate in the middle of a UTF-8 character. + // Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the + // allowed output. If s[i] is a UTF-8 continuation character, then we've cut a unicode character in half, + // so back up 'i' until s[i] is no longer a UTF-8 continuation character. (if the input was proprly + // formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated). + if (i > buflen - nwritten) + { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--;} + for (j=0; j<i; j++) *sbuffer++ = *s++; // Write the converted result + } nwritten += i; if (nwritten >= buflen) goto exit; diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.h b/usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.h index 1e0e09abe1..6e468cdb81 100644 --- a/usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.h +++ b/usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002-2018 Apple Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -110,6 +110,13 @@ extern mDNSu32 mDNSRandom(mDNSu32 max); // Returns pseudo-random result from #define mDNSIsUpperCase(X) ((X) >= 'A' && (X) <= 'Z') #define mDNSIsLowerCase(X) ((X) >= 'a' && (X) <= 'z') #define mDNSIsLetter(X) (mDNSIsUpperCase(X) || mDNSIsLowerCase(X)) + +// We believe we have adequate safeguards to protect against cache poisoning. +// In the event that someone does find a workable cache poisoning attack, we want to limit the lifetime of the poisoned entry. +// We set the maximum allowable TTL to one hour. +// With the 25% correction factor to avoid the DNS Zeno's paradox bug, that gives us an actual maximum lifetime of 75 minutes. + +#define mDNSMaximumTTLSeconds (mDNSu32)3600 #define mDNSValidHostChar(X, notfirst, notlast) (mDNSIsLetter(X) || mDNSIsDigit(X) || ((notfirst) && (notlast) && (X) == '-') ) @@ -260,7 +267,7 @@ extern const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8 extern const mDNSu8 *LocateOptRR(const DNSMessage *const msg, const mDNSu8 *const end, int minsize); extern const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end); extern mDNSBool GetPktLease(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, mDNSu32 *const lease); -extern void DumpPacket(mDNS *const m, mStatus status, mDNSBool sent, char *transport, +extern void DumpPacket(mStatus status, mDNSBool sent, char *transport, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end); extern mDNSBool RRAssertsNonexistence(const ResourceRecord *const rr, mDNSu16 type); diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/DNSDigest.c b/usr/src/contrib/mDNSResponder/mDNSCore/DNSDigest.c index 0f8b32b082..6520ac6f6e 100644 --- a/usr/src/contrib/mDNSResponder/mDNSCore/DNSDigest.c +++ b/usr/src/contrib/mDNSResponder/mDNSCore/DNSDigest.c @@ -1,6 +1,7 @@ /* -*- Mode: C; tab-width: 4 -*- * * Copyright (c) 2002-2011 Apple Inc. All rights reserved. + * Copyright (c) 2016 by Delphix. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/mDNS.c b/usr/src/contrib/mDNSResponder/mDNSCore/mDNS.c index f51c22b287..0d94aae681 100755 --- a/usr/src/contrib/mDNSResponder/mDNSCore/mDNS.c +++ b/usr/src/contrib/mDNSResponder/mDNSCore/mDNS.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2002-2015 Apple Inc. All rights reserved. + * Copyright (c) 2002-2018 Apple Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -83,7 +83,7 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m); mDNSlocal void RetrySPSRegistrations(mDNS *const m); mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password, mDNSBool unicastOnly); mDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q); -mDNSlocal void mDNS_PurgeForQuestion(mDNS *const m, DNSQuestion *q); +mDNSlocal void mDNS_PurgeBeforeResolve(mDNS *const m, DNSQuestion *q); mDNSlocal void CheckForDNSSECRecords(mDNS *const m, DNSQuestion *q); mDNSlocal void mDNS_SendKeepalives(mDNS *const m); mDNSlocal void mDNS_ExtractKeepaliveInfo(AuthRecord *ar, mDNSu32 *timeout, mDNSAddr *laddr, mDNSAddr *raddr, mDNSEthAddr *eth, @@ -548,6 +548,7 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re // because mDNS_StartQuery_internal re-initializes CNAMEReferrals to zero q->CNAMEReferrals = c; #if AWD_METRICS + metrics.expiredAnswerState = q->metrics.expiredAnswerState; // We want the newly initialized state for this value q->metrics = metrics; #endif if (sock) @@ -785,6 +786,7 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec #define GoodbyeCount ((mDNSu8)3) #define WakeupCount ((mDNSu8)18) #define MAX_PROBE_RESTARTS ((mDNSu8)20) +#define MAX_GHOST_TIME ((mDNSs32)((60*60*24*7)*mDNSPlatformOneSecond)) // One week // Number of wakeups we send if WakeOnResolve is set in the question #define InitialWakeOnResolveCount ((mDNSu8)3) @@ -2176,7 +2178,7 @@ mDNSexport void CompleteDeregistration(mDNS *const m, AuthRecord *rr) rr->resrec.RecordType = kDNSRecordTypeShared; rr->RequireGoodbye = mDNSfalse; rr->WakeUp.HMAC = zeroEthAddr; - if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; } + if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, QC_rmv); rr->AnsweredLocalQ = mDNSfalse; } mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); // Don't touch rr after this } @@ -2364,7 +2366,11 @@ mDNSlocal void SendNDP(mDNS *const m, const mDNSu8 op, const mDNSu8 flags, const // *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]; + for (i=0; i<6; i++) + if (tha) + *ptr++ = tha->b[i]; + else + *ptr++ = intf->MAC.b[i]; // 0x0C IPv6 Ethertype (0x86DD) *ptr++ = 0x86; *ptr++ = 0xDD; @@ -2401,7 +2407,11 @@ mDNSlocal void SendNDP(mDNS *const m, const mDNSu8 op, const mDNSu8 flags, const { *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]; + for (i=0; i<6; i++) + if (tha) + *ptr++ = tha->b[i]; + else + *ptr++ = intf->MAC.b[i]; } } else // Neighbor Advertisement. The NDP "target" is the address we're giving information about. @@ -2411,7 +2421,11 @@ mDNSlocal void SendNDP(mDNS *const m, const mDNSu8 op, const mDNSu8 flags, const // 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]; + for (i=0; i<6; i++) + if (tha) + *ptr++ = tha->b[i]; + else + *ptr++ = intf->MAC.b[i]; } // 0x4E or 0x56 Total NDP Packet length 78 or 86 bytes @@ -3220,21 +3234,25 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, const NetworkInterfaceInfo *intf // Depth 3: PTR "_services._dns-sd._udp.local." refers to "_example._tcp.local."; may be stale // Currently depths 4 and 5 are not expected to occur; if we did get to depth 5 we'd reconfim any records we // found referring to the given name, but not recursively descend any further reconfirm *their* antecedents. -mDNSlocal void ReconfirmAntecedents(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const int depth) +mDNSlocal void ReconfirmAntecedents(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSInterfaceID InterfaceID, const int depth) { mDNSu32 slot; - CacheGroup *cg; + const CacheGroup *cg; CacheRecord *cr; debugf("ReconfirmAntecedents (depth=%d) for %##s", depth, name->c); + if (!InterfaceID) return; // mDNS records have a non-zero InterfaceID. If InterfaceID is 0, then there's nothing to do. FORALL_CACHERECORDS(slot, cg, cr) { - domainname *crtarget = GetRRDomainNameTarget(&cr->resrec); - if (crtarget && cr->resrec.rdatahash == namehash && SameDomainName(crtarget, name)) + const domainname *crtarget; + if (cr->resrec.InterfaceID != InterfaceID) continue; // Skip non-mDNS records and mDNS records from other interfaces. + if (cr->resrec.rdatahash != namehash) continue; // Skip records whose rdata hash doesn't match the name hash. + crtarget = GetRRDomainNameTarget(&cr->resrec); + if (crtarget && SameDomainName(crtarget, name)) { - LogInfo("ReconfirmAntecedents: Reconfirming (depth=%d) %s", depth, CRDisplayString(m, cr)); + LogInfo("ReconfirmAntecedents: Reconfirming (depth=%d, InterfaceID=%p) %s", depth, InterfaceID, CRDisplayString(m, cr)); mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); if (depth < 5) - ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, depth+1); + ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, InterfaceID, depth+1); } } } @@ -3612,7 +3630,8 @@ mDNSlocal void SendQueries(mDNS *const m) { q->ThisQInterval = MaxQuestionInterval; } - else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * QuestionIntervalStep3 && !q->RequestUnicast && + else if (mDNSOpaque16IsZero(q->TargetQID) && q->InterfaceID && + 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. @@ -3623,7 +3642,7 @@ mDNSlocal void SendQueries(mDNS *const m) 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); + ReconfirmAntecedents(m, &q->qname, q->qnamehash, q->InterfaceID, 0); } } @@ -4107,8 +4126,9 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco DNSQuestion *const q = m->CurrentQuestion; const mDNSBool followcname = FollowCNAME(q, &rr->resrec, AddRecord); - verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s", - q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, CRDisplayString(m, rr)); + verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s (%s) TTL %d %s", + q->CurrentAnswers, AddRecord ? "Add" : "Rmv", MortalityDisplayString(rr->resrec.mortality), + rr->resrec.rroriginalttl, CRDisplayString(m, rr)); // When the response for the question was validated, the entire rrset was validated. If we deliver // a RMV for a single record in the rrset, we invalidate the response. If we deliver another add @@ -4149,7 +4169,11 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco if (!q->TimeoutQuestion || rr->resrec.RecordType != kDNSRecordTypePacketNegative || (m->timenow - q->StopTime < 0)) return; } - + + // Set the record to immortal if appropriate + if (AddRecord == QC_add && Question_uDNS(q) && rr->resrec.RecordType != kDNSRecordTypePacketNegative && + q->allowExpired != AllowExpired_None && rr->resrec.mortality == Mortality_Mortal ) rr->resrec.mortality = Mortality_Immortal; // Update a non-expired cache record to immortal if appropriate + #if AWD_METRICS if ((AddRecord == QC_add) && Question_uDNS(q) && !followcname) { @@ -4170,12 +4194,12 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco responseLatencyMs = 0; } - MetricsUpdateUDNSQueryStats(queryName, q->qtype, &rr->resrec, q->metrics.querySendCount, responseLatencyMs, isForCellular); + MetricsUpdateDNSQueryStats(queryName, q->qtype, &rr->resrec, q->metrics.querySendCount, q->metrics.expiredAnswerState, responseLatencyMs, isForCellular); q->metrics.answered = mDNStrue; } if (q->metrics.querySendCount > 0) { - MetricsUpdateUDNSResolveStats(queryName, &rr->resrec, isForCellular); + MetricsUpdateDNSResolveStats(queryName, &rr->resrec, isForCellular); } } #endif @@ -4183,8 +4207,7 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco // may be called twice, once when the record is received, and again when it's time to notify local clients. // If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this. - rr->LastUsed = m->timenow; - if (AddRecord == QC_add && !q->DuplicateOf && rr->CRActiveQuestion != q) + if (AddRecord == QC_add && !q->DuplicateOf && rr->CRActiveQuestion != q && rr->resrec.mortality != Mortality_Ghost) { if (!rr->CRActiveQuestion) m->rrcache_active++; // If not previously active, increment rrcache_active count debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion from %p to %p for cache record %s, CurrentAnswer %d", @@ -4293,14 +4316,21 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco return; } - // Note: Proceed with caution here because client callback function is allowed to do anything, - // including starting/stopping queries, registering/deregistering records, etc. - // - // If we get a CNAME back while we are validating the response (i.e., CNAME for DS, DNSKEY, RRSIG), - // don't follow them. If it is a ValidationRequired question, wait for the CNAME to be validated - // first before following it - if ((m->CurrentQuestion == q) && followcname && !ValidatingQuestion(q)) - AnswerQuestionByFollowingCNAME(m, q, &rr->resrec); + if ((m->CurrentQuestion == q) && !ValidatingQuestion(q)) + { + // If we get a CNAME back while we are validating the response (i.e., CNAME for DS, DNSKEY, RRSIG), + // don't follow them. If it is a ValidationRequired question, wait for the CNAME to be validated + // first before following it + if (followcname) AnswerQuestionByFollowingCNAME(m, q, &rr->resrec); + + // If we are returning expired RRs, then remember the first expired qname we we can start the query again + if (rr->resrec.mortality == Mortality_Ghost && !q->firstExpiredQname.c[0] && (q->allowExpired == AllowExpired_AllowExpiredAnswers) && rr->resrec.RecordType != kDNSRecordTypePacketNegative) + { + debugf("AnswerCurrentQuestionWithResourceRecord: Keeping track of domain for expired RR %s for question %p", CRDisplayString(m,rr), q); + // Note: question->qname is already changed at this point if following a CNAME + AssignDomainName(&q->firstExpiredQname, rr->resrec.name); // Update firstExpiredQname + } + } } mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr) @@ -4321,56 +4351,17 @@ mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr) m->CurrentQuestion = mDNSNULL; } -mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *const name, const mDNSu32 namehash, mDNSBool *purge) +mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *const name, const mDNSu32 namehash) { - const mDNSs32 threshhold = m->timenow + mDNSPlatformOneSecond; // See if there are any records expiring within one second + const mDNSs32 threshold = m->timenow + mDNSPlatformOneSecond; // See if there are any records expiring within one second const mDNSs32 start = m->timenow - 0x10000000; mDNSs32 delay = start; CacheGroup *cg = CacheGroupForName(m, namehash, name); const CacheRecord *rr; - if (purge) - *purge = mDNSfalse; for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) { - // If there are records that will expire soon, there are cases that need delayed - // delivery of events: - // - // 1) A new cache entry is about to be added as a replacement. The caller needs to - // deliver a RMV (for the current old entry) followed by ADD (for the new entry). - // It needs to schedule the timer for the next cache expiry (ScheduleNextCacheCheckTime), - // so that the cache entry can be purged (purging causes the RMV followed by ADD) - // - // 2) A new question is about to be answered and the caller needs to know whether it's - // scheduling should be delayed so that the question is not answered with this record. - // Instead of delivering an ADD (old entry) followed by RMV (old entry) and another ADD - // (new entry), a single ADD can be delivered by delaying the scheduling of the question - // immediately. - // - // When the unicast cache record is created, it's TTL has been extended beyond its value - // given in the resource record (See RRAdjustTTL). If it is in the "extended" time, the - // cache is already expired and we set "purge" to indicate that. When "purge" is set, the - // return value of the function should be ignored by the callers. - // - // Note: For case (1), "purge" argument is NULL and hence the following checks are skipped. - // It is okay to skip in that case because the cache records have been set to expire almost - // immediately and the extended time does not apply. - // - // Also, if there is already an active question we don't try to optimize as purging the cache - // would end up delivering RMV for the active question and hence we avoid that. - - if (purge && !rr->resrec.InterfaceID && !rr->CRActiveQuestion && rr->resrec.rroriginalttl) - { - mDNSu32 uTTL = RRUnadjustedTTL(rr->resrec.rroriginalttl); - if (m->timenow - (rr->TimeRcvd + ((mDNSs32)uTTL * mDNSPlatformOneSecond)) >= 0) - { - LogInfo("CheckForSoonToExpireRecords: %s: rroriginalttl %u, unadjustedTTL %u, currentTTL %u", - CRDisplayString(m, rr), rr->resrec.rroriginalttl, uTTL, (m->timenow - rr->TimeRcvd)/mDNSPlatformOneSecond); - *purge = mDNStrue; - continue; - } - } - if (threshhold - RRExpireTime(rr) >= 0) // If we have records about to expire within a second + if (threshold - RRExpireTime(rr) >= 0) // If we have records about to expire within a second { if (delay - RRExpireTime(rr) < 0) // then delay until after they've been deleted delay = RRExpireTime(rr); @@ -4400,6 +4391,7 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr) { if (ResourceRecordAnswersQuestion(&rr->resrec, q)) { + mDNSIPPort zp = zeroIPPort; // If this question is one that's actively sending queries, and it's received ten answers within one // second of sending the last query packet, then that indicates some radical network topology change, // so reset its exponential backoff back to the start. We must be at least at the eight-second interval @@ -4422,7 +4414,7 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr) 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); + rr->resrec.rDNSServer->port : zp), q); q->CurrentAnswers++; q->unansweredQueries = 0; @@ -4513,16 +4505,19 @@ mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr) // 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)) + if (!QuerySuppressed(q) && ResourceRecordAnswersQuestion(&rr->resrec, q) && + (q->allowExpired == AllowExpired_None || rr->resrec.mortality == Mortality_Mortal)) { verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr)); q->FlappingInterface1 = mDNSNULL; q->FlappingInterface2 = mDNSNULL; - if (q->CurrentAnswers == 0) + if (q->CurrentAnswers == 0) { + mDNSIPPort zp = zeroIPPort; 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)); + mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zp)); + } else { q->CurrentAnswers--; @@ -4542,11 +4537,11 @@ mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr) } if (rr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results { - if (q->CurrentAnswers == 0) + if ((q->CurrentAnswers == 0) && mDNSOpaque16IsZero(q->TargetQID)) { LogInfo("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents", q->qname.c, DNSTypeName(q->qtype)); - ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0); + ReconfirmAntecedents(m, &q->qname, q->qnamehash, rr->resrec.InterfaceID, 0); } AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv); } @@ -4670,16 +4665,15 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGrou while (*rp) { CacheRecord *const rr = *rp; + mDNSBool recordReleased = mDNSfalse; mDNSs32 event = RRExpireTime(rr); if (m->timenow - event >= 0) // If expired, delete it { - *rp = rr->next; // Cut it from the list - - 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; + verbosedebugf("CheckCacheExpiration: Removing%7d %7d %p %s", + m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr)); // 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 @@ -4696,9 +4690,30 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGrou CacheRecordRmv(m, rr); m->rrcache_active--; } - ReleaseCacheRecord(m, rr); + + event += MAX_GHOST_TIME; // Adjust so we can check for a ghost expiration + if (rr->resrec.mortality == Mortality_Mortal || // Normal expired mortal record that needs released + (rr->resrec.mortality == Mortality_Ghost && m->timenow - event >= 0)) // A ghost record that expired more than MAX_GHOST_TIME ago + { // Release as normal + *rp = rr->next; // Cut it from the list before ReleaseCacheRecord + verbosedebugf("CheckCacheExpiration: Deleting (%s)%7d %7d %p %s", + MortalityDisplayString(rr->resrec.mortality), + m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr)); + ReleaseCacheRecord(m, rr); + recordReleased = mDNStrue; + } + else // An immortal record needs to become a ghost when it expires + { // Don't release this entry + if (rr->resrec.mortality == Mortality_Immortal) + { + rr->resrec.mortality = Mortality_Ghost; // Expired immortal records become ghosts + verbosedebugf("CheckCacheExpiration: NOT Deleting (%s)%7d %7d %p %s", + MortalityDisplayString(rr->resrec.mortality), + m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr)); + } + } } - else // else, not expired; see if we need to query + 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) @@ -4721,6 +4736,10 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGrou } } } + } + + if (!recordReleased) // Schedule if we did not release the record + { verbosedebugf("CheckCacheExpiration:%6d %5d %s", (event - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr)); if (m->rrcache_nextcheck[slot] - event > 0) @@ -4774,7 +4793,7 @@ mDNSlocal mDNSBool AnswerQuestionWithLORecord(mDNS *const m, DNSQuestion *q, mDN m->CurrentRecord = mDNSNULL; return mDNStrue; } - AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue); + AnswerLocalQuestionWithLocalAuthRecord(m, rr, QC_add); if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here } @@ -4932,12 +4951,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m) { // SecsSinceRcvd is whole number of elapsed seconds, rounded down mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond; - if (rr->resrec.rroriginalttl <= SecsSinceRcvd) - { - LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %s %d %d", - rr->resrec.rroriginalttl, SecsSinceRcvd, CRDisplayString(m, rr), m->timenow, rr->TimeRcvd); - continue; // Go to next one in loop - } + if (rr->resrec.rroriginalttl <= SecsSinceRcvd && q->allowExpired != AllowExpired_AllowExpiredAnswers) continue; // Go to next one in loop // If this record set is marked unique, then that means we can reasonably assume we have the whole set // -- we don't need to rush out on the network and query immediately to see if there are more answers out there @@ -4947,6 +4961,9 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m) if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++; if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++; AnsweredFromCache = mDNStrue; +#if AWD_METRICS + if (q->metrics.expiredAnswerState == ExpiredAnswer_Allowed) q->metrics.expiredAnswerState = ExpiredAnswer_AnsweredWithExpired; +#endif AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here } @@ -4969,6 +4986,21 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m) if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving negative answer"); goto exit; } + if (q->allowExpired == AllowExpired_AllowExpiredAnswers) + { + q->allowExpired = AllowExpired_MakeAnswersImmortal; // After looking through the cache for an answer, demote to make immortal + if (q->firstExpiredQname.c[0]) // If an original query name was saved on an expired answer, start it over in case it is updated + { + LogMsg("AnswerNewQuestion: Restarting original question %p firstExpiredQname %##s for allowExpiredAnswers question", q, &q->firstExpiredQname.c); + mDNS_StopQuery_internal(m, q); // Stop old query + AssignDomainName(&q->qname, &q->firstExpiredQname); // Update qname + q->qnamehash = DomainNameHashValue(&q->qname); // and namehash + mDNS_StartQuery_internal(m, q); // start new query + q->CNAMEReferrals = 0; // Reset referral count + q->firstExpiredQname.c[0] = 0; // Erase the domain name + } + } + // Note: When a query gets suppressed or retried with search domains, we de-activate the question. // Hence we don't execute the following block of code for those cases. if (ShouldQueryImmediately && ActiveQuestion(q)) @@ -5270,7 +5302,7 @@ mDNSlocal void CheckRmvEventsForLocalRecords(mDNS *const m) { debugf("CheckRmvEventsForLocalRecords: Generating local RMV events for %s", ARDisplayString(m, rr)); rr->resrec.RecordType = kDNSRecordTypeShared; - AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); + AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, QC_rmv); if (m->CurrentRecord == rr) // If rr still exists in list, restore its state now { rr->resrec.RecordType = kDNSRecordTypeDeregistering; @@ -5481,7 +5513,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) if (LocalRecordReady(rr)) { debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr)); - AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue); + AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, QC_add); } else if (!rr->next) { @@ -5538,7 +5570,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) if (LocalRecordReady(rr)) { debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr)); - AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue); + AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, QC_add); } else LogMsg("mDNS_Execute: LocalOnlyRecord %s not ready", ARDisplayString(m, rr)); } @@ -6075,7 +6107,7 @@ mDNSexport mStatus UpdateKeepaliveRData(mDNS *const m, AuthRecord *rr, NetworkIn } if ((intf != mDNSNULL) && (mti.IntfId != intf->InterfaceID)) { - LogInfo("mDNSPlatformRetrieveTCPInfo: InterfaceID mismatch mti.IntfId = %p InterfaceID = %p", mti.IntfId, intf->InterfaceID); + LogInfo("mDNSPlatformRetrieveTCPInfo: InterfaceID mismatch mti.IntfId = %p InterfaceID = %p", mti.IntfId, intf->InterfaceID); return mStatus_BadParamErr; } @@ -6644,6 +6676,7 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m) NetworkInterfaceInfo *intf; for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) { + mDNSBool skipFullSleepProxyRegistration = mDNSfalse; // Intialize it to false. These values make sense only when SleepState is set to Sleeping. intf->SendGoodbyes = 0; @@ -6670,18 +6703,21 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m) continue; } - // Check if we have already registered with a sleep proxy for this subnet + // Check if we have already registered with a sleep proxy for this subnet. + // If so, then the subsequent in-NIC sleep proxy registration is limited to any keepalive records that belong + // to the interface. if (skipSameSubnetRegistration(m, registeredIntfIDS, registeredCount, intf->InterfaceID)) { - LogSPS("%s : Skipping sleep proxy registration on %s", __func__, intf->ifname); - continue; + LogSPS("%s : Skipping full sleep proxy registration on %s", __func__, intf->ifname); + skipFullSleepProxyRegistration = mDNStrue; } #if APPLE_OSX_mDNSResponder - else if (SupportsInNICProxy(intf)) + if (SupportsInNICProxy(intf)) { mDNSBool keepaliveOnly = mDNSfalse; - if (ActivateLocalProxy(intf, &keepaliveOnly) == mStatus_NoError) + const mStatus err = ActivateLocalProxy(intf, skipFullSleepProxyRegistration, &keepaliveOnly); + if (!skipFullSleepProxyRegistration && !err) { SendGoodbyesForWakeOnlyService(m, &WakeOnlyService); @@ -6699,9 +6735,10 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m) registeredIntfIDS[registeredCount] = intf->InterfaceID; registeredCount++; } + continue; } #endif // APPLE_OSX_mDNSResponder - else + if (!skipFullSleepProxyRegistration) { #if APPLE_OSX_mDNSResponder // If on battery, do not attempt to offload to external sleep proxies @@ -6827,7 +6864,13 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep) #endif mDNS_ReclaimLockAfterCallback(); } - +#ifdef _LEGACY_NAT_TRAVERSAL_ + if (m->SSDPSocket) + { + mDNSPlatformUDPClose(m->SSDPSocket); + m->SSDPSocket = mDNSNULL; + } +#endif m->SleepState = SleepState_Transferring; if (m->SystemWakeOnLANEnabled && m->DelaySleep) { @@ -7148,7 +7191,7 @@ mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const m const mDNSu8 *const limit = response->data + sizeof(response->data); const mDNSu8 *ptr = query->data; AuthRecord *rr; - mDNSu32 maxttl = 0x70000000; + mDNSu32 maxttl = mDNSMaximumTTLSeconds; int i; // Initialize the response fields so we can answer the questions @@ -7500,6 +7543,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con AuthRecord **nrp = &ResponseRecords; #if POOF_ENABLED + mDNSBool notD2D = !mDNSPlatformInterfaceIsD2D(InterfaceID); // We don't run the POOF algorithm on D2D interfaces. CacheRecord *ExpectedAnswers = mDNSNULL; // Records in our cache we expect to see updated CacheRecord **eap = &ExpectedAnswers; #endif // POOF_ENABLED @@ -7659,18 +7703,21 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con if (QuestionNeedsMulticastResponse && !(query->h.flags.b[0] & kDNSFlag0_TC)) { #if POOF_ENABLED - CacheGroup *cg = CacheGroupForName(m, pktq.qnamehash, &pktq.qname); - CacheRecord *cr; - - // Make a list indicating which of our own cache records we expect to see updated as a result of this query - // Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated - for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) - if (SameNameRecordAnswersQuestion(&cr->resrec, &pktq) && cr->resrec.rdlength <= SmallRecordLimit) - if (!cr->NextInKAList && eap != &cr->NextInKAList) - { - *eap = cr; - eap = &cr->NextInKAList; - } + if (notD2D) + { + CacheGroup *cg = CacheGroupForName(m, pktq.qnamehash, &pktq.qname); + CacheRecord *cr; + + // Make a list indicating which of our own cache records we expect to see updated as a result of this query + // Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated + for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) + if (SameNameRecordAnswersQuestion(&cr->resrec, &pktq) && cr->resrec.rdlength <= SmallRecordLimit) + if (!cr->NextInKAList && eap != &cr->NextInKAList) + { + *eap = cr; + eap = &cr->NextInKAList; + } + } #endif // POOF_ENABLED // Check if this question is the same as any of mine. @@ -7761,15 +7808,18 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec); #if POOF_ENABLED - // 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) + if (notD2D) { - 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; + // 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; + } } #endif // POOF_ENABLED @@ -7933,7 +7983,7 @@ exit: } #if POOF_ENABLED - while (ExpectedAnswers) + while (ExpectedAnswers && notD2D) { CacheRecord *cr = ExpectedAnswers; ExpectedAnswers = cr->NextInKAList; @@ -8045,19 +8095,25 @@ 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, mDNSBool tcp) +mDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSIPPort port, const mDNSOpaque16 id, const DNSQuestion *const question, mDNSBool tcp, DNSQuestion ** suspiciousQ) { DNSQuestion *q; for (q = m->Questions; q; q=q->next) { if (!tcp && !q->LocalSocket) continue; - if (mDNSSameIPPort(tcp ? q->tcpSrcPort : q->LocalSocket->port, port) && - mDNSSameOpaque16(q->TargetQID, id) && + if (mDNSSameIPPort(tcp ? q->tcpSrcPort : q->LocalSocket->port, port) && q->qtype == question->qtype && q->qclass == question->qclass && q->qnamehash == question->qnamehash && SameDomainName(&q->qname, &question->qname)) - return(q); + { + if (mDNSSameOpaque16(q->TargetQID, id)) return(q); + else + { + if (!tcp && suspiciousQ) *suspiciousQ = q; + return(mDNSNULL); + } + } } return(mDNSNULL); } @@ -8084,7 +8140,10 @@ mDNSlocal DNSQuestion *ExpectingUnicastResponseForRecord(mDNS *const m, mDNSIPPort srcp; if (!tcp) { - srcp = q->LocalSocket ? q->LocalSocket->port : zeroIPPort; + if (q->LocalSocket) + srcp = q->LocalSocket->port; + else + srcp = zeroIPPort; } else { @@ -8139,10 +8198,11 @@ mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, C if (!rr) NoCacheAnswer(m, &m->rec.r); else { - 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 + 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.mortality = Mortality_Mortal; // We need to add the anonymous info before we call CacheRecordAdd so that // if it finds a matching question with this record, it bumps up the counters like @@ -8209,6 +8269,7 @@ mDNSlocal void RefreshCacheRecord(mDNS *const m, CacheRecord *rr, mDNSu32 ttl) rr->TimeRcvd = m->timenow; rr->resrec.rroriginalttl = ttl; rr->UnansweredQueries = 0; + if (rr->resrec.mortality != Mortality_Mortal) rr->resrec.mortality = Mortality_Immortal; SetNextCacheCheckTimeForRecord(m, rr); } @@ -8279,7 +8340,7 @@ mDNSlocal mDNSBool IsResponseAcceptable(mDNS *const m, const CacheRecord *crlist if (target && cr->resrec.rdatahash == rr->namehash && SameDomainName(target, rr->name)) { - LogInfo("IsResponseAcceptable: Found a matching entry for %##s in the CacheFlushRecords %s", rr->name->c, CRDisplayString(m, cr)); + LogDebug("IsResponseAcceptable: Found a matching entry for %##s in the CacheFlushRecords %s", rr->name->c, CRDisplayString(m, cr)); return (mDNStrue); } } @@ -8381,7 +8442,7 @@ mDNSlocal void mDNSCoreReceiveNoDNSSECAnswers(mDNS *const m, const DNSMessage *c DNSQuestion pktq; DNSQuestion *qptr = mDNSNULL; ptr = getQuestion(response, ptr, end, InterfaceID, &pktq); - if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &pktq, !dstaddr)) && + if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &pktq, !dstaddr, mDNSNULL)) && qptr->ValidatingResponse) { DNSQuestion *next, *q; @@ -8425,7 +8486,7 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage * DNSQuestion q; DNSQuestion *qptr = mDNSNULL; ptr = getQuestion(response, ptr, end, InterfaceID, &q); - if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr))) + if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr, mDNSNULL))) { CacheRecord *rr, *neg = mDNSNULL; CacheGroup *cg = CacheGroupForName(m, q.qnamehash, &q.qname); @@ -8777,6 +8838,12 @@ mDNSlocal CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessage DNSQuestion *q; m->mDNSStats.CacheRefreshed++; + + if (rr->resrec.mortality == Mortality_Ghost && unicastQuestion && (unicastQuestion->allowExpired != AllowExpired_AllowExpiredAnswers) && !rr->DelayDelivery) + { + rr->DelayDelivery = NonZeroTime(m->timenow); + debugf("mDNSCoreReceiveCacheCheck: Reset DelayDelivery for mortalityExpired EXP:%d RR %s", m->timenow - RRExpireTime(rr), CRDisplayString(m, rr)); + } if (rr->resrec.rroriginalttl == 0) debugf("uDNS rescuing %s", CRDisplayString(m, rr)); RefreshCacheRecord(m, rr, m->rec.r.resrec.rroriginalttl); @@ -8944,6 +9011,13 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,", response->h.numAdditionals, response->h.numAdditionals == 1 ? " " : "s", end - response->data, LLQType); +#if AWD_METRICS + if (mDNSSameIPPort(srcport, UnicastDNSPort)) + { + MetricsUpdateDNSResponseSize((mDNSu32)(end - (mDNSu8 *)response)); + } +#endif + // According to RFC 2181 <http://www.ietf.org/rfc/rfc2181.txt> // When a DNS client receives a reply with TC // set, it should ignore that response, and query again, using a @@ -8956,18 +9030,25 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, // abort our TCP connection, and not complete the operation, and end up with an incomplete RRSet in our cache. // Next time there's a query for this RRSet we'll see answers in our cache, and assume we have the whole RRSet already, // and not even do the TCP query. - // Accordingly, if we get a uDNS reply with kDNSFlag0_TC set, we bail out and wait for the TCP response containing the entire RRSet. - if (!InterfaceID && (response->h.flags.b[0] & kDNSFlag0_TC)) return; + // Accordingly, if we get a uDNS reply with kDNSFlag0_TC set, we bail out and wait for the TCP response containing the + // entire RRSet, with the following exception. If the response contains an answer section and one or more records in + // either the authority section or additional section, then that implies that truncation occurred beyond the answer + // section, and the answer section is therefore assumed to be complete. + // + // From section 6.2 of RFC 1035 <https://tools.ietf.org/html/rfc1035>: + // When a response is so long that truncation is required, the truncation + // should start at the end of the response and work forward in the + // datagram. Thus if there is any data for the authority section, the + // answer section is guaranteed to be unique. + if (!InterfaceID && (response->h.flags.b[0] & kDNSFlag0_TC) && + ((response->h.numAnswers == 0) || ((response->h.numAuthorities == 0) && (response->h.numAdditionals == 0)))) return; if (LLQType == uDNS_LLQ_Ignore) return; // 1. We ignore questions (if any) in mDNS response packets // 2. If this is an LLQ response, we handle it much the same - // 3. If we get a uDNS UDP response with the TC (truncated) bit set, then we can't treat this - // answer as being the authoritative complete RRSet, and respond by deleting all other - // matching cache records that don't appear in this packet. // Otherwise, this is a authoritative uDNS answer, so arrange for any stale records to be purged - if (ResponseMCast || LLQType == uDNS_LLQ_Events || (response->h.flags.b[0] & kDNSFlag0_TC)) + if (ResponseMCast || LLQType == uDNS_LLQ_Events) ptr = LocateAnswers(response, end); // Otherwise, for one-shot queries, any answers in our cache that are not also contained // in this response packet are immediately deemed to be invalid. @@ -8985,9 +9066,9 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, // packet number, then we deduce they are old and delete them for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++) { - DNSQuestion q, *qptr = mDNSNULL; + DNSQuestion q, *qptr = mDNSNULL, *suspiciousForQ = mDNSNULL; ptr = getQuestion(response, ptr, end, InterfaceID, &q); - if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr))) + if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr, &suspiciousForQ))) { if (!failure) { @@ -9050,6 +9131,15 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, returnEarly = mDNStrue; } } + else if (!InterfaceID && suspiciousForQ) + { + // If a response is suspicious for a question, then reissue the question via TCP + LogInfo("mDNSCoreReceiveResponse: Server %p responded suspiciously to query %##s (%s) qID %d != rID: %d", + suspiciousForQ->qDNSServer, q.qname.c, DNSTypeName(q.qtype), + mDNSVal16(suspiciousForQ->TargetQID), mDNSVal16(response->h.id)); + uDNS_RestartQuestionAsTCP(m, suspiciousForQ, srcaddr, srcport); + return; + } } if (returnEarly) { @@ -9184,6 +9274,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, { debugf("mDNSCoreReceiveResponse: InterfaceID %p %##s (%s)", q->InterfaceID, q->qname.c, DNSTypeName(q->qtype)); m->rec.r.resrec.rDNSServer = uDNSServer = q->qDNSServer; + if (!unicastQuestion) unicastQuestion = q; // Acceptable responses to unicast questions need to have (unicastQuestion != nil) } else { @@ -9413,7 +9504,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, if (AddToCFList) delay = NonZeroTime(m->timenow + mDNSPlatformOneSecond); else - delay = CheckForSoonToExpireRecords(m, m->rec.r.resrec.name, m->rec.r.resrec.namehash, mDNSNULL); + delay = CheckForSoonToExpireRecords(m, m->rec.r.resrec.name, m->rec.r.resrec.namehash); // If unique, assume we may have to delay delivery of this 'add' event. // Below, where we walk the CacheFlushRecords list, we either call CacheRecordDeferredAdd() @@ -9481,6 +9572,7 @@ exit: CacheRecord *r1 = CacheFlushRecords, *r2; const mDNSu32 slot = HashSlotFromNameHash(r1->resrec.namehash); const CacheGroup *cg = CacheGroupForRecord(m, &r1->resrec); + mDNSBool purgedRecords = mDNSfalse; CacheFlushRecords = CacheFlushRecords->NextInCFList; r1->NextInCFList = mDNSNULL; @@ -9531,6 +9623,12 @@ exit: r1->resrec.rrtype == r2->resrec.rrtype && r1->resrec.rrclass == r2->resrec.rrclass) { + if (r1->resrec.mortality == Mortality_Mortal && r2->resrec.mortality != Mortality_Mortal) + { + verbosedebugf("mDNSCoreReceiveResponse: R1(%p) is being immortalized by R2(%p)", r1, r2); + r1->resrec.mortality = Mortality_Immortal; // Immortalize the replacement record + } + // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics) // else, if record is old, mark it to be flushed if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond && RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond) @@ -9562,8 +9660,9 @@ exit: r2->resrec.rroriginalttl = r1->resrec.rroriginalttl; } r2->TimeRcvd = m->timenow; + SetNextCacheCheckTimeForRecord(m, r2); } - else // else, if record is old, mark it to be flushed + else if (r2->resrec.InterfaceID) // else, if record is old, mark it to be flushed { 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)); @@ -9601,8 +9700,30 @@ exit: // We use (m->timenow - 1) instead of m->timenow, because we use that to identify records // that we marked for deletion via an explicit DE record } + SetNextCacheCheckTimeForRecord(m, r2); + } + else + { +#if AWD_METRICS + if (r2->resrec.mortality == Mortality_Ghost) + { + DNSQuestion * q; + for (q = m->Questions; q; q=q->next) + { + if (!q->LongLived && ActiveQuestion(q) && + ResourceRecordAnswersQuestion(&r2->resrec, q) && + q->metrics.expiredAnswerState == ExpiredAnswer_AnsweredWithExpired) + { + q->metrics.expiredAnswerState = ExpiredAnswer_ExpiredAnswerChanged; + } + } + } +#endif + // Old uDNS records are scheduled to be purged instead of given at most one second to live. + r2->resrec.mortality = Mortality_Mortal; // We want it purged, so remove any immortality + mDNS_PurgeCacheResourceRecord(m, r2); + purgedRecords = mDNStrue; } - SetNextCacheCheckTimeForRecord(m, r2); } } @@ -9630,7 +9751,16 @@ exit: NSECRecords = mDNSNULL; NSECCachePtr = mDNSNULL; } - r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, mDNSNULL); + if (r1->resrec.InterfaceID) + { + r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash); + } + else + { + // If uDNS records from an older RRset were scheduled to be purged, then delay delivery slightly to allow + // them to be deleted before any ADD events for this record. + r1->DelayDelivery = purgedRecords ? NonZeroTime(m->timenow) : 0; + } // 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); @@ -9742,7 +9872,7 @@ mDNSlocal mDNSu8 *GetValueForMACAddr(mDNSu8 *ptr, mDNSu8 *limit, mDNSEthAddr *et int i; mDNSs8 hval = 0; int colons = 0; - mDNSu8 val = 0; + mDNSu16 val = 0; /* need to use 16 bit int to detect overflow */ for (i = 0; ptr < limit && *ptr != ' ' && i < 17; i++, ptr++) { @@ -9759,7 +9889,7 @@ mDNSlocal mDNSu8 *GetValueForMACAddr(mDNSu8 *ptr, mDNSu8 *limit, mDNSEthAddr *et LogMsg("GetValueForMACAddr: Address malformed colons %d val %d", colons, val); return mDNSNULL; } - eth->b[colons] = val; + eth->b[colons] = (mDNSs8)val; colons++; val = 0; } @@ -9769,7 +9899,7 @@ mDNSlocal mDNSu8 *GetValueForMACAddr(mDNSu8 *ptr, mDNSu8 *limit, mDNSEthAddr *et LogMsg("GetValueForMACAddr: Address malformed colons %d", colons); return mDNSNULL; } - eth->b[colons] = val; + eth->b[colons] = (mDNSs8)val; return ptr; } @@ -10209,7 +10339,7 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m, if (!InterfaceID || !m->SPSSocket || !mDNSSameIPPort(dstport, m->SPSSocket->port)) return; if (mDNS_PacketLoggingEnabled) - DumpPacket(m, mStatus_NoError, mDNSfalse, "UDP", srcaddr, srcport, dstaddr, dstport, msg, end); + DumpPacket(mStatus_NoError, mDNSfalse, "UDP", srcaddr, srcport, dstaddr, dstport, msg, end); ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space + DNSOpt_OwnerData_ID_Space); if (ptr) @@ -10468,7 +10598,6 @@ mDNSexport void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr, cr->TimeRcvd = m->timenow; cr->DelayDelivery = 0; cr->NextRequiredQuery = m->timenow; - cr->LastUsed = m->timenow; cr->CRActiveQuestion = mDNSNULL; cr->UnansweredQueries = 0; cr->LastUnansweredTime = 0; @@ -10563,7 +10692,7 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS { ifid = mDNSInterface_Any; if (mDNS_PacketLoggingEnabled) - DumpPacket(m, mStatus_NoError, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, dstaddr, dstport, msg, end); + DumpPacket(mStatus_NoError, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, dstaddr, dstport, msg, end); uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport); // Note: mDNSCore also needs to get access to received unicast responses } @@ -11128,11 +11257,11 @@ mDNSlocal DNSServer *GetServerForName(mDNS *m, const domainname *name, mDNSInter curmatch = GetBestServer(m, name, InterfaceID, ServiceID, 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, + LogInfo("GetServerForName: DNS server %#a:%d (Penalty Time Left %d) (Scope %s:%p) for %##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); + LogInfo("GetServerForName: no DNS server (Scope %s:%p) for %##s", ifname ? ifname : "None", InterfaceID, name); return(curmatch); } @@ -11161,14 +11290,14 @@ mDNSexport DNSServer *GetServerForQuestion(mDNS *m, DNSQuestion *question) if (curmatch != mDNSNULL) { - LogInfo("GetServerForQuestion: %p DNS server (%p) %#a:%d (Penalty Time Left %d) (Scope %s:%p:%d) found for name %##s (%s)", + LogInfo("GetServerForQuestion: %p DNS server (%p) %#a:%d (Penalty Time Left %d) (Scope %s:%p:%d) for %##s (%s)", question, curmatch, &curmatch->addr, mDNSVal16(curmatch->port), (curmatch->penaltyTime ? (curmatch->penaltyTime - m->timenow) : 0), ifname ? ifname : "None", InterfaceID, question->ServiceID, name, DNSTypeName(question->qtype)); } else { - LogInfo("GetServerForQuestion: %p no DNS server (Scope %s:%p:%d) found for name %##s (%s)", + LogInfo("GetServerForQuestion: %p no DNS server (Scope %s:%p:%d) for %##s (%s)", question, ifname ? ifname : "None", InterfaceID, question->ServiceID, name, DNSTypeName(question->qtype)); } @@ -11212,6 +11341,8 @@ mDNSlocal mDNSBool IsPrivateDomain(mDNS *const m, DNSQuestion *q) } } +#define TrueFalseStr(X) ((X) ? "true" : "false") + // This function takes the DNSServer as a separate argument because sometimes the // caller has not yet assigned the DNSServer, but wants to evaluate the SuppressQuery // status before switching to it. @@ -11220,14 +11351,14 @@ mDNSlocal mDNSBool ShouldSuppressUnicastQuery(mDNS *const m, DNSQuestion *q, DNS // Some callers don't check for the qtype if (q->qtype != kDNSType_A && q->qtype != kDNSType_AAAA) { - LogInfo("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, not A/AAAA type", q->qname.c, DNSTypeName(q->qtype)); + LogDebug("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, not A/AAAA type", q->qname.c, DNSTypeName(q->qtype)); return mDNSfalse; } // Private domains are exempted irrespective of what the DNSServer says if (IsPrivateDomain(m, q)) { - LogInfo("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, Private Domain", q->qname.c, DNSTypeName(q->qtype)); + LogDebug("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, Private Domain", q->qname.c, DNSTypeName(q->qtype)); return mDNSfalse; } @@ -11238,28 +11369,35 @@ mDNSlocal mDNSBool ShouldSuppressUnicastQuery(mDNS *const m, DNSQuestion *q, DNS } // Check if the DNS Configuration allows A/AAAA queries to be sent - if ((q->qtype == kDNSType_A) && (d->req_A)) + if ((q->qtype == kDNSType_A) && d->req_A) { - LogInfo("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, DNSServer %##s %#a:%d allows A queries", q->qname.c, - DNSTypeName(q->qtype), d->domain.c, &d->addr, mDNSVal16(d->port)); - return mDNSfalse; + // The server's configuration allows A record queries, so don't suppress this query unless + // 1. the interface associated with the server is CLAT46; and + // 2. the query has the kDNSServiceFlagsPathEvaluationDone flag, which indicates that it came from libnetcore. + // See <rdar://problem/42672030> for more info. + if (!(d->isCLAT46 && (q->flags & kDNSServiceFlagsPathEvaluationDone))) + { + LogDebug("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, DNSServer %##s %#a:%d allows A queries", q->qname.c, + DNSTypeName(q->qtype), d->domain.c, &d->addr, mDNSVal16(d->port)); + return mDNSfalse; + } } - if ((q->qtype == kDNSType_AAAA) && (d->req_AAAA)) + if ((q->qtype == kDNSType_AAAA) && d->req_AAAA) { - LogInfo("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, DNSServer %##s %#a:%d allows AAAA queries", q->qname.c, + LogDebug("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, DNSServer %##s %#a:%d allows AAAA queries", q->qname.c, DNSTypeName(q->qtype), d->domain.c, &d->addr, mDNSVal16(d->port)); return mDNSfalse; } #if USE_DNS64 if (DNS64IsQueryingARecord(q->dns64.state)) { - LogInfo("ShouldSuppressUnicastQuery: DNS64 query not suppressed for %##s, qtype %s", q->qname.c, DNSTypeName(q->qtype)); + LogDebug("ShouldSuppressUnicastQuery: DNS64 query not suppressed for %##s, qtype %s", q->qname.c, DNSTypeName(q->qtype)); return mDNSfalse; } #endif - LogInfo("ShouldSuppressUnicastQuery: Query suppressed for %##s, qtype %s, since DNS Configuration does not allow (req_A is %s and req_AAAA is %s)", - q->qname.c, DNSTypeName(q->qtype), d->req_A ? "true" : "false", d->req_AAAA ? "true" : "false"); + LogInfo("ShouldSuppressUnicastQuery: Query suppressed for %##s, qtype %s, since DNS Configuration does not allow (req_A %s, req_AAAA %s, CLAT46 %s)", + q->qname.c, DNSTypeName(q->qtype), TrueFalseStr(d->req_A), TrueFalseStr(d->req_AAAA), TrueFalseStr(d->isCLAT46)); return mDNStrue; } @@ -11642,8 +11780,8 @@ mDNSlocal mStatus ValidateParameters(mDNS *const m, DNSQuestion *const question) return(mStatus_NoError); } -// InitDNSConfig() is called by InitCommonState() to initialize the DNS configuration of the Question. -// These are a subset of the internal uDNS fields. Must be done before ShouldSuppressQuery() & mDNS_PurgeForQuestion() +// InitDNSConfig() is called by InitCommonState() to initialize the DNS configuration of the Question. +// These are a subset of the internal uDNS fields. Must be done before ShouldSuppressQuery() & mDNS_PurgeBeforeResolve() mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question) { // First reset all DNS Configuration @@ -11654,6 +11792,7 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question) question->StopTime = (question->TimeoutQuestion) ? question->StopTime : 0; #if AWD_METRICS mDNSPlatformMemZero(&question->metrics, sizeof(question->metrics)); + question->metrics.expiredAnswerState = (question->allowExpired != AllowExpired_None) ? ExpiredAnswer_Allowed : ExpiredAnswer_None; #endif // Need not initialize the DNS Configuration for Local Only OR P2P Questions when timeout not specified @@ -11674,7 +11813,7 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question) } question->qDNSServer = GetServerForQuestion(m, question); - LogInfo("InitDNSConfig: question %p %##s (%s) Timeout %d, DNS Server %#a:%d", + LogDebug("InitDNSConfig: question %p %##s (%s) Timeout %d, DNS Server %#a:%d", question, question->qname.c, DNSTypeName(question->qtype), timeout, question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL, mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort)); @@ -11699,9 +11838,8 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question) // InitCommonState() is called by mDNS_StartQuery_internal() to initialize the common(uDNS/mDNS) internal // state fields of the DNS Question. These are independent of the Client layer. -mDNSlocal mDNSBool InitCommonState(mDNS *const m, DNSQuestion *const question) +mDNSlocal void InitCommonState(mDNS *const m, DNSQuestion *const question) { - mDNSBool purge; int i; mDNSBool isBlocked = mDNSfalse; @@ -11720,7 +11858,7 @@ mDNSlocal mDNSBool InitCommonState(mDNS *const m, DNSQuestion *const question) // turned ON which can allocate memory e.g., base64 encoding, in the case of DNSSEC. question->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question question->qnamehash = DomainNameHashValue(&question->qname); - question->DelayAnswering = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, &purge); + question->DelayAnswering = mDNSOpaque16IsZero(question->TargetQID) ? CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash) : 0; question->LastQTime = m->timenow; question->ExpectUnicastResp = 0; question->LastAnswerPktNum = m->PktNum; @@ -11802,7 +11940,6 @@ mDNSlocal mDNSBool InitCommonState(mDNS *const m, DNSQuestion *const question) if (question->WakeOnResolve) { question->WakeOnResolveCount = InitialWakeOnResolveCount; - purge = mDNStrue; } for (i=0; i<DupSuppressInfoSize; i++) @@ -11819,8 +11956,6 @@ mDNSlocal mDNSBool InitCommonState(mDNS *const m, DNSQuestion *const question) if (question->DelayAnswering) LogInfo("InitCommonState: Delaying answering for %d ticks while cache stabilizes for %##s (%s)", question->DelayAnswering - m->timenow, question->qname.c, DNSTypeName(question->qtype)); - - return(purge); } // Excludes the DNS Config fields which are already handled by InitDNSConfig() @@ -11902,7 +12037,7 @@ mDNSlocal void InitDNSSECProxyState(mDNS *const m, DNSQuestion *const question) // Once the question is completely initialized including the duplicate logic, this function // is called to finalize the unicast question which requires flushing the cache if needed, // activating the query etc. -mDNSlocal void FinalizeUnicastQuestion(mDNS *const m, DNSQuestion *question, mDNSBool purge) +mDNSlocal void FinalizeUnicastQuestion(mDNS *const m, DNSQuestion *question) { // Ensure DNS related info of duplicate question is same as the orig question if (question->DuplicateOf) @@ -11927,14 +12062,7 @@ mDNSlocal void FinalizeUnicastQuestion(mDNS *const m, DNSQuestion *question, mDN ActivateUnicastQuery(m, question, mDNSfalse); - // If purge was set above, flush the cache. Need to do this after we set the - // DNS server on the question - if (purge) - { - question->DelayAnswering = 0; - mDNS_PurgeForQuestion(m, question); - } - else if (!question->DuplicateOf && DNSSECQuestion(question)) + if (!question->DuplicateOf && DNSSECQuestion(question)) { // For DNSSEC questions, we need to have the RRSIGs also for verification. CheckForDNSSECRecords(m, question); @@ -11957,7 +12085,6 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu { DNSQuestion **q; mStatus vStatus; - mDNSBool purge; // First check for cache space (can't do queries if there is no cache space allocated) if (m->rrcache_size == 0) @@ -12005,7 +12132,7 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu // InitCommonState -> InitDNSConfig) as DNS server selection affects DNSSEC // validation. - purge = InitCommonState(m, question); + InitCommonState(m, question); InitWABState(question); InitLLQState(question); #ifdef DNS_PUSH_ENABLED @@ -12038,7 +12165,7 @@ 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)) { - FinalizeUnicastQuestion(m, question, purge); + FinalizeUnicastQuestion(m, question); } else { @@ -12058,10 +12185,10 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu } } #endif // BONJOUR_ON_DEMAND - if (purge) + if (question->WakeOnResolve) { LogInfo("mDNS_StartQuery_internal: Purging for %##s", question->qname.c); - mDNS_PurgeForQuestion(m, question); + mDNS_PurgeBeforeResolve(m, question); } } } @@ -12127,7 +12254,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que queryName = question->metrics.originalQName ? question->metrics.originalQName : &question->qname; isForCell = (question->qDNSServer && question->qDNSServer->cellIntf); durationMs = ((m->timenow - question->metrics.firstQueryTime) * 1000) / mDNSPlatformOneSecond; - MetricsUpdateUDNSQueryStats(queryName, question->qtype, mDNSNULL, question->metrics.querySendCount, durationMs, isForCell); + MetricsUpdateDNSQueryStats(queryName, question->qtype, mDNSNULL, question->metrics.querySendCount, question->metrics.expiredAnswerState, durationMs, isForCell); } #endif // Take care to cut question from list *before* calling UpdateQuestionDuplicates @@ -12335,7 +12462,7 @@ mDNSexport mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const q { // Don't use mDNS_DropLockBeforeCallback() here, since we don't allow API calls if (question->QuestionCallback) - question->QuestionCallback(m, question, &rr->resrec, mDNSfalse); + question->QuestionCallback(m, question, &rr->resrec, QC_rmv); } } mDNS_Unlock(m); @@ -12347,7 +12474,7 @@ mDNSexport mStatus mDNS_Reconfirm(mDNS *const m, CacheRecord *const cr) mStatus status; mDNS_Lock(m); status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); - if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0); + if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, cr->resrec.InterfaceID, 0); mDNS_Unlock(m); return(status); } @@ -12360,7 +12487,7 @@ mDNSexport mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr cr = FindIdenticalRecordInCache(m, rr); debugf("mDNS_ReconfirmByValue: %p %s", cr, RRDisplayString(m, rr)); if (cr) status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); - if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0); + if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, cr->resrec.InterfaceID, 0); mDNS_Unlock(m); return(status); } @@ -12876,7 +13003,7 @@ mDNSexport void mDNS_DeactivateNetWake_internal(mDNS *const m, NetworkInterfaceI if (m->SPSBrowseCallback) { mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback - m->SPSBrowseCallback(m, &set->NetWakeBrowse, mDNSNULL, mDNSfalse); + m->SPSBrowseCallback(m, &set->NetWakeBrowse, mDNSNULL, QC_rmv); mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again } @@ -13166,6 +13293,7 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se } else { + rr->resrec.mortality = Mortality_Mortal; mDNS_PurgeCacheResourceRecord(m, rr); } } @@ -13363,7 +13491,7 @@ mDNSexport mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType) // If the optional target host parameter is set, then the storage it points to must remain valid for the lifetime of the service registration mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, const domainlabel *const name, const domainname *const type, const domainname *const domain, - const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen, + const domainname *const host, mDNSIPPort port, RData *const txtrdata, const mDNSu8 txtinfo[], mDNSu16 txtlen, AuthRecord *SubTypes, mDNSu32 NumSubTypes, mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context, mDNSu32 flags) { @@ -13400,7 +13528,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, hostTTL = kHostNameTTL; mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, hostTTL, recordType, artype, ServiceCallback, sr); - mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, recordType, artype, ServiceCallback, sr); + mDNS_SetupResourceRecord(&sr->RR_TXT, txtrdata, InterfaceID, kDNSType_TXT, kStandardTTL, recordType, artype, ServiceCallback, sr); // If port number is zero, that means the client is really trying to do a RegisterNoSuchService if (mDNSIPPortIsZero(port)) @@ -13610,7 +13738,9 @@ mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordS else debugf("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type.c, domain.c, name1.c, newname->c); err = mDNS_RegisterService(m, sr, newname, &type, &domain, - host, sr->RR_SRV.resrec.rdata->u.srv.port, sr->RR_TXT.resrec.rdata->u.txt.c, sr->RR_TXT.resrec.rdlength, + host, sr->RR_SRV.resrec.rdata->u.srv.port, + (sr->RR_TXT.resrec.rdata != &sr->RR_TXT.rdatastorage) ? sr->RR_TXT.resrec.rdata : mDNSNULL, + sr->RR_TXT.resrec.rdata->u.txt.c, sr->RR_TXT.resrec.rdlength, sr->SubTypes, sr->NumSubTypes, sr->RR_PTR.resrec.InterfaceID, sr->ServiceCallback, sr->ServiceContext, sr->flags); @@ -13846,7 +13976,9 @@ mDNSlocal void mDNSCoreReceiveRawARP(mDNS *const m, const ARP_EthIP *const arp, } else if (msg == msg4) { - SendARP(m, 2, rr, (mDNSv4Addr *)arp->tpa.b, &arp->sha, (mDNSv4Addr *)arp->spa.b, &arp->sha); + mDNSv4Addr tpa = arp->tpa; + mDNSv4Addr spa = arp->spa; + SendARP(m, 2, rr, &tpa, &arp->sha, &spa, &arp->sha); } } } @@ -14249,6 +14381,7 @@ mDNSlocal void SleepProxyServerCallback(mDNS *const m, ServiceRecordSet *const s mDNS_RegisterService(m, srs, &name, &SleepProxyServiceType, &localdomain, mDNSNULL, m->SPSSocket->port, // Host, port + mDNSNULL, (mDNSu8 *)"", 1, // TXT data, length mDNSNULL, 0, // Subtypes (none) mDNSInterface_Any, // Interface ID @@ -14611,7 +14744,7 @@ mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const } } -mDNSlocal void mDNS_PurgeForQuestion(mDNS *const m, DNSQuestion *q) +mDNSlocal void mDNS_PurgeBeforeResolve(mDNS *const m, DNSQuestion *q) { CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname); CacheRecord *rp; @@ -14627,7 +14760,7 @@ mDNSlocal void mDNS_PurgeForQuestion(mDNS *const m, DNSQuestion *q) { if (SameNameRecordAnswersQuestion(&rp->resrec, q)) { - LogInfo("mDNS_PurgeForQuestion: Flushing %s", CRDisplayString(m, rp)); + LogInfo("mDNS_PurgeBeforeResolve: Flushing %s", CRDisplayString(m, rp)); mDNS_PurgeCacheResourceRecord(m, rp); } } @@ -14867,10 +15000,21 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) if (t != s) { mDNSBool old, new; + mDNSIPPort tport, sport; + + if (t) + tport = t->port; + else + tport = zeroIPPort; + + if (s) + sport = s->port; + else + sport = zeroIPPort; // If DNS Server for this question has changed, reactivate it LogInfo("uDNS_SetupDNSConfig: Updating DNS Server from %#a:%d (%##s) to %#a:%d (%##s) for question %##s (%s) (scope:%p)", - t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), t ? t->domain.c : (mDNSu8*)"", - s ? &s->addr : mDNSNULL, mDNSVal16(s ? s->port : zeroIPPort), s ? s->domain.c : (mDNSu8*)"", + t ? &t->addr : mDNSNULL, mDNSVal16(tport), t ? t->domain.c : (mDNSu8*)"", + s ? &s->addr : mDNSNULL, mDNSVal16(sport), s ? s->domain.c : (mDNSu8*)"", q->qname.c, DNSTypeName(q->qtype), q->InterfaceID); old = q->SuppressQuery; @@ -14919,8 +15063,9 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) } else { + mDNSIPPort zp = zeroIPPort; 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); + q, q->qname.c, DNSTypeName(q->qtype), t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zp), q->DuplicateOf, q->SuppressUnusable); for (qptr = q->next ; qptr; qptr = qptr->next) if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; } } @@ -14967,6 +15112,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) { LogInfo("uDNS_SetupDNSConfig: Purging Resourcerecord %s, New DNS server %#a , Old DNS server %#a", CRDisplayString(m, cr), &ptr->addr, (cr->resrec.rDNSServer != mDNSNULL ? &cr->resrec.rDNSServer->addr : mDNSNULL)); + cr->resrec.mortality = Mortality_Mortal; mDNS_PurgeCacheResourceRecord(m, cr); } else @@ -15035,6 +15181,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) cr->resrec.rDNSServer = mDNSNULL; } + cr->resrec.mortality = Mortality_Mortal; PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNStrue); } } diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/mDNSDebug.h b/usr/src/contrib/mDNSResponder/mDNSCore/mDNSDebug.h index 68a696ef8a..03ed8107fb 100755 --- a/usr/src/contrib/mDNSResponder/mDNSCore/mDNSDebug.h +++ b/usr/src/contrib/mDNSResponder/mDNSCore/mDNSDebug.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2002-2015 Apple Inc. All rights reserved. + * Copyright (c) 2002-2018 Apple Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -87,9 +87,9 @@ extern "C" { #define MDNS_GNU_VA_ARGS 0 #define MDNS_HAS_VA_ARG_MACROS 1 #else - #define MDNS_C99_VA_ARGS 0 + #define MDNS_C99_VA_ARGS 1 #define MDNS_GNU_VA_ARGS 0 - #define MDNS_HAS_VA_ARG_MACROS 0 + #define MDNS_HAS_VA_ARG_MACROS 1 #endif #if (MDNS_HAS_VA_ARG_MACROS) @@ -99,12 +99,14 @@ extern "C" { #define LogOperation(... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, __VA_ARGS__);} while (0) #define LogSPS(... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS, __VA_ARGS__);} while (0) #define LogInfo(... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO, __VA_ARGS__);} while (0) + #define LogDebug(... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_DEBUG, __VA_ARGS__);} while (0) #elif (MDNS_GNU_VA_ARGS) #define debug_noop( ARGS... ) ((void)0) #define LogMsg( ARGS... ) LogMsgWithLevel(MDNS_LOG_MSG, ARGS) #define LogOperation( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, ARGS);} while (0) #define LogSPS( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS, ARGS);} while (0) #define LogInfo( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO, ARGS);} while (0) + #define LogDebug( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_DEBUG, ARGS);} while (0) #else #error Unknown variadic macros #endif @@ -116,10 +118,12 @@ extern "C" { #define LogOperation (mDNS_LoggingEnabled == 0) ? ((void)0) : LogOperation_ #define LogSPS (mDNS_LoggingEnabled == 0) ? ((void)0) : LogSPS_ #define LogInfo (mDNS_LoggingEnabled == 0) ? ((void)0) : LogInfo_ + #define LogDebug (mDNS_LoggingEnabled == 0) ? ((void)0) : LogDebug_ extern void LogMsg_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); extern void LogOperation_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); extern void LogSPS_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); extern void LogInfo_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); +extern void LogDebug_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); #endif #if MDNS_DEBUGMSGS diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h b/usr/src/contrib/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h index cd52c20e53..772664fe02 100755 --- a/usr/src/contrib/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h +++ b/usr/src/contrib/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2002-2015 Apple Inc. All rights reserved. + * Copyright (c) 2002-2018 Apple Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -101,6 +101,10 @@ extern "C" { #define MaximumRDSize 264 #endif +#if !defined(MDNSRESPONDER_BTMM_SUPPORT) +#define MDNSRESPONDER_BTMM_SUPPORT 0 +#endif + // *************************************************************************** // Function scope indicators @@ -276,6 +280,8 @@ typedef struct mDNSInterfaceID_dummystruct { void *dummy; } *mDNSInterfaceID; // find you get code that doesn't work consistently on big-endian and little-endian machines. #if defined(_WIN32) #pragma pack(push,2) +#elif !defined(__GNUC__) + #pragma pack(1) #endif typedef union { mDNSu8 b[ 2]; mDNSu16 NotAnInteger; } mDNSOpaque16; typedef union { mDNSu8 b[ 4]; mDNSu32 NotAnInteger; } mDNSOpaque32; @@ -284,6 +290,8 @@ typedef union { mDNSu8 b[ 8]; mDNSu16 w[4]; mDNSu32 l[2]; } mDNSOpaque64; typedef union { mDNSu8 b[16]; mDNSu16 w[8]; mDNSu32 l[4]; } mDNSOpaque128; #if defined(_WIN32) #pragma pack(pop) +#elif !defined(__GNUC__) + #pragma pack() #endif typedef mDNSOpaque16 mDNSIPPort; // An IP port is a two-byte opaque identifier (not an integer) @@ -1335,6 +1343,13 @@ typedef struct McastResolver mDNSu32 timeout; // timeout value for questions } McastResolver; +enum { + Mortality_Mortal = 0, // This cache record can expire and get purged + Mortality_Immortal = 1, // Allow this record to remain in the cache indefinitely + Mortality_Ghost = 2 // An immortal record that has expired and can linger in the cache +}; +typedef mDNSu8 MortalityState; + // scoped values for DNSServer matching enum { @@ -1372,6 +1387,7 @@ typedef struct DNSServer mDNSBool req_DO; // If set, okay to send DNSSEC queries (EDNS DO bit is supported) mDNSBool DNSSECAware; // Set if we are able to receive a response to a request sent with DO option. mDNSBool isExpensive; // True if the interface to this server is expensive. + mDNSBool isCLAT46; // True if the interface to this server is CLAT46. } DNSServer; typedef struct @@ -1386,6 +1402,7 @@ typedef struct struct ResourceRecord_struct { mDNSu8 RecordType; // See kDNSRecordTypes enum. + MortalityState mortality; // Mortality of this resource record (See MortalityState enum) mDNSu16 rrtype; // See DNS_TypeValues enum. mDNSu16 rrclass; // See DNS_ClassValues enum. mDNSu32 rroriginalttl; // In seconds @@ -1399,7 +1416,6 @@ struct ResourceRecord_struct // ReconfirmAntecedents(), etc., use rdatahash as a pre-flight check to see // whether it's worth doing a full SameDomainName() call. If the rdatahash // is not a correct case-insensitive name hash, they'll get false negatives. - // Grouping pointers together at the end of the structure improves the memory layout efficiency mDNSInterfaceID InterfaceID; // Set if this RR is specific to one interface // For records received off the wire, InterfaceID is *always* set to the receiving interface @@ -1638,7 +1654,7 @@ struct CacheRecord_struct mDNSs32 TimeRcvd; // In platform time units 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 + // Extra four bytes here (on 64bit) DNSQuestion *CRActiveQuestion; // Points to an active question referencing this answer. Can never point to a NewQuestion. mDNSs32 LastUnansweredTime; // In platform time units; last time we incremented UnansweredQueries mDNSu8 UnansweredQueries; // Number of times we've issued a query for this record without getting an answer @@ -1811,8 +1827,13 @@ typedef enum { DNSPUSH_SERVERFOUND = 3, DNSPUSH_ESTABLISHED = 4 } DNSPush_State; - - + +enum { + AllowExpired_None = 0, // Don't allow expired answers or mark answers immortal (behave normally) + AllowExpired_MakeAnswersImmortal = 1, // Any answers to this question get marked as immortal + AllowExpired_AllowExpiredAnswers = 2 // Allow already expired answers from the cache +}; +typedef mDNSu8 AllowExpiredState; #define HMAC_LEN 64 #define HMAC_IPAD 0x36 @@ -1896,16 +1917,29 @@ typedef enum { DNSSECValNotRequired = 0, DNSSECValRequired, DNSSECValInProgress, // RFC 4122 defines it to be 16 bytes #define UUID_SIZE 16 -#define AWD_METRICS (USE_AWD && TARGET_OS_EMBEDDED) +#define AWD_METRICS (USE_AWD && TARGET_OS_IOS) #if AWD_METRICS -typedef struct + +enum { - domainname * originalQName; // Name of original A/AAAA record if this question is for a CNAME record. - mDNSu32 querySendCount; // Number of queries that have been sent to DNS servers so far. - mDNSs32 firstQueryTime; // The time when the first query was sent to a DNS server. - mDNSBool answered; // Has this question been answered? + ExpiredAnswer_None = 0, // No expired answers used + ExpiredAnswer_Allowed = 1, // An expired answer is allowed by this request + ExpiredAnswer_AnsweredWithExpired = 2, // Question was answered with an expired answer + ExpiredAnswer_ExpiredAnswerChanged = 3, // Expired answer changed on refresh + + ExpiredAnswer_EnumCount +}; +typedef mDNSu8 ExpiredAnswerMetric; +typedef struct +{ + domainname * originalQName; // Name of original A/AAAA record if this question is for a CNAME record. + mDNSu32 querySendCount; // Number of queries that have been sent to DNS servers so far. + mDNSs32 firstQueryTime; // The time when the first query was sent to a DNS server. + mDNSBool answered; // Has this question been answered? + ExpiredAnswerMetric expiredAnswerState; // Expired answer state (see ExpiredAnswerMetric above) + } uDNSMetrics; #endif @@ -1977,6 +2011,7 @@ struct DNSQuestion_struct 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 + AllowExpiredState allowExpired; // Allow expired answers state (see enum AllowExpired_None, etc. above) 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 @@ -2016,6 +2051,7 @@ struct DNSQuestion_struct mDNSIPPort TargetPort; // Must be set if Target is set mDNSOpaque16 TargetQID; // Must be set if Target is set domainname qname; + domainname firstExpiredQname; // first expired qname in request chain mDNSu16 qtype; mDNSu16 qclass; mDNSBool LongLived; // Set by client for calls to mDNS_StartQuery to indicate LLQs to unicast layer. @@ -2039,7 +2075,7 @@ struct DNSQuestion_struct domainname *qnameOrig; // Copy of the original question name if it is not fully qualified mDNSQuestionCallback *QuestionCallback; void *QuestionContext; -#if TARGET_OS_EMBEDDED +#if AWD_METRICS uDNSMetrics metrics; // Data used for collecting unicast DNS query metrics. #endif #if USE_DNS64 @@ -2155,7 +2191,7 @@ struct NetworkInterfaceInfo_struct mDNSBool DirectLink; // a direct link, indicating we can skip the probe for // address records mDNSBool SupportsUnicastMDNSResponse; // Indicates that the interface supports unicast responses - // to Bonjour queries. Generally true for an interface + // to Bonjour queries. Generally true for an interface. }; #define SLE_DELETE 0x00000001 @@ -2604,6 +2640,8 @@ extern mDNSu8 NumUnreachableDNSServers; #define mDNSinline static __inline #elif ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9))) #define mDNSinline static inline +#else + #define mDNSinline static inline #endif // If we're not doing inline functions, then this header needs to have the extern declarations @@ -2778,7 +2816,7 @@ extern void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDN extern mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType); extern mStatus mDNS_RegisterService (mDNS *const m, ServiceRecordSet *sr, const domainlabel *const name, const domainname *const type, const domainname *const domain, - const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen, + const domainname *const host, mDNSIPPort port, RData *txtrdata, const mDNSu8 txtinfo[], mDNSu16 txtlen, AuthRecord *SubTypes, mDNSu32 NumSubTypes, mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context, mDNSu32 flags); extern mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl, mDNSu32 flags); @@ -2939,6 +2977,7 @@ extern char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RDataB #define RRDisplayString(m, rr) GetRRDisplayString_rdb(rr, &(rr)->rdata->u, (m)->MsgBuffer) #define ARDisplayString(m, rr) GetRRDisplayString_rdb(&(rr)->resrec, &(rr)->resrec.rdata->u, (m)->MsgBuffer) #define CRDisplayString(m, rr) GetRRDisplayString_rdb(&(rr)->resrec, &(rr)->resrec.rdata->u, (m)->MsgBuffer) +#define MortalityDisplayString(M) (M == Mortality_Mortal ? "mortal" : (M == Mortality_Immortal ? "immortal" : "ghost")) extern mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2); extern void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText); extern mDNSBool mDNSv4AddrIsRFC1918(const mDNSv4Addr * const addr); // returns true for RFC1918 private addresses @@ -3039,8 +3078,8 @@ extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCa 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, mDNSs32 serviceID, const mDNSAddr *addr, - const mDNSIPPort port, mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSu16 resGroupID, - mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO); + const mDNSIPPort port, mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSBool isCLAT46, + mDNSu16 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO); extern void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 responseFlags); extern void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID); @@ -3357,7 +3396,7 @@ extern void RemoveAutoTunnel6Record(mDNS *const m); extern mDNSBool RecordReadyForSleep(AuthRecord *rr); // For now this LocalSleepProxy 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 -extern mStatus ActivateLocalProxy(NetworkInterfaceInfo *const intf, mDNSBool *keepaliveOnly); +extern mStatus ActivateLocalProxy(NetworkInterfaceInfo *const intf, mDNSBool offloadKeepAlivesOnly, mDNSBool *keepaliveOnly); extern void mDNSPlatformUpdateDNSStatus(DNSQuestion *q); extern void mDNSPlatformTriggerDNSRetry(DNSQuestion *v4q, DNSQuestion *v6q); extern void mDNSPlatformLogToFile(int log_level, const char *buffer); @@ -3601,17 +3640,17 @@ struct CompileTimeAssertionChecks_mDNS char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1208) ? 1 : -1]; char sizecheck_CacheRecord [(sizeof(CacheRecord) <= 232) ? 1 : -1]; char sizecheck_CacheGroup [(sizeof(CacheGroup) <= 232) ? 1 : -1]; - char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 912) ? 1 : -1]; + char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 1168) ? 1 : -1]; - char sizecheck_ZoneData [(sizeof(ZoneData) <= 1744) ? 1 : -1]; + char sizecheck_ZoneData [(sizeof(ZoneData) <= 2000) ? 1 : -1]; char sizecheck_NATTraversalInfo [(sizeof(NATTraversalInfo) <= 200) ? 1 : -1]; char sizecheck_HostnameInfo [(sizeof(HostnameInfo) <= 3050) ? 1 : -1]; char sizecheck_DNSServer [(sizeof(DNSServer) <= 330) ? 1 : -1]; - char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 7376) ? 1 : -1]; + char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 8400) ? 1 : -1]; char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 5540) ? 1 : -1]; char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 7888) ? 1 : -1]; #if APPLE_OSX_mDNSResponder - char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1256) ? 1 : -1]; + char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1512) ? 1 : -1]; #endif }; diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/uDNS.c b/usr/src/contrib/mDNSResponder/mDNSCore/uDNS.c index 0b1fe638ec..84913404d4 100755 --- a/usr/src/contrib/mDNSResponder/mDNSCore/uDNS.c +++ b/usr/src/contrib/mDNSResponder/mDNSCore/uDNS.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2002-2015 Apple Inc. All rights reserved. + * Copyright (c) 2002-2017 Apple Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,10 @@ #endif #include "uDNS.h" +#if AWD_METRICS +#include "Metrics.h" +#endif + #if (defined(_MSC_VER)) // Disable "assignment within conditional expression". // Other compilers understand the convention that if you place the assignment expression within an extra pair @@ -111,9 +115,11 @@ mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mDNSu32 random) #pragma mark - Name Server List Management #endif +#define TrueFalseStr(X) ((X) ? "true" : "false") + mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSs32 serviceID, const mDNSAddr *addr, - const mDNSIPPort port, mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSu16 resGroupID, - mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO) + const mDNSIPPort port, mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSBool isCLAT46, + mDNSu16 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO) { DNSServer **p = &m->DNSServers; DNSServer *tmp = mDNSNULL; @@ -127,9 +133,9 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons if (!d) d = (const domainname *)""; - LogInfo("mDNS_AddDNSServer(%d): Adding %#a for %##s, InterfaceID %p, serviceID %u, scoped %d, resGroupID %d req_A is %s req_AAAA is %s cell %s isExpensive %s req_DO is %s", - NumUnicastDNSServers, addr, d->c, interface, serviceID, scoped, resGroupID, reqA ? "True" : "False", reqAAAA ? "True" : "False", - cellIntf ? "True" : "False", isExpensive ? "True" : "False", reqDO ? "True" : "False"); + LogInfo("mDNS_AddDNSServer(%d): Adding %#a for %##s, InterfaceID %p, serviceID %u, scoped %d, resGroupID %d req_A %s, req_AAAA %s, cell %s, expensive %s, CLAT46 %s, req_DO %s", + NumUnicastDNSServers, addr, d->c, interface, serviceID, scoped, resGroupID, + TrueFalseStr(reqA), TrueFalseStr(reqAAAA), TrueFalseStr(cellIntf), TrueFalseStr(isExpensive), TrueFalseStr(isCLAT46), TrueFalseStr(reqDO)); while (*p) // Check if we already have this {interface,address,port,domain} tuple registered + reqA/reqAAAA bits { @@ -193,6 +199,7 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons (*p)->timeout = timeout; (*p)->cellIntf = cellIntf; (*p)->isExpensive = isExpensive; + (*p)->isCLAT46 = isCLAT46; (*p)->req_A = reqA; (*p)->req_AAAA = reqAAAA; (*p)->req_DO = reqDO; @@ -544,7 +551,7 @@ mDNSlocal mStatus uDNS_RequestAddress(mDNS *m) return err; } -mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool usePCP) +mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool usePCP, mDNSBool unmapping) { mStatus err = mStatus_NoError; @@ -643,19 +650,25 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool useP info->sentNATPMP = mDNSfalse; #ifdef _LEGACY_NAT_TRAVERSAL_ - if (mDNSIPPortIsZero(m->UPnPRouterPort) || mDNSIPPortIsZero(m->UPnPSOAPPort)) + // If an unmapping is being performed, then don't send an LNT discovery message or an LNT port map request. + if (!unmapping) { - LNT_SendDiscoveryMsg(m); - debugf("uDNS_SendNATMsg: LNT_SendDiscoveryMsg"); - } - else - { - mStatus lnterr = LNT_MapPort(m, info); - if (lnterr) - LogMsg("uDNS_SendNATMsg: LNT_MapPort returned error %d", lnterr); + if (mDNSIPPortIsZero(m->UPnPRouterPort) || mDNSIPPortIsZero(m->UPnPSOAPPort)) + { + LNT_SendDiscoveryMsg(m); + debugf("uDNS_SendNATMsg: LNT_SendDiscoveryMsg"); + } + else + { + mStatus lnterr = LNT_MapPort(m, info); + if (lnterr) + LogMsg("uDNS_SendNATMsg: LNT_MapPort returned error %d", lnterr); - err = err ? err : lnterr; // PCP error takes precedence + err = err ? err : lnterr; // PCP error takes precedence + } } +#else + (void)unmapping; // Unused #endif // _LEGACY_NAT_TRAVERSAL_ } } @@ -919,6 +932,16 @@ mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *tra } } + // Even if we DIDN'T make a successful UPnP mapping yet, we might still have a partially-open TCP connection we need to clean up + // Before zeroing traversal->RequestedPort below, perform the LNT unmapping, which requires the mapping's external port, + // held by the traversal->RequestedPort variable. + #ifdef _LEGACY_NAT_TRAVERSAL_ + { + mStatus err = LNT_UnmapPort(m, traversal); + if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %d", err); + } + #endif // _LEGACY_NAT_TRAVERSAL_ + if (traversal->ExpiryTime && unmap) { traversal->NATLease = 0; @@ -940,17 +963,9 @@ mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *tra traversal->RequestedPort = zeroIPPort; traversal->NewAddress = zerov4Addr; - uDNS_SendNATMsg(m, traversal, traversal->lastSuccessfulProtocol != NATTProtocolNATPMP); + uDNS_SendNATMsg(m, traversal, traversal->lastSuccessfulProtocol != NATTProtocolNATPMP, mDNStrue); } - // Even if we DIDN'T make a successful UPnP mapping yet, we might still have a partially-open TCP connection we need to clean up - #ifdef _LEGACY_NAT_TRAVERSAL_ - { - mStatus err = LNT_UnmapPort(m, traversal); - if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %d", err); - } - #endif // _LEGACY_NAT_TRAVERSAL_ - return(mStatus_NoError); } @@ -1327,6 +1342,12 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, mDNSNULL, &tcpInfo->Addr, tcpInfo->Port, sock, AuthInfo, mDNSfalse); if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %d", err); err = mStatus_UnknownErr; goto exit; } +#if AWD_METRICS + if (mDNSSameIPPort(tcpInfo->Port, UnicastDNSPort)) + { + MetricsUpdateDNSQuerySize((mDNSu32)(end - (mDNSu8 *)&tcpInfo->request)); + } +#endif // Record time we sent this question if (q) @@ -1856,7 +1877,10 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question if (question->ThisQInterval != -1) LogMsg("GetZoneData_QuestionCallback: Question %##s (%s) ThisQInterval %d not -1", question->qname.c, DNSTypeName(question->qtype), question->ThisQInterval); zd->Addr.type = mDNSAddrType_IPv4; - zd->Addr.ip.v4 = (answer->rdlength == 4) ? answer->rdata->u.ipv4 : zerov4Addr; + if (answer->rdlength == 4) + zd->Addr.ip.v4 = answer->rdata->u.ipv4; + else + zd->Addr.ip.v4 = zerov4Addr; // In order to simulate firewalls blocking our outgoing TCP connections, returning immediate ICMP errors or TCP resets, // the code below will make us try to connect to loopback, resulting in an immediate "port unreachable" failure. // This helps us test to make sure we handle this case gracefully @@ -2679,6 +2703,7 @@ mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn) mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router) { mDNSBool v4Changed, v6Changed, RouterChanged; + mDNSv6Addr v6; if (m->mDNS_busy != m->mDNS_reentrancy) LogMsg("mDNS_SetPrimaryInterfaceInfo: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); @@ -2690,7 +2715,11 @@ mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, co mDNS_Lock(m); v4Changed = !mDNSSameIPv4Address(m->AdvertisedV4.ip.v4, v4addr ? v4addr->ip.v4 : zerov4Addr); - v6Changed = !mDNSSameIPv6Address(m->AdvertisedV6.ip.v6, v6addr ? v6addr->ip.v6 : zerov6Addr); + if (v6addr) + v6 = v6addr->ip.v6; + else + v6 = zerov6Addr; + v6Changed = !mDNSSameIPv6Address(m->AdvertisedV6.ip.v6, v6); RouterChanged = !mDNSSameIPv4Address(m->Router.ip.v4, router ? router->ip.v4 : zerov4Addr); if (v4addr && (v4Changed || RouterChanged)) @@ -3649,7 +3678,7 @@ mDNSlocal void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interface { // Send a NAT-PMP request for this operation as needed // and update the state variables - uDNS_SendNATMsg(m, n, mDNSfalse); + uDNS_SendNATMsg(m, n, mDNSfalse, mDNSfalse); } m->NextScheduledNATOp = m->timenow; @@ -3903,14 +3932,7 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS if (msg->h.flags.b[0] & kDNSFlag0_TC && mDNSSameOpaque16(qptr->TargetQID, msg->h.id) && m->timenow - qptr->LastQTime < RESPONSE_WINDOW) { if (!srcaddr) LogMsg("uDNS_ReceiveMsg: TCP DNS response had TC bit set: ignoring"); - else - { - // Don't reuse TCP connections. We might have failed over to a different DNS server - // while the first TCP connection is in progress. We need a new TCP connection to the - // new DNS server. So, always try to establish a new connection. - if (qptr->tcp) { DisposeTCPConn(qptr->tcp); qptr->tcp = mDNSNULL; } - qptr->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_Zero, srcaddr, srcport, mDNSNULL, qptr, mDNSNULL); - } + else uDNS_RestartQuestionAsTCP(m, qptr, srcaddr, srcport); } } @@ -4694,8 +4716,9 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) new = GetServerForQuestion(m, q); if (new) { + mDNSIPPort zp = zeroIPPort; LogInfo("uDNS_checkCurrentQuestion: Retrying question %p %##s (%s) DNS Server %#a:%d ThisQInterval %d", - q, q->qname.c, DNSTypeName(q->qtype), new ? &new->addr : mDNSNULL, mDNSVal16(new ? new->port : zeroIPPort), q->ThisQInterval); + q, q->qname.c, DNSTypeName(q->qtype), new ? &new->addr : mDNSNULL, mDNSVal16(new? new->port : zp), q->ThisQInterval); DNSServerChangeForQuestion(m, q, new); } for (qptr = q->next ; qptr; qptr = qptr->next) @@ -4730,6 +4753,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) } else { + mDNSIPPort zp = zeroIPPort; debugf("uDNS_CheckCurrentQuestion sending %p %##s (%s) %#a:%d UnansweredQueries %d", q, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->unansweredQueries); @@ -4757,9 +4781,10 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) else { err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, q->LocalSocket, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, mDNSNULL, q->UseBackgroundTrafficClass); -#if TARGET_OS_EMBEDDED +#if AWD_METRICS if (!err) { + MetricsUpdateDNSQuerySize((mDNSu32)(end - (mDNSu8 *)&m->omsg)); if (q->metrics.answered) { q->metrics.querySendCount = 0; @@ -4891,9 +4916,12 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) 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; } - LogInfo("uDNS_checkCurrentQuestion: Tried all DNS servers, retry question %p SuppressUnusable %d %##s (%s) with DNS Server %#a:%d after 60 seconds, ThisQInterval %d", + { + mDNSIPPort zp = zeroIPPort; + LogInfo("uDNS_checkCurrentQuestion: Tried all DNS servers, retry question %p SuppressUnusable %d %##s (%s) with DNS Server %#a:%d after 60 seconds, ThisQInterval %d", q, q->SuppressUnusable, q->qname.c, DNSTypeName(q->qtype), - q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->ThisQInterval); + q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zp), q->ThisQInterval); + } } } else @@ -4991,7 +5019,7 @@ mDNSexport void CheckNATMappings(mDNS *m) cur->retryInterval = NATMAP_INIT_RETRY; } - uDNS_SendNATMsg(m, cur, mDNStrue); // Will also do UPnP discovery for us, if necessary + uDNS_SendNATMsg(m, cur, mDNStrue, mDNSfalse); // Will also do UPnP discovery for us, if necessary if (cur->ExpiryTime) // If have active mapping then set next renewal time halfway to expiry NATSetNextRenewalTime(m, cur); @@ -5722,6 +5750,15 @@ mDNSexport domainname *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, mD return mDNSNULL; } +mDNSexport void uDNS_RestartQuestionAsTCP(mDNS *m, DNSQuestion *const q, const mDNSAddr *const srcaddr, const mDNSIPPort srcport) +{ + // Don't reuse TCP connections. We might have failed over to a different DNS server + // while the first TCP connection is in progress. We need a new TCP connection to the + // new DNS server. So, always try to establish a new connection. + if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; } + q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_Zero, srcaddr, srcport, mDNSNULL, q, mDNSNULL); +} + mDNSlocal void FlushAddressCacheRecords(mDNS *const m) { mDNSu32 slot; @@ -5787,7 +5824,7 @@ struct CompileTimeAssertionChecks_uDNS // 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_tcpInfo_t [(sizeof(tcpInfo_t) <= 9056) ? 1 : -1]; - char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 5000) ? 1 : -1]; + char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 6136) ? 1 : -1]; }; #if COMPILER_LIKES_PRAGMA_MARK diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/uDNS.h b/usr/src/contrib/mDNSResponder/mDNSCore/uDNS.h index 90f50a6fc1..0a0622784d 100755 --- a/usr/src/contrib/mDNSResponder/mDNSCore/uDNS.h +++ b/usr/src/contrib/mDNSResponder/mDNSCore/uDNS.h @@ -129,6 +129,8 @@ extern void uDNS_SetupWABQueries(mDNS *const m); extern void uDNS_StartWABQueries(mDNS *const m, int queryType); extern void uDNS_StopWABQueries(mDNS *const m, int queryType); extern domainname *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, mDNSs8 *searchIndex, mDNSBool ignoreDotLocal); + +extern void uDNS_RestartQuestionAsTCP(mDNS *m, DNSQuestion *const q, const mDNSAddr *const srcaddr, const mDNSIPPort srcport); typedef enum { diff --git a/usr/src/contrib/mDNSResponder/mDNSPosix/PosixDaemon.c b/usr/src/contrib/mDNSResponder/mDNSPosix/PosixDaemon.c index c1cc6a4e65..dd932949e7 100644 --- a/usr/src/contrib/mDNSResponder/mDNSPosix/PosixDaemon.c +++ b/usr/src/contrib/mDNSResponder/mDNSPosix/PosixDaemon.c @@ -132,8 +132,8 @@ mDNSlocal void ToggleLogPacket(void) mDNS_PacketLoggingEnabled = !mDNS_PacketLoggingEnabled; } -mDNSlocal void DumpStateLog() // Dump a little log of what we've been up to. +mDNSlocal void DumpStateLog() { LogMsg("---- BEGIN STATE LOG ----"); udsserver_info(); diff --git a/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSPosix.c b/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSPosix.c index b9c3cd58eb..50acd2bd4c 100755 --- a/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSPosix.c +++ b/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSPosix.c @@ -433,10 +433,6 @@ mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result #pragma mark ***** DDNS Config Platform Functions #endif -/* - * Stub to set or get DNS config. Even if it actually does not do anything, - * it has to make sure the data is zeroed properly. - */ mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig) { @@ -506,7 +502,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, 0, &DNSAddr, UnicastDNSPort, kScopeNone, 0, mDNSfalse, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse); + mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, 0, &DNSAddr, UnicastDNSPort, kScopeNone, 0, mDNSfalse, mDNSfalse, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse); numOfServers++; } } @@ -667,9 +663,9 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf // Enable inbound packets on IFEF_AWDL interface. // Only done for multicast sockets, since we don't expect unicast socket operations // on the IFEF_AWDL interface. Operation is a no-op for other interface types. - #ifdef SO_RECV_ANYIF + #ifdef SO_RECV_ANYIF if (setsockopt(*sktPtr, SOL_SOCKET, SO_RECV_ANYIF, &kOn, sizeof(kOn)) < 0) perror("setsockopt - SO_RECV_ANYIF"); - #endif + #endif } // We want to receive destination addresses and interface identifiers. @@ -771,11 +767,11 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf #warning This platform has no way to get the destination interface information for IPv6 -- will only work for single-homed hosts #endif #if defined(IPV6_RECVHOPLIMIT) - if (err == 0) - { - err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &kOn, sizeof(kOn)); - if (err < 0) { err = errno; perror("setsockopt - IPV6_RECVHOPLIMIT"); } - } + if (err == 0) + { + err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &kOn, sizeof(kOn)); + if (err < 0) { err = errno; perror("setsockopt - IPV6_RECVHOPLIMIT"); } + } #elif defined(IPV6_HOPLIMIT) if (err == 0) { @@ -1220,10 +1216,10 @@ mDNSlocal mDNSu32 ProcessRoutingNotification(int sd) */ case RTM_ADD: case RTM_DELETE: - if (pRSMsg->ifam_type == RTM_IFINFO) - result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index; - else - result |= 1 << pRSMsg->ifam_index; + if (pRSMsg->ifam_type == RTM_IFINFO) + result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index; + else + result |= 1 << pRSMsg->ifam_index; break; } @@ -1341,7 +1337,8 @@ mDNSexport mStatus mDNSPlatformInit(mDNS *const m) // Failure to observe interface changes is non-fatal. if (err != mStatus_NoError) { - fprintf(stderr, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n", getpid(), err); + fprintf(stderr, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n", + (int)getpid(), err); err = mStatus_NoError; } } diff --git a/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSUNP.c b/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSUNP.c index ed6da80953..cc2401bdac 100755 --- a/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSUNP.c +++ b/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSUNP.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002-2018 Apple Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -84,40 +84,56 @@ void plen_to_mask(int plen, char *addr) { } /* Gets IPv6 interface information from the /proc filesystem in linux*/ -struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) +struct ifi_info *get_ifi_info_linuxv6(int doaliases) { struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr; FILE *fp = NULL; - char addr[8][5]; - int flags, myflags, index, plen, scope; - char ifname[9], lastname[IFNAMSIZ]; - char addr6[32+7+1]; /* don't forget the seven ':' */ + int i, nitems, flags, index, plen, scope; struct addrinfo hints, *res0; int err; int sockfd = -1; struct ifreq ifr; + char ifnameFmt[16], addrStr[32 + 7 + 1], ifname[IFNAMSIZ], lastname[IFNAMSIZ]; res0=NULL; ifihead = NULL; ifipnext = &ifihead; - lastname[0] = 0; if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) { sockfd = socket(AF_INET6, SOCK_DGRAM, 0); if (sockfd < 0) { goto gotError; } - while (fscanf(fp, - "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n", - addr[0],addr[1],addr[2],addr[3], - addr[4],addr[5],addr[6],addr[7], - &index, &plen, &scope, &flags, ifname) != EOF) { - - myflags = 0; - if (strncmp(lastname, ifname, IFNAMSIZ) == 0) { + + // Parse /proc/net/if_inet6 according to <https://www.tldp.org/HOWTO/Linux+IPv6-HOWTO/ch11s04.html>. + + // Create a string specifier with a width of IFNAMSIZ - 1 ("%<IFNAMSIZ - 1>s") to scan the interface name. The + // reason why we don't just use the string-ified macro expansion of IFNAMSIZ for the width is because the width + // needs to be a decimal string and there's no guarantee that IFNAMSIZ will be defined as a decimal integer. For + // example, it could be defined in hexadecimal or as an arithmetic expression. + + snprintf(ifnameFmt, sizeof(ifnameFmt), "%%%ds", IFNAMSIZ - 1); + + // Write the seven IPv6 address string colons and NUL terminator, i.e., "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx". + // The remaining 32 IPv6 address characters come from /proc/net/if_inet6. + + for (i = 4; i < 39; i += 5) addrStr[i] = ':'; + addrStr[39] = '\0'; + + lastname[0] = '\0'; + for (;;) { + nitems = fscanf(fp, " %4c%4c%4c%4c%4c%4c%4c%4c %x %x %x %x", + &addrStr[0], &addrStr[5], &addrStr[10], &addrStr[15], + &addrStr[20], &addrStr[25], &addrStr[30], &addrStr[35], + &index, &plen, &scope, &flags); + if (nitems != 12) break; + + nitems = fscanf(fp, ifnameFmt, ifname); + if (nitems != 1) break; + + if (strcmp(lastname, ifname) == 0) { if (doaliases == 0) continue; /* already processed this interface */ - myflags = IFI_ALIAS; } memcpy(lastname, ifname, IFNAMSIZ); ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info)); @@ -130,15 +146,11 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) *ifipnext = ifi; /* prev points to this new one */ ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ - sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", - addr[0],addr[1],addr[2],addr[3], - addr[4],addr[5],addr[6],addr[7]); - /* Add address of the interface */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; hints.ai_flags = AI_NUMERICHOST; - err = getaddrinfo(addr6, NULL, &hints, &res0); + err = getaddrinfo(addrStr, NULL, &hints, &res0); if (err) { goto gotError; } @@ -156,9 +168,9 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) goto gotError; } - ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_family=family; + ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_family=AF_INET6; ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_scope_id=scope; - inet_pton(family, ipv6addr, &((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_addr); + inet_pton(AF_INET6, ipv6addr, &((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_addr); /* Add interface name */ memcpy(ifi->ifi_name, ifname, IFI_NAME); @@ -222,8 +234,7 @@ done: * Unlike plen_to_mask returns netmask in binary form and not * in text form. */ -static void plen_to_netmask(int prefix, unsigned char *addr) -{ +static void plen_to_netmask(int prefix, unsigned char *addr) { for (; prefix > 8; prefix -= 8) *addr++ = 0xff; for (; prefix > 0; prefix--) @@ -543,7 +554,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(doaliases); #elif HAVE_SOLARIS return get_ifi_info_solaris(family); #endif @@ -839,7 +850,7 @@ recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp, *ttl = 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be - msg.msg_control = control_un.control; + msg.msg_control = (void *) control_un.control; msg.msg_controllen = sizeof(control_un.control); msg.msg_flags = 0; #else diff --git a/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSUNP.h b/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSUNP.h index cc81b7d393..2b36ceb042 100755 --- a/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSUNP.h +++ b/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSUNP.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002-2018 Apple Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -62,8 +62,8 @@ typedef unsigned int socklen_t; #define GET_SA_LEN(X) (((struct sockaddr*)&(X))->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr)) #endif -#define IFI_NAME 16 /* same as IFNAMSIZ in <net/if.h> */ -#define IFI_HADDR 8 /* allow for 64-bit EUI-64 in future */ +#define IFI_NAME IFNAMSIZ /* same as IFNAMSIZ in <net/if.h> */ +#define IFI_HADDR 8 /* allow for 64-bit EUI-64 in future */ // Renamed from my_in_pktinfo because in_pktinfo is used by Linux. @@ -98,7 +98,7 @@ struct ifi_info { #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX #define PROC_IFINET6_PATH "/proc/net/if_inet6" -extern struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases); +extern struct ifi_info *get_ifi_info_linuxv6(int doaliases); #endif #if defined(AF_INET6) && HAVE_IPV6 diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/PlatformCommon.c b/usr/src/contrib/mDNSResponder/mDNSShared/PlatformCommon.c index 909efed5c5..3a13d5ce53 100644 --- a/usr/src/contrib/mDNSResponder/mDNSShared/PlatformCommon.c +++ b/usr/src/contrib/mDNSResponder/mDNSShared/PlatformCommon.c @@ -69,10 +69,9 @@ mDNSexport void mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAdd else return; if ((connect(sock, &addr.s, inner_len)) < 0) { - if (errno != ENETUNREACH) { - LogMsg("mDNSPlatformSourceAddrForDest: connect %#a failed errno %d " - "(%s)", dst, errno, strerror(errno)); - } + if (errno != ENETUNREACH) + LogMsg("mDNSPlatformSourceAddrForDest: connect %#a failed errno %d (%s)", dst, errno, + strerror(errno)); goto exit; } diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd.h b/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd.h index 701c4ff3a6..0a4597fae0 100644 --- a/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd.h +++ b/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2003-2015 Apple Inc. All rights reserved. + * Copyright (c) 2003-2018 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -66,7 +66,7 @@ */ #ifndef _DNS_SD_H -#define _DNS_SD_H 8780101 +#define _DNS_SD_H 8806001 #ifdef __cplusplus extern "C" { @@ -75,9 +75,11 @@ extern "C" { /* Set to 1 if libdispatch is supported * Note: May also be set by project and/or Makefile */ -#ifndef _DNS_SD_LIBDISPATCH +#if defined(__APPLE__) +#define _DNS_SD_LIBDISPATCH 1 +#else #define _DNS_SD_LIBDISPATCH 0 -#endif /* ndef _DNS_SD_LIBDISPATCH */ +#endif /* standard calling convention under Win32 is __stdcall */ /* Note: When compiling Intel EFI (Extensible Firmware Interface) under MS Visual Studio, the */ @@ -88,6 +90,12 @@ extern "C" { #define DNSSD_API #endif +#if (defined(__GNUC__) && (__GNUC__ >= 4)) +#define DNSSD_EXPORT __attribute__((visibility("default"))) +#else +#define DNSSD_EXPORT +#endif + #if defined(_WIN32) #include <winsock2.h> typedef SOCKET dnssd_sock_t; @@ -526,11 +534,25 @@ enum * This flag is private and should not be used. */ - kDNSServiceFlagsPrivateFour = 0x40000000 + kDNSServiceFlagsPrivateFour = 0x40000000, /* * This flag is private and should not be used. */ + kDNSServiceFlagsAllowExpiredAnswers = 0x80000000, + /* + * When kDNSServiceFlagsAllowExpiredAnswers is passed to DNSServiceQueryRecord or DNSServiceGetAddrInfo, + * if there are matching expired records still in the cache, then they are immediately returned to the + * client, and in parallel a network query for that name is issued. All returned records from the query will + * remain in the cache after expiration. + */ + + kDNSServiceFlagsExpiredAnswer = 0x80000000 + /* + * When kDNSServiceFlagsAllowExpiredAnswers is passed to DNSServiceQueryRecord or DNSServiceGetAddrInfo, + * an expired answer will have this flag set. + */ + }; #define kDNSServiceOutputFlags (kDNSServiceFlagsValidate | kDNSServiceFlagsValidateOptional | kDNSServiceFlagsMoreComing | kDNSServiceFlagsAdd | kDNSServiceFlagsDefault) @@ -871,6 +893,7 @@ typedef int32_t DNSServiceErrorType; * if the daemon (or "system service" on Windows) is not running. */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceGetProperty ( const char *property, /* Requested property (i.e. kDNSServiceProperty_DaemonVersion) */ @@ -930,6 +953,7 @@ DNSServiceErrorType DNSSD_API DNSServiceGetProperty * error. */ +DNSSD_EXPORT dnssd_sock_t DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef); @@ -951,6 +975,7 @@ dnssd_sock_t DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef); * an error code indicating the specific failure that occurred. */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef); @@ -978,6 +1003,7 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef); * */ +DNSSD_EXPORT void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef); @@ -1062,6 +1088,7 @@ typedef void (DNSSD_API *DNSServiceDomainEnumReply) * is not initialized). */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains ( DNSServiceRef *sdRef, @@ -1252,6 +1279,7 @@ typedef void (DNSSD_API *DNSServiceRegisterReply) * is not initialized). */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceRegister ( DNSServiceRef *sdRef, @@ -1307,6 +1335,7 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister * error code indicating the error that occurred (the RecordRef is not initialized). */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceAddRecord ( DNSServiceRef sdRef, @@ -1348,6 +1377,7 @@ DNSServiceErrorType DNSSD_API DNSServiceAddRecord * error code indicating the error that occurred. */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord ( DNSServiceRef sdRef, @@ -1380,6 +1410,7 @@ DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord * error code indicating the error that occurred. */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord ( DNSServiceRef sdRef, @@ -1485,6 +1516,7 @@ typedef void (DNSSD_API *DNSServiceBrowseReply) * is not initialized). */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceBrowse ( DNSServiceRef *sdRef, @@ -1613,6 +1645,7 @@ typedef void (DNSSD_API *DNSServiceResolveReply) * is not initialized). */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceResolve ( DNSServiceRef *sdRef, @@ -1730,6 +1763,7 @@ typedef void (DNSSD_API *DNSServiceQueryRecordReply) * is not initialized). */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceQueryRecord ( DNSServiceRef *sdRef, @@ -1834,6 +1868,7 @@ typedef void (DNSSD_API *DNSServiceGetAddrInfoReply) * the error that occurred. */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo ( DNSServiceRef *sdRef, @@ -1870,6 +1905,7 @@ DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo * case the DNSServiceRef is not initialized). */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef); /* DNSServiceRegisterRecord @@ -1952,6 +1988,7 @@ typedef void (DNSSD_API *DNSServiceRegisterRecordReply) * not initialized). */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord ( DNSServiceRef sdRef, @@ -2001,6 +2038,7 @@ DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord * */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord ( DNSServiceFlags flags, @@ -2184,6 +2222,7 @@ typedef void (DNSSD_API *DNSServiceNATPortMappingReply) * display) then pass zero for protocol, internalPort, externalPort and ttl. */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate ( DNSServiceRef *sdRef, @@ -2230,6 +2269,7 @@ DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate * */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceConstructFullName ( char * const fullName, @@ -2310,6 +2350,7 @@ typedef union _TXTRecordRef_t { char PrivateData[16]; char *ForceNaturalAlignmen * the TXTRecordRef. */ +DNSSD_EXPORT void DNSSD_API TXTRecordCreate ( TXTRecordRef *txtRecord, @@ -2328,6 +2369,7 @@ void DNSSD_API TXTRecordCreate * */ +DNSSD_EXPORT void DNSSD_API TXTRecordDeallocate ( TXTRecordRef *txtRecord @@ -2371,6 +2413,7 @@ void DNSSD_API TXTRecordDeallocate * exceed the available storage. */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API TXTRecordSetValue ( TXTRecordRef *txtRecord, @@ -2394,6 +2437,7 @@ DNSServiceErrorType DNSSD_API TXTRecordSetValue * exist in the TXTRecordRef. */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API TXTRecordRemoveValue ( TXTRecordRef *txtRecord, @@ -2413,6 +2457,7 @@ DNSServiceErrorType DNSSD_API TXTRecordRemoveValue * Returns 0 if the TXTRecordRef is empty. */ +DNSSD_EXPORT uint16_t DNSSD_API TXTRecordGetLength ( const TXTRecordRef *txtRecord @@ -2430,6 +2475,7 @@ uint16_t DNSSD_API TXTRecordGetLength * to DNSServiceUpdateRecord(). */ +DNSSD_EXPORT const void * DNSSD_API TXTRecordGetBytesPtr ( const TXTRecordRef *txtRecord @@ -2484,6 +2530,7 @@ const void * DNSSD_API TXTRecordGetBytesPtr * Otherwise, it returns 0. */ +DNSSD_EXPORT int DNSSD_API TXTRecordContainsKey ( uint16_t txtLen, @@ -2513,6 +2560,7 @@ int DNSSD_API TXTRecordContainsKey * For non-empty value, valueLen will be length of value data. */ +DNSSD_EXPORT const void * DNSSD_API TXTRecordGetValuePtr ( uint16_t txtLen, @@ -2535,6 +2583,7 @@ const void * DNSSD_API TXTRecordGetValuePtr * */ +DNSSD_EXPORT uint16_t DNSSD_API TXTRecordGetCount ( uint16_t txtLen, @@ -2580,6 +2629,7 @@ uint16_t DNSSD_API TXTRecordGetCount * TXTRecordGetCount()-1. */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex ( uint16_t txtLen, @@ -2632,6 +2682,7 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex * queue param is invalid */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue ( DNSServiceRef service, @@ -2646,6 +2697,7 @@ typedef void (DNSSD_API *DNSServiceSleepKeepaliveReply) DNSServiceErrorType errorCode, void *context ); +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive ( DNSServiceRef *sdRef, diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd_private.h b/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd_private.h index ccec1403d0..2d42973361 100644 --- a/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd_private.h +++ b/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd_private.h @@ -1,11 +1,12 @@ /* -*- Mode: C; tab-width: 4 -*- - * - * Copyright (c) 2015 Apple Inc. All rights reserved. + * + * Copyright (c) 2015-2018 Apple Inc. All rights reserved. */ #ifndef _DNS_SD_PRIVATE_H #define _DNS_SD_PRIVATE_H +#include <dns_sd.h> // Private flags (kDNSServiceFlagsPrivateOne, kDNSServiceFlagsPrivateTwo, kDNSServiceFlagsPrivateThree, kDNSServiceFlagsPrivateFour) from dns_sd.h enum @@ -58,6 +59,7 @@ enum * returned to indicate that the calling process does not have entitlements * to use this API. */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid); #endif @@ -77,12 +79,16 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef * * if the daemon is not running. The value of the pid is undefined if the return * value has error. */ +DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceGetPID ( uint16_t srcport, int32_t *pid ); +DNSSD_EXPORT +DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain); + #define kDNSServiceCompPrivateDNS "PrivateDNS" #define kDNSServiceCompMulticastDNS "MulticastDNS" diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_clientlib.c b/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_clientlib.c index 649d403f02..1b4c5f8a54 100644 --- a/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_clientlib.c +++ b/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_clientlib.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2004-2011 Apple Inc. All rights reserved. + * Copyright (c) 2004-2018 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -31,10 +31,6 @@ #include "dns_sd.h" -#if MDNS_BUILDINGSHAREDLIBRARY || MDNS_BUILDINGSTUBLIBRARY -#pragma export on -#endif - #if defined(_WIN32) // disable warning "conversion from <data> to uint16_t" #pragma warning(disable:4244) @@ -361,10 +357,18 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) # s #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) +// The "used" variable attribute prevents a non-exported variable from being stripped, even if its visibility is hidden, +// e.g., when compiling with -fvisibility=hidden. +#if defined(__GNUC__) +#define DNSSD_USED __attribute__((used)) +#else +#define DNSSD_USED +#endif + // NOT static -- otherwise the compiler may optimize it out // The "@(#) " pattern is a special prefix the "what" command looks for #ifndef MDNS_VERSIONSTR_NODTS -const char VersionString_SCCS_libdnssd[] = "@(#) libdns_sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; +const char VersionString_SCCS_libdnssd[] DNSSD_USED = "@(#) libdns_sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; #else const char VersionString_SCCS_libdnssd[] = "@(#) libdns_sd " STRINGIFY(mDNSResponderVersion); #endif diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_clientstub.c b/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_clientstub.c index e943c47f80..189c9361fa 100644 --- a/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_clientstub.c +++ b/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_clientstub.c @@ -28,6 +28,7 @@ #include <errno.h> #include <stdlib.h> +#include <fcntl.h> #include "dnssd_ipc.h" @@ -80,7 +81,7 @@ static void syslog( int priority, const char * message, ...) } #else - #include <fcntl.h> // For O_RDWR etc. + #include <sys/fcntl.h> // For O_RDWR etc. #include <sys/time.h> #include <sys/socket.h> #include <syslog.h> @@ -628,7 +629,7 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f } #define deliver_request_bailout(MSG) \ - do { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: %s failed %d (%s)", (MSG), dnssd_errno, dnssd_strerror(dnssd_errno)); goto cleanup; } while(0) + syslog(LOG_WARNING, "dnssd_clientstub deliver_request: %s failed %d (%s)", (MSG), dnssd_errno, dnssd_strerror(dnssd_errno)); goto cleanup static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) { @@ -674,14 +675,22 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) dnssd_sockaddr_t caddr; dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr); listenfd = socket(AF_DNSSD, SOCK_STREAM, 0); - if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("TCP socket"); + if (!dnssd_SocketValid(listenfd)) { + deliver_request_bailout("TCP socket"); + } caddr.sin_family = AF_INET; caddr.sin_port = 0; caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR); - if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) deliver_request_bailout("TCP bind"); - if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) deliver_request_bailout("TCP getsockname"); - if (listen(listenfd, 1) < 0) deliver_request_bailout("TCP listen"); + if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) { + deliver_request_bailout("TCP bind"); + } + if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) { + deliver_request_bailout("TCP getsockname"); + } + if (listen(listenfd, 1) < 0) { + deliver_request_bailout("TCP listen"); + } port.s = caddr.sin_port; data[0] = port.b[0]; // don't switch the byte order, as the data[1] = port.b[1]; // daemon expects it in network byte order @@ -692,7 +701,9 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) int bindresult; dnssd_sockaddr_t caddr; listenfd = socket(AF_DNSSD, SOCK_STREAM, 0); - if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET socket"); + if (!dnssd_SocketValid(listenfd)) { + deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET socket"); + } caddr.sun_family = AF_LOCAL; // According to Stevens (section 3.2), there is no portable way to @@ -704,13 +715,19 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) mask = umask(0); bindresult = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)); umask(mask); - if (bindresult < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET bind"); - if (listen(listenfd, 1) < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET listen"); + if (bindresult < 0) { + deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET bind"); + } + if (listen(listenfd, 1) < 0) { + deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET listen"); + } } #else { dnssd_sock_t sp[2]; - if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0) deliver_request_bailout("socketpair"); + if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0) { + deliver_request_bailout("socketpair"); + } else { errsd = sp[0]; // We'll read our four-byte error code from sp[0] @@ -776,8 +793,9 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) if ((err = set_waitlimit(listenfd, DNSSD_CLIENT_TIMEOUT)) != kDNSServiceErr_NoError) goto cleanup; errsd = accept(listenfd, (struct sockaddr *)&daddr, &len); - if (!dnssd_SocketValid(errsd)) + if (!dnssd_SocketValid(errsd)) { deliver_request_bailout("accept"); + } #else struct iovec vec = { ((char *)hdr) + sizeof(ipc_msg_hdr) + datalen, 1 }; // Send the last byte along with the SCM_RIGHTS @@ -1330,7 +1348,7 @@ DNSServiceErrorType DNSSD_API DNSServiceResolve if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny()) flags |= kDNSServiceFlagsIncludeP2P; - err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, callBack, context); + err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, (void *)callBack, context); if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL // Calculate total message length @@ -1396,7 +1414,7 @@ DNSServiceErrorType DNSSD_API DNSServiceQueryRecord if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny()) flags |= kDNSServiceFlagsIncludeP2P; - err = ConnectToServer(sdRef, flags, query_request, handle_query_response, callBack, context); + err = ConnectToServer(sdRef, flags, query_request, handle_query_response, (void *)callBack, context); if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL if (!name) name = "\0"; @@ -1504,7 +1522,7 @@ DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo if (!sdRef || !hostname || !callBack) return kDNSServiceErr_BadParam; - err = ConnectToServer(sdRef, flags, addrinfo_request, handle_addrinfo_response, callBack, context); + err = ConnectToServer(sdRef, flags, addrinfo_request, handle_addrinfo_response, (void *)callBack, context); if (err) { return err; // On error ConnectToServer leaves *sdRef set to NULL @@ -1562,7 +1580,7 @@ DNSServiceErrorType DNSSD_API DNSServiceBrowse if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny()) flags |= kDNSServiceFlagsIncludeP2P; - err = ConnectToServer(sdRef, flags, browse_request, handle_browse_response, callBack, context); + err = ConnectToServer(sdRef, flags, browse_request, handle_browse_response, (void *)callBack, context); if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL if (!domain) domain = ""; @@ -1584,7 +1602,6 @@ DNSServiceErrorType DNSSD_API DNSServiceBrowse return err; } -DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain); DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain) { DNSServiceErrorType err; @@ -1654,7 +1671,7 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny()) flags |= kDNSServiceFlagsIncludeP2P; - err = ConnectToServer(sdRef, flags, reg_service_request, callBack ? handle_regservice_response : NULL, callBack, context); + err = ConnectToServer(sdRef, flags, reg_service_request, callBack ? handle_regservice_response : NULL, (void *)callBack, context); if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL len = sizeof(DNSServiceFlags); @@ -1714,7 +1731,7 @@ DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0; if (f1 + f2 != 1) return kDNSServiceErr_BadParam; - err = ConnectToServer(sdRef, flags, enumeration_request, handle_enumeration_response, callBack, context); + err = ConnectToServer(sdRef, flags, enumeration_request, handle_enumeration_response, (void *)callBack, context); if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL len = sizeof(DNSServiceFlags); @@ -2211,7 +2228,7 @@ DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate union { uint16_t s; u_char b[2]; } internalPort = { internalPortInNetworkByteOrder }; union { uint16_t s; u_char b[2]; } externalPort = { externalPortInNetworkByteOrder }; - DNSServiceErrorType err = ConnectToServer(sdRef, flags, port_mapping_request, handle_port_mapping_response, callBack, context); + DNSServiceErrorType err = ConnectToServer(sdRef, flags, port_mapping_request, handle_port_mapping_response, (void *)callBack, context); if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL len = sizeof(flags); @@ -2413,7 +2430,7 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive ka = malloc(sizeof(SleepKAContext)); if (!ka) return kDNSServiceErr_NoMemory; - ka->AppCallback = callBack; + ka->AppCallback = (void *)callBack; ka->AppContext = context; err = DNSServiceCreateConnection(sdRef); diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/mDNSDebug.c b/usr/src/contrib/mDNSResponder/mDNSShared/mDNSDebug.c index 3f78384c81..e76ae419bb 100644 --- a/usr/src/contrib/mDNSResponder/mDNSShared/mDNSDebug.c +++ b/usr/src/contrib/mDNSResponder/mDNSShared/mDNSDebug.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2003-2015 Apple Inc. All rights reserved. + * Copyright (c) 2003-2018 Apple Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -77,6 +77,7 @@ void LogMsg_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_MSG) void LogOperation_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_OPERATION) void LogSPS_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_SPS) void LogInfo_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_INFO) +void LogDebug_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_DEBUG) #endif #if MDNS_DEBUGMSGS diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/uds_daemon.c b/usr/src/contrib/mDNSResponder/mDNSShared/uds_daemon.c index de30ef13a1..35b65f6608 100644 --- a/usr/src/contrib/mDNSResponder/mDNSShared/uds_daemon.c +++ b/usr/src/contrib/mDNSResponder/mDNSShared/uds_daemon.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2003-2015 Apple Inc. All rights reserved. + * Copyright (c) 2003-2018 Apple Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +41,9 @@ // not fully qualified) with any number of labels e.g., moon, moon.cs, moon.cs.be, etc. mDNSBool AlwaysAppendSearchDomains = mDNSfalse; +// Control enabling ioptimistic DNS +mDNSBool EnableAllowExpired = mDNStrue; + // Apple-specific functionality, not required for other platforms #if APPLE_OSX_mDNSResponder #include <sys/ucred.h> @@ -325,8 +328,8 @@ mDNSlocal void abort_request(request_state *req) // Now, if this request_state is not subordinate to some other primary, close file descriptor and discard replies if (!req->primary) { - if (req->errsd != req->sd) LogOperation("%3d: Removing FD and closing errsd %d", req->sd, req->errsd); - else LogOperation("%3d: Removing FD", req->sd); + if (req->errsd != req->sd) LogDebug("%3d: Removing FD and closing errsd %d", req->sd, req->errsd); + else LogDebug("%3d: Removing FD", req->sd); 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; } @@ -1079,7 +1082,7 @@ mDNSlocal void connection_termination(request_state *request) mDNSlocal void handle_cancel_request(request_state *request) { request_state **req = &all_requests; - LogOperation("%3d: Cancel %08X %08X", request->sd, request->hdr.client_context.u32[1], request->hdr.client_context.u32[0]); + LogDebug("%3d: Cancel %08X %08X", request->sd, request->hdr.client_context.u32[1], request->hdr.client_context.u32[0]); while (*req) { if ((*req)->primary == request && @@ -1691,7 +1694,7 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain &request->u.servicereg.name, &request->u.servicereg.type, domain, request->u.servicereg.host.c[0] ? &request->u.servicereg.host : NULL, request->u.servicereg.port, - request->u.servicereg.txtdata, request->u.servicereg.txtlen, + mDNSNULL, request->u.servicereg.txtdata, request->u.servicereg.txtlen, instance->subtypes, request->u.servicereg.num_subtypes, interfaceID, regservice_callback, instance, request->flags); @@ -2168,7 +2171,7 @@ mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d { domainname tmp; ConstructServiceName(&tmp, NULL, &info->u.browser.regtype, &b->domain); - LogInfo("add_domain_to_browser: calling external_start_browsing_for_service()"); + LogDebug("add_domain_to_browser: calling external_start_browsing_for_service()"); external_start_browsing_for_service(info->u.browser.interface_id, &tmp, kDNSType_PTR, info->flags); } } @@ -3164,7 +3167,7 @@ mDNSlocal mDNSBool RetryQuestionWithSearchDomains(DNSQuestion *question, request } else { - LogInfo("%3d: RetryQuestionWithSearchDomains: Not appending search domains - SuppressQuery %d, SearchListIndex %d, AppendSearchDomains %d", req->sd, AddRecord, question->SearchListIndex, question->AppendSearchDomains); + LogDebug("%3d: RetryQuestionWithSearchDomains: Not appending search domains - SuppressQuery %d, SearchListIndex %d, AppendSearchDomains %d", req->sd, AddRecord, question->SearchListIndex, question->AppendSearchDomains); } return mDNSfalse; } @@ -3180,10 +3183,11 @@ mDNSlocal void queryrecord_result_reply(mDNS *const m, request_state *req, DNSQu ConvertDomainNameToCString(answer->name, name); - LogOperation("%3d: %s(%##s, %s) RESULT %s interface %d: %s", req->sd, + LogOperation("%3d: %s(%##s, %s) RESULT %s interface %d: (%s)%s", req->sd, req->hdr.op == query_request ? "DNSServiceQueryRecord" : "DNSServiceGetAddrInfo", question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", - mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse), RRDisplayString(m, answer)); + mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse), + MortalityDisplayString(answer->mortality), RRDisplayString(m, answer)); len = sizeof(DNSServiceFlags); // calculate reply data length len += sizeof(mDNSu32); // interface index @@ -3197,6 +3201,8 @@ mDNSlocal void queryrecord_result_reply(mDNS *const m, request_state *req, DNSQu if (AddRecord) flags |= kDNSServiceFlagsAdd; + if (answer->mortality == Mortality_Ghost) + flags |= kDNSServiceFlagsExpiredAnswer; if (question->ValidationStatus != 0) { error = kDNSServiceErr_NoError; @@ -3454,7 +3460,7 @@ mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question, // the "core" needs to temporarily turn off SuppressQuery to answer this query. if (AddRecord == QC_suppressed) { - LogInfo("queryrecord_result_callback: Suppressed question %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); + LogDebug("queryrecord_result_callback: Suppressed question %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); queryrecord_result_reply(m, req, question, answer, AddRecord, kDNSServiceErr_NoSuchRecord); return; } @@ -3519,7 +3525,7 @@ mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question, // appended .local, we need to see if we need to send an additional query. This should // normally happen just once because after we append .local, we ignore all negative // responses for .local above. - LogInfo("queryrecord_result_callback: Retrying question %##s (%s) after appending search domains", question->qname.c, DNSTypeName(question->qtype)); + LogDebug("queryrecord_result_callback: Retrying question %##s (%s) after appending search domains", question->qname.c, DNSTypeName(question->qtype)); if (RetryQuestionWithSearchDomains(question, req, AddRecord)) { // Note: We need to call SendAdditionalQuery every time after appending a search domain as .local could @@ -3648,34 +3654,35 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request) request->interfaceIndex = interfaceIndex; mDNSPlatformMemZero(&request->u.queryrecord, sizeof(request->u.queryrecord)); - q->InterfaceID = InterfaceID; - q->flags = flags; - q->Target = zeroAddr; + q->InterfaceID = InterfaceID; + q->flags = flags; + q->Target = zeroAddr; if (!MakeDomainNameFromDNSNameString(&q->qname, name)) return(mStatus_BadParamErr); #if 0 if (!AuthorizedDomain(request, &q->qname, AutoBrowseDomains)) return (mStatus_NoError); #endif - q->qtype = rrtype; - q->qclass = rrclass; - q->LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0; - q->ExpectUnique = mDNSfalse; - q->ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0; - q->ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0; - q->SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable ) != 0; - q->TimeoutQuestion = (flags & kDNSServiceFlagsTimeout ) != 0; - q->WakeOnResolve = 0; + q->qtype = rrtype; + q->qclass = rrclass; + q->LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0; + q->ExpectUnique = mDNSfalse; + q->ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0; + q->ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0; + q->SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable ) != 0; + q->TimeoutQuestion = (flags & kDNSServiceFlagsTimeout ) != 0; + q->allowExpired = (EnableAllowExpired && (flags & kDNSServiceFlagsAllowExpiredAnswers) != 0) ? AllowExpired_AllowExpiredAnswers : AllowExpired_None; + q->WakeOnResolve = 0; q->UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0; if ((flags & kDNSServiceFlagsValidate) != 0) q->ValidationRequired = DNSSEC_VALIDATION_SECURE; else if ((flags & kDNSServiceFlagsValidateOptional) != 0) q->ValidationRequired = DNSSEC_VALIDATION_SECURE_OPTIONAL; q->ValidatingResponse = 0; - q->ProxyQuestion = 0; + q->ProxyQuestion = 0; q->AnonInfo = mDNSNULL; - q->QuestionCallback = queryrecord_result_callback; - q->QuestionContext = request; - q->SearchListIndex = 0; - q->StopTime = 0; + q->QuestionCallback = queryrecord_result_callback; + q->QuestionContext = request; + q->SearchListIndex = 0; + q->StopTime = 0; q->DNSSECAuthInfo = mDNSNULL; q->DAIFreeCallback = mDNSNULL; @@ -3739,7 +3746,7 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request) LogMcastQ(q, request, q_start); if (callExternalHelpers(q->InterfaceID, &q->qname, q->flags)) { - LogInfo("handle_queryrecord_request: calling external_start_browsing_for_service()"); + LogDebug("handle_queryrecord_request: calling external_start_browsing_for_service()"); external_start_browsing_for_service(q->InterfaceID, &q->qname, q->qtype, q->flags); } } @@ -4260,7 +4267,7 @@ mDNSlocal void addrinfo_termination_callback(request_state *request) if (callExternalHelpers(request->u.addrinfo.interface_id, &request->u.addrinfo.q4.qname, request->flags)) { - LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for kDNSServiceType_A record"); + LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for A record"); external_stop_browsing_for_service(request->u.addrinfo.interface_id, &request->u.addrinfo.q4.qname, kDNSServiceType_A, request->flags); } } @@ -4295,7 +4302,7 @@ mDNSlocal void addrinfo_termination_callback(request_state *request) if (callExternalHelpers(request->u.addrinfo.interface_id, &request->u.addrinfo.q6.qname, request->flags)) { - LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for kDNSServiceType_AAAA record"); + LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for AAAA record"); external_stop_browsing_for_service(request->u.addrinfo.interface_id, &request->u.addrinfo.q6.qname, kDNSServiceType_AAAA, request->flags); } } @@ -4425,19 +4432,20 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) 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.ServiceID = request->u.addrinfo.q6.ServiceID = serviceIndex; - request->u.addrinfo.q4.flags = request->u.addrinfo.q6.flags = flags; - 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; - request->u.addrinfo.q4.TimeoutQuestion = request->u.addrinfo.q6.TimeoutQuestion = (flags & kDNSServiceFlagsTimeout ) != 0; - request->u.addrinfo.q4.WakeOnResolve = request->u.addrinfo.q6.WakeOnResolve = 0; + request->u.addrinfo.q4.InterfaceID = request->u.addrinfo.q6.InterfaceID = request->u.addrinfo.interface_id; + request->u.addrinfo.q4.ServiceID = request->u.addrinfo.q6.ServiceID = serviceIndex; + request->u.addrinfo.q4.flags = request->u.addrinfo.q6.flags = flags; + 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; + request->u.addrinfo.q4.TimeoutQuestion = request->u.addrinfo.q6.TimeoutQuestion = (flags & kDNSServiceFlagsTimeout ) != 0; + request->u.addrinfo.q4.allowExpired = request->u.addrinfo.q6.allowExpired = (EnableAllowExpired && (flags & kDNSServiceFlagsAllowExpiredAnswers) != 0) ? AllowExpired_AllowExpiredAnswers : AllowExpired_None; + request->u.addrinfo.q4.WakeOnResolve = request->u.addrinfo.q6.WakeOnResolve = 0; request->u.addrinfo.q4.UseBackgroundTrafficClass = request->u.addrinfo.q6.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0; if ((flags & kDNSServiceFlagsValidate) != 0) request->u.addrinfo.q4.ValidationRequired = request->u.addrinfo.q6.ValidationRequired = DNSSEC_VALIDATION_SECURE; @@ -4499,7 +4507,7 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) LogMcastQ(&request->u.addrinfo.q6, request, q_start); if (callExternalHelpers(InterfaceID, &d, flags)) { - LogInfo("handle_addrinfo_request: calling external_start_browsing_for_service() for kDNSServiceType_AAAA record"); + LogDebug("handle_addrinfo_request: calling external_start_browsing_for_service() for AAAA record"); external_start_browsing_for_service(InterfaceID, &d, kDNSServiceType_AAAA, flags); } } @@ -4541,7 +4549,7 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) if (callExternalHelpers(InterfaceID, &d, flags)) { - LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for kDNSServiceType_AAAA record"); + LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for AAAA record"); external_stop_browsing_for_service(InterfaceID, &d, kDNSServiceType_AAAA, flags); } } @@ -4555,7 +4563,7 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) LogMcastQ(&request->u.addrinfo.q4, request, q_start); if (callExternalHelpers(InterfaceID, &d, flags)) { - LogInfo("handle_addrinfo_request: calling external_start_browsing_for_service() for kDNSServiceType_A record"); + LogDebug("handle_addrinfo_request: calling external_start_browsing_for_service() for A record"); external_start_browsing_for_service(InterfaceID, &d, kDNSServiceType_A, flags); } } @@ -4755,7 +4763,7 @@ mDNSlocal void read_msg(request_state *req) #if !defined(USE_TCP_LOOPBACK) got_errfd: #endif - LogOperation("%3d: Result code socket %d created %08X %08X", req->sd, req->errsd, req->hdr.client_context.u32[1], req->hdr.client_context.u32[0]); + LogDebug("%3d: Result code 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) #else @@ -4954,8 +4962,8 @@ mDNSlocal void request_callback(int fd, short filter, void *info) send_all(req->errsd, (const char *)&err_netorder, sizeof(err_netorder)); if (req->errsd != req->sd) { - LogOperation("%3d: Result code socket %d closed %08X %08X (%d)", - req->sd, req->errsd, req->hdr.client_context.u32[1], req->hdr.client_context.u32[0], err); + LogDebug("%3d: Result code socket %d closed %08X %08X (%d)", + req->sd, req->errsd, req->hdr.client_context.u32[1], req->hdr.client_context.u32[0], err); dnssd_close(req->errsd); req->errsd = req->sd; // Also need to reset the parent's errsd, if this is a subordinate operation @@ -5026,7 +5034,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: connect_callback: Adding FD for uid %u", request->sd, request->uid); + LogDebug("%3d: connect_callback: Adding FD for uid %u", request->sd, request->uid); udsSupportAddFDToEventLoop(sd, request_callback, request, &request->platform_data); } } @@ -5087,7 +5095,7 @@ mDNSexport int udsserver_init(dnssd_sock_t skts[], mDNSu32 count) FILE *fp = fopen(PID_FILE, "w"); if (fp != NULL) { - fprintf(fp, "%d\n", getpid()); + fprintf(fp, "%d\n", (int)getpid()); fclose(fp); } } @@ -6256,10 +6264,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) <= 2954) ? 1 : -1]; + char sizecheck_request_state [(sizeof(request_state) <= 3696) ? 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) <= 1202) ? 1 : -1]; + char sizecheck_browser_t [(sizeof(browser_t) <= 1432) ? 1 : -1]; char sizecheck_reply_hdr [(sizeof(reply_hdr) <= 12) ? 1 : -1]; char sizecheck_reply_state [(sizeof(reply_state) <= 64) ? 1 : -1]; }; |