#include <arpa/inet.h> // For inet_addr()
#include <net/if.h> // For if_nametoindex()
static const char kFilePathSep = '/';
-// #ifndef NOT_HAVE_SA_LEN
-// #define SA_LEN(addr) ((addr)->sa_len)
-// #else
- #define SA_LEN(addr) (((addr)->sa_family == AF_INET6)? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))
-// #endif
+ #define SA_LEN(addr) ((addr)->sa_len)
#endif
#if (TEST_NEW_CLIENTSTUB && !defined(__APPLE_API_PRIVATE))
include /Developer/Makefiles/pb_makefiles/platform.make
-MVERS = "mDNSResponder-320.10.80"
+MVERS = "mDNSResponder-320.14.0"
DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig"
// *not* on a Microsoft Active Directory network, and there is no authoritative server for "local". Note that this is not
// in conflict with the mDNS spec, because that spec says, "Multicast DNS Zones have no SOA record," so it's okay to cache
// negative answers for "local. SOA" from a uDNS server, because the mDNS spec already says that such records do not exist :-)
+ //
+ // By suppressing negative responses, it might take longer to timeout a .local question as it might be expecting a
+ // response e.g., we deliver a positive "A" response and suppress negative "AAAA" response and the upper layer may
+ // be waiting longer to get the AAAA response before returning the "A" response to the application. To handle this
+ // case without creating the negative cache entries, we generate a negative response and let the layer above us
+ // do the appropriate thing. This negative response is also needed for appending new search domains.
if (!InterfaceID && q.qtype != kDNSType_SOA && IsLocalDomain(&q.qname))
{
- // If we did not find a positive answer and we can append search domains to this question,
- // generate a negative response (without creating a cache entry) to append search domains.
- if (qptr->AppendSearchDomains && !rr)
+ if (!rr)
{
LogInfo("mDNSCoreReceiveResponse: Generate negative response for %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
m->CurrentQuestion = qptr;
}
}
+// Check for a positive unicast response to the question but with qtype
+mDNSexport mDNSBool mDNS_CheckForCacheRecord(mDNS *const m, DNSQuestion *q, mDNSu16 qtype)
+ {
+ DNSQuestion question;
+ const mDNSu32 slot = HashSlot(&q->qname);
+ CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ CacheRecord *rp;
+
+ // Create an identical question but with qtype
+ mDNS_SetupQuestion(&question, q->InterfaceID, &q->qname, qtype, mDNSNULL, mDNSNULL);
+ question.qDNSServer = q->qDNSServer;
+
+ for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next)
+ {
+ if (!rp->resrec.InterfaceID && rp->resrec.RecordType != kDNSRecordTypePacketNegative &&
+ SameNameRecordAnswersQuestion(&rp->resrec, &question))
+ {
+ LogInfo("mDNS_CheckForCacheRecord: Found %s", CRDisplayString(m, rp));
+ return mDNStrue;
+ }
+ }
+ return mDNSfalse;
+ }
+
mDNSlocal void CacheRecordResetDNSServer(mDNS *const m, DNSQuestion *q, DNSServer *new)
{
const mDNSu32 slot = HashSlot(&q->qname);
#define MD5_LEN 16
#define AutoTunnelUnregistered(X) ( \
- (X)->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered && \
- (X)->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered && \
- (X)->AutoTunnelService. resrec.RecordType == kDNSRecordTypeUnregistered && \
- (X)->AutoTunnel6Record. resrec.RecordType == kDNSRecordTypeUnregistered )
+ (X)->AutoTunnelHostRecord. resrec.RecordType == kDNSRecordTypeUnregistered && \
+ (X)->AutoTunnelDeviceInfo. resrec.RecordType == kDNSRecordTypeUnregistered && \
+ (X)->AutoTunnelService. resrec.RecordType == kDNSRecordTypeUnregistered && \
+ (X)->AutoTunnel6Record. resrec.RecordType == kDNSRecordTypeUnregistered && \
+ (X)->AutoTunnel6MetaRecord.resrec.RecordType == kDNSRecordTypeUnregistered )
// Internal data structure to maintain authentication information
typedef struct DomainAuthInfo
AuthRecord AutoTunnelTarget; // Opaque hostname of tunnel endpoint; used as SRV target for AutoTunnelService record
AuthRecord AutoTunnelDeviceInfo; // Device info of tunnel endpoint
AuthRecord AutoTunnelService; // Service record (possibly NAT-Mapped) of IKE daemon implementing tunnel endpoint
- AuthRecord AutoTunnel6Record; // AutoTunnel AAAA Record obtained from Connectivityd
+ AuthRecord AutoTunnel6Record; // AutoTunnel AAAA record obtained from awacsd
+ AuthRecord AutoTunnel6MetaRecord; // Notify remote peers to connect to the relay servers for potential outbound connections from this host
NATTraversalInfo AutoTunnelNAT;
domainname domain;
domainname keyname;
extern AuthGroup *AuthGroupForRecord(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr);
extern AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr);
extern AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr);
+extern mDNSBool mDNS_CheckForCacheRecord(mDNS *const m, DNSQuestion *q, mDNSu16 qtype);
// For now this AutoTunnel stuff is specific to Mac OS X.
// In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
char sizecheck_DNSServer [(sizeof(DNSServer) <= 320) ? 1 : -1];
char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 6850) ? 1 : -1];
char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 5500) ? 1 : -1];
- char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 7808) ? 1 : -1];
+ char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 7968) ? 1 : -1];
char sizecheck_ServiceInfoQuery [(sizeof(ServiceInfoQuery) <= 3200) ? 1 : -1];
#if APPLE_OSX_mDNSResponder
char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1148) ? 1 : -1];
// Caution: Only zero AutoTunnelHostRecord.namestorage and AutoTunnelNAT.clientContext AFTER we've determined that this is a NEW DomainAuthInfo
// being added to the list. Otherwise we risk smashing our AutoTunnel host records and NATOperation that are already active and in use.
- info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
- info->AutoTunnelHostRecord.namestorage.c[0] = 0;
- info->AutoTunnelTarget .resrec.RecordType = kDNSRecordTypeUnregistered;
- info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
- info->AutoTunnelService .resrec.RecordType = kDNSRecordTypeUnregistered;
- info->AutoTunnel6Record .resrec.RecordType = kDNSRecordTypeUnregistered;
+ info->AutoTunnelHostRecord .resrec.RecordType = kDNSRecordTypeUnregistered;
+ info->AutoTunnelHostRecord .namestorage.c[0] = 0;
+ info->AutoTunnelTarget .resrec.RecordType = kDNSRecordTypeUnregistered;
+ info->AutoTunnelDeviceInfo .resrec.RecordType = kDNSRecordTypeUnregistered;
+ info->AutoTunnelService .resrec.RecordType = kDNSRecordTypeUnregistered;
+ info->AutoTunnel6Record .resrec.RecordType = kDNSRecordTypeUnregistered;
+ info->AutoTunnel6MetaRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
info->AutoTunnelNAT.clientContext = mDNSNULL;
info->next = mDNSNULL;
*p = info;
mDNSexport domainname ActiveDirectoryPrimaryDomain;
mDNSexport int ActiveDirectoryPrimaryDomainLabelCount;
mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer;
+
+static mDNSBool AWACSDConnected = mDNSfalse;
#endif // APPLE_OSX_mDNSResponder
// Used by AutoTunnel
}
#endif
+// pre-declaration
+mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
+
+// Notify remote peers to connect to the relay servers for potential outbound connections from this host.
+// Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
+// sometimes the caller may already be holding the lock e.g., SetupLocalAutoTunnelInterface_internal and sometimes
+// not e.g., AutoTunnelHostNameChanged
+mDNSlocal void RegisterAutoTunnel6MetaRecord(mDNS *m, DomainAuthInfo *info)
+ {
+ mStatus err;
+
+ if (!m->mDNS_busy) LogMsg("RegisterAutoTunnel6MetaRecord: ERROR!! Lock not held");
+
+ if (!AWACSDConnected)
+ {
+ LogInfo("RegisterAutoTunnel6MetaRecord no need to register");
+ return;
+ }
+
+ if (info->AutoTunnel6MetaRecord.resrec.RecordType == kDNSRecordTypeUnregistered)
+ {
+ mDNS_SetupResourceRecord(&info->AutoTunnel6MetaRecord, mDNSNULL, mDNSInterface_Any, kDNSType_PTR, kStandardTTL, kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
+ AssignDomainName (&info->AutoTunnel6MetaRecord.namestorage, (const domainname*) "\x0C" "_autotunnel6");
+ AppendDomainName (&info->AutoTunnel6MetaRecord.namestorage, &info->domain);
+
+ info->AutoTunnel6MetaRecord.resrec.rdata->u.name.c[0] = 0;
+ AppendDomainLabel(&info->AutoTunnel6MetaRecord.resrec.rdata->u.name, &m->hostlabel);
+ AppendDomainName (&info->AutoTunnel6MetaRecord.resrec.rdata->u.name, &info->domain);
+ info->AutoTunnel6MetaRecord.resrec.RecordType = kDNSRecordTypeShared;
+
+ err = mDNS_Register_internal(m, &info->AutoTunnel6MetaRecord);
+ if (err) LogMsg("RegisterAutoTunnel6MetaRecord error %d registering %##s", err, info->AutoTunnel6MetaRecord.namestorage.c);
+ else LogInfo("RegisterAutoTunnel6MetaRecord registering %##s %##s", info->AutoTunnel6MetaRecord.namestorage.c, info->AutoTunnel6MetaRecord.resrec.rdata->u.name.c);
+ }
+ }
// Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
// sometimes the caller may already be holding the lock e.g., SetupLocalAutoTunnelInterface_internal and sometimes
UpdateAutoTunnelDomainStatus(m, info);
}
+mDNSlocal void DeregisterAutoTunnel6MetaRecord(mDNS *m, DomainAuthInfo *info)
+ {
+ LogInfo("DeregisterAutoTunnel6MetaRecord %##s", info->domain.c);
+
+ if (info->AutoTunnel6MetaRecord.resrec.RecordType > kDNSRecordTypeDeregistering)
+ {
+ mStatus err = mDNS_Deregister(m, &info->AutoTunnel6MetaRecord);
+ if (err)
+ {
+ info->AutoTunnel6MetaRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
+ info->AutoTunnel6MetaRecord.resrec.rdata->u.name.c[0] = 0;
+ LogMsg("DeregisterAutoTunnel6MetaRecord error %d deregistering %##s", err, info->AutoTunnel6MetaRecord.namestorage.c);
+ }
+ else LogInfo("DeregisterAutoTunnel6MetaRecord: Deregistered record");
+ }
+ else LogInfo("DeregisterAutoTunnel6MetaRecord: Not deregistering record state:%d", info->AutoTunnel6MetaRecord.resrec.RecordType);
+ }
+
mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
{
LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c);
info->AutoTunnel6Record.resrec.rdata->u.ipv6 = zerov6Addr;
RegisterAutoTunnel6Record(m,info);
}
+ else if (rr == &info->AutoTunnel6MetaRecord)
+ {
+ LogInfo("AutoTunnelRecordCallback: Calling RegisterAutoTunnel6MetaRecord");
+ info->AutoTunnel6MetaRecord.resrec.rdata->u.name.c[0] = 0;
+ RegisterAutoTunnel6MetaRecord(m,info);
+ }
}
}
DeregisterAutoTunnelDevInfoRecord(m, info);
DeregisterAutoTunnelServiceRecords(m, info);
DeregisterAutoTunnel6Record(m, info);
+ DeregisterAutoTunnel6MetaRecord(m, info);
UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
UpdateAutoTunnelDomainStatus(m, info);
}
#endif
DeregisterAutoTunnelServiceRecords(m, info);
DeregisterAutoTunnel6Record(m, info);
+ DeregisterAutoTunnel6MetaRecord(m, info);
RegisterAutoTunnelServiceRecords(m, info);
mDNS_Lock(m);
RegisterAutoTunnelDevInfoRecord(m, info);
RegisterAutoTunnel6Record(m, info);
+ RegisterAutoTunnel6MetaRecord(m, info);
m->NextSRVUpdate = NonZeroTime(m->timenow);
mDNS_Unlock(m);
}
{
DomainAuthInfo *BTMMDomain = mDNSNULL;
DomainAuthInfo *FoundInList;
- static mDNSBool AWACSDConnected = mDNSfalse;
char AllUsers[1024]; // maximum size of mach message
char AllPass[1024]; // maximum size of mach message
char username[MAX_DOMAIN_LABEL + 1];
LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers);
AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com");
AWACSDConnected = mDNStrue;
+
+ // We have to do this after AWACSDConnected is true
+ for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
+ if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain))
+ {
+ LogInfo("UpdateBTMMRelayConnection RegisterAutoTunnel6MetaRecord: %##s", FoundInList->domain.c);
+ RegisterAutoTunnel6MetaRecord(m, FoundInList);
+ }
}
else
{
// this case as though the dictionary does not have the value
RemoveAutoTunnel6Record(m);
// If awacsd crashes or exits for some reason, restart the relay connection
+ mDNS_Lock(m);
UpdateBTMMRelayConnection(m);
+ mDNS_Unlock(m);
return;
}
RemoveAutoTunnel6Record(m);
m->AutoTunnelRelayAddrOut = zerov6Addr;
// We don't have a utun interface, start the relay connection if possible
+ mDNS_Lock(m);
UpdateBTMMRelayConnection(m);
+ mDNS_Unlock(m);
}
else
{
len = strlen(buf);
if (!len) break; // sanity check
-
+ //Check for end of line code(mostly only \n but pre-OS X Macs could have only \r)
if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
+ {
buf[len - 1] = '\0';
-
+ len = len - 1;
+ }
// fgets always null terminates and hence even if we have no
- // newline at the end, it is null terminated. The callee expects
- // the length to be such that buf[length] to be zero and hence
- // we pass len - 1.
- mDNSMacOSXParseEtcHostsLine(m, buf, len - 1, auth);
+ // newline at the end, it is null terminated. The callee
+ // (mDNSMacOSXParseEtcHostsLine) expects the length to be such that
+ // buf[length] is zero and hence we decrement len to reflect that.
+ if (len)
+ {
+ //Additional check when end of line code is 2 chars ie\r\n(DOS, other old OSes)
+ //here we need to check for just \r but taking extra caution.
+ if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
+ {
+ buf[len - 1] = '\0';
+ len = len - 1;
+ }
+ }
+ if (!len) //Sanity Check: len should never be zero
+ {
+ LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
+ continue;
+ }
+ mDNSMacOSXParseEtcHostsLine(m, buf, len, auth);
}
fclose(fp);
}
if (StopNow == 2) break;
}
#endif
- else {
- if (strlen(arg) >= sizeof(hostname)) {
- fprintf(stderr, "hostname must be < %d characters\n", (int)sizeof(hostname));
- goto usage;
- }
+ else
strcpy(hostname, arg);
- }
// Now we have the host name; get its A, AAAA, and HINFO
if (hostname[0]) DoQuery(&q, hostname, kDNSQType_ANY, &target, InfoCallback);
return(0);
usage:
- fprintf(stderr, "Usage: %s <dot-local hostname> or <IPv4 address> or <IPv6 address> ...\n", progname);
+ fprintf(stderr, "%s <dot-local hostname> or <IPv4 address> or <IPv6 address> ...\n", progname);
return(-1);
}
endif
else
-# any target that contains the string "linux"
-ifeq ($(findstring linux,$(os)),linux)
-CFLAGS_OS = -D_GNU_SOURCE -DHAVE_IPV6 -DNOT_HAVE_SA_LEN -DUSES_NETLINK -DHAVE_LINUX -DTARGET_OS_LINUX -fno-strict-aliasing
-LD = gcc -shared
+ifeq ($(os),linux)
+CFLAGS_OS = -DNOT_HAVE_SA_LEN -DUSES_NETLINK -DHAVE_LINUX -DTARGET_OS_LINUX
FLEXFLAGS_OS = -l
JAVACFLAGS_OS += -I$(JDK)/include/linux
-
-# uClibc does not support Name Service Switch
-ifneq ($(os),linux-uclibc)
OPTIONALTARG = nss_mdns
OPTINSTALL = InstalledNSS
-endif
else
ifeq ($(os),netbsd)
ifeq ($(os),freebsd)
# If not already defined, set LOCALBASE to /usr/local
+# FreeBSD requires the startup script to end in ".sh"
LOCALBASE?=/usr/local
INSTBASE=$(LOCALBASE)
-CFLAGS_OS = -DHAVE_IPV6
+STARTUPSCRIPTNAME=mdns.sh
+CFLAGS_OS =
# FreeBSD 4 requires threaded code to be compiled and linked using the "-pthread" option,
# and requires that the "-lpthread" link option NOT be used
# This appies only to FreeBSD -- "man cc" on FreeBSD says:
# We have to define __MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 or on Leopard
# we get build failures: ‘daemon’ is deprecated (declared at /usr/include/stdlib.h:283)
CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Werror -Wdeclaration-after-statement \
- -D__MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 \
- -D__APPLE_USE_RFC_2292 #-Wunreachable-code
+ -D__MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 #-Wunreachable-code
CC = gcc
LD = $(CC) -dynamiclib
LINKOPTS = -lSystem
else
$(error ERROR: Must specify target OS on command-line, e.g. "make os=x [target]".\
-Supported operating systems include: x, linux, linux-uclibc, netbsd, freebsd, openbsd, solaris)
+Supported operating systems include: x, linux, netbsd, freebsd, openbsd, solaris)
endif
endif
endif
6 Aug 2002
-Impact: A local network user may cause a denial of the Bonjour service
-Description: An error handling issue exists in the Bonjour Namespace
-Provider. A local network user may send a maliciously crafted multicast
-DNS packet leading to an unexpected termination of the Bonjour service.
-This update addresses the issue by performing additional validation of
-multicast DNS packets. This issue does not affect systems running Mac OS
-X or Windows.
-CVE-ID
-CVE-2011-0220 : JaeSeung Song of the Department of Computing at Imperial
-College London
To Do List
----------
if (gMDNSPlatformPosixVerboseLevel > 0) {
fprintf(stderr,
- "%s: Registered service %d, name \"%s\", type \"%s\", domain \"%s\", port %ld\n",
+ "%s: Registered service %d, name '%s', type '%s', port %ld\n",
gProgramName,
thisServ->serviceID,
richTextName,
serviceType,
- serviceDomain,
portNumber);
}
} else {
return status;
}
-static mDNSBool ReadALine(char *buf, size_t bufSize, FILE *fp, mDNSBool skipBlankLines)
+static mDNSBool ReadALine(char *buf, size_t bufSize, FILE *fp)
+// Read a line, skipping over any blank lines or lines starting with '#'
{
- size_t len;
- mDNSBool readNextLine;
-
+ mDNSBool good, skip;
do {
- readNextLine = mDNSfalse;
-
- if (fgets(buf, bufSize, fp) == NULL)
- return mDNSfalse; // encountered EOF or an error condition
-
- // These first characters indicate a blank line.
- if (buf[0] == ' ' || buf[0] == '\t' || buf[0] == '\r' || buf[0] == '\n') {
- if (!skipBlankLines)
- return mDNSfalse;
- readNextLine = mDNStrue;
- }
- // always skip comment lines
- if (buf[0] == '#')
- readNextLine = mDNStrue;
-
- } while (readNextLine);
-
- len = strlen( buf);
- if ( buf[len - 1] == '\r' || buf[len - 1] == '\n')
- buf[len - 1] = '\0';
-
- return mDNStrue;
+ good = (fgets(buf, bufSize, fp) != NULL);
+ skip = (good && (buf[0] == '#'));
+ } while (good && skip);
+ if (good)
+ {
+ int len = strlen( buf);
+ if ( buf[len - 1] == '\r' || buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
+ }
+ return good;
}
static mStatus RegisterServicesInFile(const char *filePath)
{
mStatus status = mStatus_NoError;
FILE * fp = fopen(filePath, "r");
+ int junk;
if (fp == NULL) {
- return mStatus_UnknownErr;
+ status = mStatus_UnknownErr;
}
-
- if (gMDNSPlatformPosixVerboseLevel > 1)
- fprintf(stderr, "Parsing %s for services\n", filePath);
-
- do {
- char nameBuf[256];
- char * name = nameBuf;
- char type[256];
- const char *dom = kDefaultServiceDomain;
- char rawText[1024];
- mDNSu8 text[sizeof(RDataBody)];
- unsigned int textLen = 0;
- char port[256];
- char *p;
-
- // Read the service name, type, port, and optional text record fields.
- // Skip blank lines while looking for the next service name.
- if (! ReadALine(name, sizeof(nameBuf), fp, mDNStrue))
- break;
-
- // Special case that allows service name to begin with a '#'
- // character by escaping it with a '\' to distiguish it from
- // a comment line. Remove the leading '\' here before
- // registering the service.
- if (name[0] == '\\' && name[1] == '#')
- name++;
-
- if (gMDNSPlatformPosixVerboseLevel > 1)
- fprintf(stderr, "Service name: \"%s\"\n", name);
-
- // Don't skip blank lines in calls to ReadAline() after finding the
- // service name since the next blank line indicates the end
- // of this service record.
- if (! ReadALine(type, sizeof(type), fp, mDNSfalse))
- break;
-
- // see if a domain name is specified
- p = type;
- while (*p && *p != ' ' && *p != '\t') p++;
- if (*p) {
- *p = 0; // NULL terminate the <type>.<protocol> string
- // skip any leading whitespace before domain name
- p++;
- while (*p && (*p == ' ' || *p == '\t')) p++;
- if (*p)
- dom = p;
- }
- if (gMDNSPlatformPosixVerboseLevel > 1) {
- fprintf(stderr, "Service type: \"%s\"\n", type);
- fprintf(stderr, "Service domain: \"%s\"\n", dom);
- }
-
- if (! ReadALine(port, sizeof(port), fp, mDNSfalse))
- break;
- if (gMDNSPlatformPosixVerboseLevel > 1)
- fprintf(stderr, "Service port: %s\n", port);
-
- if ( ! CheckThatRichTextNameIsUsable(name, mDNStrue)
- || ! CheckThatServiceTypeIsUsable(type, mDNStrue)
- || ! CheckThatPortNumberIsUsable(atol(port), mDNStrue))
- break;
-
- // read the TXT record fields
- while (1) {
- int len;
- if (!ReadALine(rawText, sizeof(rawText), fp, mDNSfalse)) break;
- if (gMDNSPlatformPosixVerboseLevel > 1)
- fprintf(stderr, "Text string: \"%s\"\n", rawText);
- len = strlen(rawText);
- if (len <= 255)
- {
- unsigned int newlen = textLen + 1 + len;
- if (len == 0 || newlen >= sizeof(text)) break;
- text[textLen] = len;
- mDNSPlatformMemCopy(text + textLen + 1, rawText, len);
- textLen = newlen;
+ if (status == mStatus_NoError) {
+ mDNSBool good = mDNStrue;
+ do {
+ int ch;
+ char name[256];
+ char type[256];
+ const char *dom = kDefaultServiceDomain;
+ char rawText[1024];
+ mDNSu8 text[sizeof(RDataBody)];
+ unsigned int textLen = 0;
+ char port[256];
+
+ // Skip over any blank lines.
+ do ch = fgetc(fp); while ( ch == '\n' || ch == '\r' );
+ if (ch != EOF) good = (ungetc(ch, fp) == ch);
+
+ // Read three lines, check them for validity, and register the service.
+ good = ReadALine(name, sizeof(name), fp);
+ if (good) {
+ good = ReadALine(type, sizeof(type), fp);
+ }
+ if (good) {
+ char *p = type;
+ while (*p && *p != ' ') p++;
+ if (*p) {
+ *p = 0;
+ dom = p+1;
}
- else
- fprintf(stderr, "%s: TXT attribute too long for name = %s, type = %s, port = %s\n",
- gProgramName, name, type, port);
- }
-
- status = RegisterOneService(name, type, dom, text, textLen, atol(port));
- if (status != mStatus_NoError) {
- // print error, but try to read and register other services in the file
- fprintf(stderr, "%s: Failed to register service, name \"%s\", type \"%s\", domain \"%s\", port %s\n",
- gProgramName, name, type, dom, port);
- }
-
- } while (!feof(fp));
+ }
+ if (good) {
+ good = ReadALine(port, sizeof(port), fp);
+ }
+ if (good) {
+ good = CheckThatRichTextNameIsUsable(name, mDNSfalse)
+ && CheckThatServiceTypeIsUsable(type, mDNSfalse)
+ && CheckThatPortNumberIsUsable(atol(port), mDNSfalse);
+ }
+ if (good) {
+ while (1) {
+ int len;
+ if (!ReadALine(rawText, sizeof(rawText), fp)) break;
+ len = strlen(rawText);
+ if (len <= 255)
+ {
+ unsigned int newlen = textLen + 1 + len;
+ if (len == 0 || newlen >= sizeof(text)) break;
+ text[textLen] = len;
+ mDNSPlatformMemCopy(text + textLen + 1, rawText, len);
+ textLen = newlen;
+ }
+ else
+ fprintf(stderr, "%s: TXT attribute too long for name = %s, type = %s, port = %s\n",
+ gProgramName, name, type, port);
+ }
+ }
+ if (good) {
+ status = RegisterOneService(name, type, dom, text, textLen, atol(port));
+ if (status != mStatus_NoError) {
+ fprintf(stderr, "%s: Failed to register service, name = %s, type = %s, port = %s\n",
+ gProgramName, name, type, port);
+ status = mStatus_NoError; // keep reading
+ }
+ }
+ } while (good && !feof(fp));
- if (!feof(fp)) {
- fprintf(stderr, "%s: Error reading service file %s\n", gProgramName, filePath);
- status = mStatus_UnknownErr;
- }
+ if ( ! good ) {
+ fprintf(stderr, "%s: Error reading service file %s\n", gProgramName, filePath);
+ }
+ }
- assert(0 == fclose(fp));
+ if (fp != NULL) {
+ junk = fclose(fp);
+ assert(junk == 0);
+ }
- return status;
+ return status;
}
static mStatus RegisterOurServices(void)
-#
-# Example services file parsed by mDNSResponderPosix.
-#
-# Lines beginning with '#' are comments/ignored.
-# Blank lines indicate the end of a service record specification.
-# The first character of the service name can be a '#' if you escape it with
-# backslash to distinguish if from a comment line.
-# ie, "\#serviceName" will be registered as "#serviceName".
-# Note that any line beginning with white space is considered a blank line.
-#
-# The record format is:
-#
-# <service name>
-# <type>.<protocol> <optional domain>
-# <port number>
-# <zero or more strings for the text record, one string per line>
-#
-# <One or more blank lines between records>
-#
-# Examples shown below.
-
-serviceName1
+Tweedlebug
_afpovertcp._tcp.
548
name=val1
-serviceName2
+Tweedlebug2
_afpovertcp._tcp. local.
548
name=val2
name2=anotherattribute
-serviceName3
+Tweedlebug3
_afpovertcp._tcp.
548
name=val3
assert(msg != NULL);
assert(end != NULL);
assert((((char *) end) - ((char *) msg)) > 0);
+ assert(dstPort.NotAnInteger != 0);
- if (dstPort.NotAnInteger == 0)
- {
- LogMsg("mDNSPlatformSendUDP: Invalid argument -dstPort is set to 0");
- return PosixErrorToStatus(EINVAL);
- }
if (dst->type == mDNSAddrType_IPv4)
{
struct sockaddr_in *sin = (struct sockaddr_in*)&to;
#if defined(IPV6_PKTINFO)
if (err == 0)
{
- err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_PKTINFO, &kOn, sizeof(kOn));
+ err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_PKTINFO, &kOn, sizeof(kOn));
if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); }
}
#else
#if defined(IPV6_HOPLIMIT)
if (err == 0)
{
- err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_HOPLIMIT, &kOn, sizeof(kOn));
+ err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_HOPLIMIT, &kOn, sizeof(kOn));
if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); }
}
#endif
// Set up the fields required by the mDNS core.
SockAddrTomDNSAddr(intfAddr, &intf->coreIntf.ip, NULL);
SockAddrTomDNSAddr(intfMask, &intf->coreIntf.mask, NULL);
-
//LogMsg("SetupOneInterface: %#a %#a", &intf->coreIntf.ip, &intf->coreIntf.mask);
strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname));
intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0;
/* Gets IPv6 interface information from the /proc filesystem in linux*/
struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
{
- struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
+ struct ifi_info *ifi, *ifihead, **ifipnext;
FILE *fp;
char addr[8][5];
int flags, myflags, index, plen, scope;
struct sockaddr_in6 *sin6;
struct in6_addr *addrptr;
int err;
- int sockfd = -1;
- struct ifreq ifr;
res0=NULL;
ifihead = NULL;
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],
ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
if (ifi == NULL) {
goto gotError;
- }
-
- ifipold = *ifipnext; /* need this later */
- ifiptr = ifipnext;
+ }
+
*ifipnext = ifi; /* prev points to this new one */
ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
/* Add interface index */
ifi->ifi_index = index;
- /* Add interface flags*/
- memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
- if (errno == EADDRNOTAVAIL) {
- /*
- * If the main interface is configured with no IP address but
- * an alias interface exists with an IP address, you get
- * EADDRNOTAVAIL for the main interface
- */
- free(ifi->ifi_addr);
- free(ifi);
- ifipnext = ifiptr;
- *ifipnext = ifipold;
- continue;
- } else {
- goto gotError;
- }
- }
- ifi->ifi_flags = ifr.ifr_flags;
+ /* If interface is in /proc then it is up*/
+ ifi->ifi_flags = IFF_UP;
+
freeaddrinfo(res0);
res0=NULL;
}
res0=NULL;
}
done:
- if (sockfd != -1) {
- assert(close(sockfd) == 0);
- }
return(ifihead); /* pointer to first structure in linked list */
}
#endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
struct ifi_info *get_ifi_info(int family, int doaliases)
{
int junk;
- struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
+ struct ifi_info *ifi, *ifihead, **ifipnext;
int sockfd, sockf6, len, lastlen, flags, myflags;
#ifdef NOT_HAVE_IF_NAMETOINDEX
int index = 200;
if (ifi == NULL) {
goto gotError;
}
- ifipold = *ifipnext; /* need this later */
- ifiptr = ifipnext;
- *ifipnext = ifi; /* prev points to this new one */
- ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
-
+ *ifipnext = ifi; /* prev points to this new one */
+ ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
+
ifi->ifi_flags = flags; /* IFF_xxx values */
ifi->ifi_myflags = myflags; /* IFI_xxx values */
#ifndef NOT_HAVE_IF_NAMETOINDEX
memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
#ifdef SIOCGIFNETMASK
- if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) {
- if (errno == EADDRNOTAVAIL) {
- /*
- * If the main interface is configured with no IP address but
- * an alias interface exists with an IP address, you get
- * EADDRNOTAVAIL for the main interface
- */
- free(ifi->ifi_addr);
- free(ifi);
- ifipnext = ifiptr;
- *ifipnext = ifipold;
- continue;
- } else {
- goto gotError;
- }
- }
-
+ if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) goto gotError;
ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
if (ifi->ifi_netmask == NULL) goto gotError;
sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
memset(&ifr6, 0, sizeof(ifr6));
memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name ));
memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
- if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) {
- if (errno == EADDRNOTAVAIL) {
- /*
- * If the main interface is configured with no IP address but
- * an alias interface exists with an IP address, you get
- * EADDRNOTAVAIL for the main interface
- */
- free(ifi->ifi_addr);
- free(ifi);
- ifipnext = ifiptr;
- *ifipnext = ifipold;
- continue;
- } else {
- goto gotError;
- }
- }
+ if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) goto gotError;
ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
if (ifi->ifi_netmask == NULL) goto gotError;
sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
}
#endif
-#if defined(IPV6_PKTINFO) && HAVE_IPV6
- if (cmptr->cmsg_level == IPPROTO_IPV6 &&
- cmptr->cmsg_type == IPV6_2292_PKTINFO) {
+#if defined(IPV6_PKTINFO) && HAVE_IPV6
+ if (cmptr->cmsg_level == IPPROTO_IPV6 &&
+ cmptr->cmsg_type == IPV6_PKTINFO) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
#if defined(IPV6_HOPLIMIT) && HAVE_IPV6
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
- cmptr->cmsg_type == IPV6_2292_HOPLIMIT) {
+ cmptr->cmsg_type == IPV6_HOPLIMIT) {
*ttl = *(int*)CMSG_DATA(cmptr);
continue;
}
#ifdef HAVE_LINUX
#include <linux/socket.h>
-#define IPV6_2292_PKTINFO IPV6_2292PKTINFO
-#define IPV6_2292_HOPLIMIT IPV6_2292HOPLIMIT
-#else
-// The following are the supported non-linux posix OSes -
-// netbsd, freebsd and openbsd.
-#if HAVE_IPV6
-#define IPV6_2292_PKTINFO 19
-#define IPV6_2292_HOPLIMIT 20
-#endif
#endif
#ifdef __cplusplus
#endif
#endif
-// FreeBSD
-
-#if( !defined( TARGET_OS_FREEBSD ) )
- #if( defined( __FreeBSD__ ) )
- #define TARGET_OS_FREEBSD 1
- #else
- #define TARGET_OS_FREEBSD 0
- #endif
-#endif
-
// Linux
#if( !defined( TARGET_OS_LINUX ) )
// No predefined macro for VxWorks so just assume VxWorks if nothing else is set.
- #if( !macintosh && !__MACH__ && !defined( __FreeBSD__ ) && !defined( __linux__ ) && !defined ( __SVR4 ) && !defined ( __sun ) && !defined( __PALMOS_TRAPS__ ) && !defined( __PALMOS_ARMLET__ ) && !defined( _WIN32 ) )
+ #if( !macintosh && !__MACH__ && !defined( __linux__ ) && !defined ( __SVR4 ) && !defined ( __sun ) && !defined( __PALMOS_TRAPS__ ) && !defined( __PALMOS_ARMLET__ ) && !defined( _WIN32 ) )
#define TARGET_OS_VXWORKS 1
#else
#define TARGET_OS_VXWORKS 0
#include <libkern/OSTypes.h>
#include <sys/types.h>
-#elif( TARGET_OS_FREEBSD )
-
- // FreeBSD
- #include <stdint.h>
- #include <pthread.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/socket.h>
-
#elif( TARGET_OS_LINUX )
// Linux
// - Windows
#if( TARGET_LANGUAGE_C_LIKE )
- #if( !defined(_SSIZE_T) && ( TARGET_OS_WIN32 || !defined( _BSD_SSIZE_T_DEFINED_ ) ) && !TARGET_OS_FREEBSD && !TARGET_OS_LINUX && !TARGET_OS_VXWORKS && !TARGET_OS_MAC)
+ #if( !defined(_SSIZE_T) && ( TARGET_OS_WIN32 || !defined( _BSD_SSIZE_T_DEFINED_ ) ) && !TARGET_OS_LINUX && !TARGET_OS_VXWORKS && !TARGET_OS_MAC)
typedef int ssize_t;
#endif
#endif
*/
#ifndef _DNS_SD_H
-#define _DNS_SD_H 3201080
+#define _DNS_SD_H 3201400
#ifdef __cplusplus
extern "C" {
*q2 = *q;
q2->InterfaceID = mDNSInterface_Unicast;
q2->ExpectUnique = mDNStrue;
+ // Always set the QuestionContext to indicate that this question should be stopped
+ // before freeing. Don't rely on "q".
+ q2->QuestionContext = request;
// If the query starts as a single label e.g., somehost, and we have search domains with .local,
// queryrecord_result_callback calls this function when .local is appended to "somehost".
// At that time, the name in "q" is pointing at somehost.local and its qnameOrig pointing at
{
if (!answer->InterfaceID && IsLocalDomain(answer->name))
{
- LogInfo("queryrecord_result_callback:Question %##s (%s) answering local with unicast", question->qname.c, DNSTypeName(question->qtype));
- return;
+ mDNSu16 qtype;
+ // Sanity check: "q" will be set only if "question" is the .local unicast query.
+ if (!q)
+ {
+ LogMsg("queryrecord_result_callback: ERROR!! answering multicast question with unicast cache record");
+ return;
+ }
+ // Deliver negative response for A/AAAA if there was a positive response for AAAA/A respectively.
+ if (question->qtype != kDNSType_A && question->qtype != kDNSType_AAAA)
+ {
+ LogInfo("queryrecord_result_callback:Question %##s (%s) not answering local question with negative unicast response", question->qname.c, DNSTypeName(question->qtype));
+ return;
+ }
+ qtype = (question->qtype == kDNSType_A ? kDNSType_AAAA : kDNSType_A);
+ if (!mDNS_CheckForCacheRecord(m, question, qtype))
+ {
+ LogInfo("queryrecord_result_callback:Question %##s (%s) not answering local question with negative unicast response (can't find positive record)", question->qname.c, DNSTypeName(question->qtype));
+ return;
+ }
+ LogInfo("queryrecord_result_callback:Question %##s (%s) answering local with negative unicast response (found positive record)", question->qname.c, DNSTypeName(question->qtype));
}
error = kDNSServiceErr_NoSuchRecord;
}
// determine whether sa_len is defined on a particular platform.
laddr.sun_len = sizeof(struct sockaddr_un);
#endif
- if (strlen(MDNS_UDS_SERVERPATH) >= sizeof(laddr.sun_path))
- {
- LogMsg("ERROR: MDNS_UDS_SERVERPATH must be < %d characters", (int)sizeof(laddr.sun_path));
- goto error;
- }
mDNSPlatformStrCopy(laddr.sun_path, MDNS_UDS_SERVERPATH);
ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
umask(mask);