Commit 008d43bb authored by Fawzi Mohamed's avatar Fawzi Mohamed
Browse files

mdnssd: IPv6 fixes + merging 320.10.80 and 333.10



mostly uses original whitespace (for easier merging)

Change-Id: Ic3ced878f2ab77f86a06c4135636e659716588c2
Reviewed-by: default avatarFawzi Mohamed <fawzi.mohamed@nokia.com>
parent 927fb4c7
......@@ -1369,12 +1369,20 @@ mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr,
return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
}
// This is called only when the caller knows that it is a Unicast Resource Record and it is a Unicast Question
// and hence we don't need InterfaceID checks like above. Though this may not be a big optimization, the main
// reason we need this is that we can't compare DNSServers between the question and the resource record because
// the resource record may not be completely initialized e.g., mDNSCoreReceiveResponse
mDNSexport mDNSBool UnicastResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
{
// This is called with both unicast resource record and multicast resource record. The question that
// received the unicast response could be the regular unicast response from a DNS server or a response
// to a mDNS QU query. The main reason we need this function is that we can't compare DNSServers between the
// question and the resource record because the resource record is not completely initialized in
// mDNSCoreReceiveResponse when this function is called.
mDNSexport mDNSBool ResourceRecordAnswersUnicastResponse(const ResourceRecord *const rr, const DNSQuestion *const q)
{
// For resource records created using multicast, the InterfaceIDs have to match
if (rr->InterfaceID &&
q->InterfaceID && rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
// If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question.
if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
// RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
if (!RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
......
......@@ -164,7 +164,7 @@ extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *c
extern mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
extern mDNSBool AnyTypeRecordAnswersQuestion (const ResourceRecord *const rr, const DNSQuestion *const q);
extern mDNSBool UnicastResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
extern mDNSBool ResourceRecordAnswersUnicastResponse(const ResourceRecord *const rr, const DNSQuestion *const q);
extern mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const rr, const DNSQuestion *const q);
extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate);
extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd);
......
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
* Copyright (c) 2002-2011 Apple Computer, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -571,9 +571,16 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num);
#endif
#endif
// None of the invocations of the following macros actually use the result,
// so cast them to void to avoid any compiler warnings/errors about not using
// the result (e.g. when using clang).
// If the resultant values need to be used at some point, these must be changed.
#define HOST_c2l(c,l) ((void)_HOST_c2l(c,l))
#define HOST_l2c(l,c) ((void)_HOST_l2c(l,c))
#if defined(DATA_ORDER_IS_BIG_ENDIAN)
#define HOST_c2l(c,l) (l =(((unsigned long)(*((c)++)))<<24), \
#define _HOST_c2l(c,l) (l =(((unsigned long)(*((c)++)))<<24), \
l|=(((unsigned long)(*((c)++)))<<16), \
l|=(((unsigned long)(*((c)++)))<< 8), \
l|=(((unsigned long)(*((c)++))) ), \
......@@ -601,7 +608,7 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num);
case 2: l|=((unsigned long)(*(--(c))))<<16; \
case 1: l|=((unsigned long)(*(--(c))))<<24; \
} }
#define HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \
#define _HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \
*((c)++)=(unsigned char)(((l)>>16)&0xff), \
*((c)++)=(unsigned char)(((l)>> 8)&0xff), \
*((c)++)=(unsigned char)(((l) )&0xff), \
......@@ -609,7 +616,7 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num);
#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
#define HOST_c2l(c,l) (l =(((unsigned long)(*((c)++))) ), \
#define _HOST_c2l(c,l) (l =(((unsigned long)(*((c)++))) ), \
l|=(((unsigned long)(*((c)++)))<< 8), \
l|=(((unsigned long)(*((c)++)))<<16), \
l|=(((unsigned long)(*((c)++)))<<24), \
......@@ -637,7 +644,7 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num);
case 2: l|=((unsigned long)(*(--(c))))<< 8; \
case 1: l|=((unsigned long)(*(--(c)))); \
} }
#define HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
#define _HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
*((c)++)=(unsigned char)(((l)>> 8)&0xff), \
*((c)++)=(unsigned char)(((l)>>16)&0xff), \
*((c)++)=(unsigned char)(((l)>>24)&0xff), \
......
......@@ -77,7 +77,7 @@
*/
#ifndef _DNS_SD_H
#define _DNS_SD_H 3200500
#define _DNS_SD_H 3331000
#ifdef __cplusplus
extern "C" {
......
......@@ -152,7 +152,7 @@ typedef enum
} reply_op_t;
#if defined(_WIN64)
# pragma pack(4)
# pragma pack(push,4)
#endif
// Define context object big enough to hold a 64-bit pointer,
......@@ -176,6 +176,10 @@ typedef packedstruct
// index/socket pair uniquely identifies a record. (Used to select records for removal by DNSServiceRemoveRecord())
} ipc_msg_hdr;
#if defined(_WIN64)
# pragma pack(pop)
#endif
// routines to write to and extract data from message buffers.
// caller responsible for bounds checking.
// ptr is the address of the pointer to the start of the field.
......
......@@ -349,7 +349,7 @@ mDNSexport mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterface
if (addr->type == mDNSAddrType_IPv6)
{
if (mDNSv6AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue);
if (mDNSv6AddressIsLinkLocal(&addr->ip.v6)) return(mDNStrue);
for (intf = m->HostInterfaces; intf; intf = intf->next)
if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) &&
......@@ -1730,7 +1730,7 @@ mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const d
}
if (m->omsg.h.numAnswers)
mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSNULL);
mDNSSendDNSMessage(m, &m->omsg, responseptr, InterfaceID, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSNULL);
}
}
......@@ -3285,6 +3285,22 @@ mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAdd
#pragma mark - RR List Management & Task Management
#endif
// Whenever a question is answered, reset its state so that we don't query
// the network repeatedly. This happens first time when we answer the question and
// and later when we refresh the cache.
mDNSlocal void ResetQuestionState(mDNS *const m, DNSQuestion *q)
{
q->LastQTime = m->timenow;
q->LastQTxTime = m->timenow;
q->RecentAnswerPkts = 0;
q->ThisQInterval = MaxQuestionInterval;
q->RequestUnicast = mDNSfalse;
// Reset unansweredQueries so that we don't penalize this server later when we
// start sending queries when the cache expires.
q->unansweredQueries = 0;
debugf("ResetQuestionState: Set MaxQuestionInterval for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
}
// Note: AnswerCurrentQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list.
// Any code walking either list must use the m->CurrentQuestion (and possibly m->CurrentRecord) mechanism to protect against this.
// In fact, to enforce this, the routine will *only* answer the question currently pointed to by m->CurrentQuestion,
......@@ -3343,12 +3359,7 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
(AddRecord == QC_add && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))))
if (ActiveQuestion(q) && (mDNSOpaque16IsZero(q->TargetQID) || !q->LongLived))
{
q->LastQTime = m->timenow;
q->LastQTxTime = m->timenow;
q->RecentAnswerPkts = 0;
q->ThisQInterval = MaxQuestionInterval;
q->RequestUnicast = mDNSfalse;
debugf("AnswerCurrentQuestionWithResourceRecord: Set MaxQuestionInterval for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
ResetQuestionState(m, q);
}
if (rr->DelayDelivery) return; // We'll come back later when CacheRecordDeferredAdd() calls us
......@@ -6278,6 +6289,8 @@ mDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m,
return(mDNSNULL);
}
// This function is called when we receive a unicast response. This could be the case of a unicast response from the
// DNS server or a response to the QU query. Hence, the cache record's InterfaceId can be both NULL or non-NULL (QU case)
mDNSlocal DNSQuestion *ExpectingUnicastResponseForRecord(mDNS *const m,
const mDNSAddr *const srcaddr, const mDNSBool SrcLocal, const mDNSIPPort port, const mDNSOpaque16 id, const CacheRecord *const rr, mDNSBool tcp)
{
......@@ -6285,12 +6298,9 @@ mDNSlocal DNSQuestion *ExpectingUnicastResponseForRecord(mDNS *const m,
(void)id;
(void)srcaddr;
// Unicast records have zero as InterfaceID
if (rr->resrec.InterfaceID) return mDNSNULL;
for (q = m->Questions; q; q=q->next)
{
if (!q->DuplicateOf && UnicastResourceRecordAnswersQuestion(&rr->resrec, q))
if (!q->DuplicateOf && ResourceRecordAnswersUnicastResponse(&rr->resrec, q))
{
if (!mDNSOpaque16IsZero(q->TargetQID))
{
......@@ -6867,12 +6877,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
if (!q->DuplicateOf && !q->LongLived &&
ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
{
q->LastQTime = m->timenow;
q->LastQTxTime = m->timenow;
q->RecentAnswerPkts = 0;
q->ThisQInterval = MaxQuestionInterval;
q->RequestUnicast = mDNSfalse;
q->unansweredQueries = 0;
ResetQuestionState(m, q);
debugf("mDNSCoreReceiveResponse: Set MaxQuestionInterval for %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
break; // Why break here? Aren't there other questions we might want to look at?-- SC July 2010
}
......@@ -7146,8 +7151,14 @@ exit:
// If we already had a negative cache entry just update it, else make one or more new negative cache entries
if (neg)
{
debugf("Renewing negative TTL from %d to %d %s", neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg));
debugf("mDNSCoreReceiveResponse: Renewing negative TTL from %d to %d %s", neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg));
RefreshCacheRecord(m, neg, negttl);
// When we created the cache for the first time and answered the question, the question's
// interval was set to MaxQuestionInterval. If the cache is about to expire and we are resending
// the queries, the interval should still be at MaxQuestionInterval. If the query is being
// restarted (setting it to InitialQuestionInterval) for other reasons e.g., wakeup,
// we should reset its question interval here to MaxQuestionInterval.
ResetQuestionState(m, qptr);
}
else while (1)
{
......@@ -7817,6 +7828,55 @@ mDNSlocal mDNSu32 GetTimeoutForMcastQuestion(mDNS *m, DNSQuestion *question)
return ( curmatch ? curmatch->timeout : DEFAULT_MCAST_TIMEOUT);
}
// Returns true if it is a Domain Enumeration Query
mDNSexport mDNSBool DomainEnumQuery(const domainname *qname)
{
const mDNSu8 *mDNS_DEQLabels[] = { (const mDNSu8 *)"\001b", (const mDNSu8 *)"\002db", (const mDNSu8 *)"\002lb",
(const mDNSu8 *)"\001r", (const mDNSu8 *)"\002dr", (const mDNSu8 *)mDNSNULL, };
const domainname *d = qname;
const mDNSu8 *label;
int i = 0;
// We need at least 3 labels (DEQ prefix) + one more label to make a meaningful DE query
if (CountLabels(qname) < 4) { debugf("DomainEnumQuery: question %##s, not enough labels", qname->c); return mDNSfalse; }
label = (const mDNSu8 *)d;
while (mDNS_DEQLabels[i] != (const mDNSu8 *)mDNSNULL)
{
if (SameDomainLabel(mDNS_DEQLabels[i], label)) {debugf("DomainEnumQuery: DEQ %##s, label1 match", qname->c); break;}
i++;
}
if (mDNS_DEQLabels[i] == (const mDNSu8 *)mDNSNULL)
{
debugf("DomainEnumQuery: Not a DEQ %##s, label1 mismatch", qname->c);
return mDNSfalse;
}
debugf("DomainEnumQuery: DEQ %##s, label1 match", qname->c);
// CountLabels already verified the number of labels
d = (const domainname *)(d->c + 1 + d->c[0]); // Second Label
label = (const mDNSu8 *)d;
if (!SameDomainLabel(label, (const mDNSu8 *)"\007_dns-sd"))
{
debugf("DomainEnumQuery: Not a DEQ %##s, label2 mismatch", qname->c);
return(mDNSfalse);
}
debugf("DomainEnumQuery: DEQ %##s, label2 match", qname->c);
d = (const domainname *)(d->c + 1 + d->c[0]); // Third Label
label = (const mDNSu8 *)d;
if (!SameDomainLabel(label, (const mDNSu8 *)"\004_udp"))
{
debugf("DomainEnumQuery: Not a DEQ %##s, label3 mismatch", qname->c);
return(mDNSfalse);
}
debugf("DomainEnumQuery: DEQ %##s, label3 match", qname->c);
debugf("DomainEnumQuery: Question %##s is a Domain Enumeration query", qname->c);
return mDNStrue;
}
// Sets all the Valid DNS servers for a question
mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
{
......@@ -7826,8 +7886,10 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
int bettermatch, currcount;
int index = 0;
mDNSu32 timeout = 0;
mDNSBool DEQuery;
question->validDNSServers = zeroOpaque64;
DEQuery = DomainEnumQuery(&question->qname);
for (curr = m->DNSServers; curr; curr = curr->next)
{
debugf("SetValidDNSServers: Parsing DNS server Address %#a (Domain %##s), Scope: %d", &curr->addr, curr->domain.c, curr->scoped);
......@@ -7847,7 +7909,9 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
{ debugf("SetValidDNSServers: Scoped DNS server %#a (Domain %##s) with Interface Any", &curr->addr, curr->domain.c); continue; }
currcount = CountLabels(&curr->domain);
if ((!curr->scoped && (!question->InterfaceID || (question->InterfaceID == mDNSInterface_Unicast))) || (curr->interface == question->InterfaceID))
if ((!DEQuery || !curr->cellIntf) &&
((!curr->scoped && (!question->InterfaceID || (question->InterfaceID == mDNSInterface_Unicast))) ||
(curr->interface == question->InterfaceID)))
{
bettermatch = BetterMatchForName(&question->qname, namecount, &curr->domain, currcount, bestmatchlen);
......@@ -7864,6 +7928,7 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
" Timeout %d, interface %p", question->qname.c, &curr->addr, curr->domain.c, curr->scoped, index, curr->timeout,
curr->interface);
timeout += curr->timeout;
if (DEQuery) debugf("DomainEnumQuery: Question %##s, DNSServer %#a, cell %d", question->qname.c, &curr->addr, curr->cellIntf);
bit_set_opaque64(question->validDNSServers, index);
}
}
......
......@@ -1075,6 +1075,7 @@ typedef struct DNSServer
mDNSBool scoped; // interface should be matched against question only
// if scoped is set
mDNSu32 timeout; // timeout value for questions
mDNSBool cellIntf; // Resolver from Cellular Interface ?
} DNSServer;
typedef struct // Size is 36 bytes when compiling for 32-bit; 48 when compiling for 64-bit
......@@ -2468,7 +2469,7 @@ extern void RecreateNATMappings(mDNS *const m);
extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext);
extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn);
extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router);
extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped, mDNSu32 timeout);
extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped, mDNSu32 timeout, mDNSBool cellIntf);
extern void PenalizeDNSServer(mDNS *const m, DNSQuestion *q);
extern void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID);
......@@ -2653,8 +2654,8 @@ extern mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const Netw
extern void LNT_SendDiscoveryMsg(mDNS *m);
extern void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, const mDNSu8 *const data, const mDNSu16 len);
extern mStatus LNT_GetExternalAddress(mDNS *m);
extern mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *n);
extern mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *n);
extern mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *const n);
extern mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *const n);
extern void LNT_ClearState(mDNS *const m);
#endif // _LEGACY_NAT_TRAVERSAL_
......@@ -2729,6 +2730,7 @@ extern void DNSServerChangeForQuestion(mDNS *const m, DNSQuestion *q, DNSServer
extern void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr);
extern void CheckSuppressUnusableQuestions(mDNS *const m);
extern void RetrySearchDomainQuestions(mDNS *const m);
extern mDNSBool DomainEnumQuery(const domainname *qname);
// Used only in logging to restrict the number of /etc/hosts entries printed
extern void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result);
......@@ -2943,7 +2945,7 @@ struct CompileTimeAssertionChecks_mDNS
char sizecheck_ZoneData [(sizeof(ZoneData) <= 1624) ? 1 : -1];
char sizecheck_NATTraversalInfo [(sizeof(NATTraversalInfo) <= 192) ? 1 : -1];
char sizecheck_HostnameInfo [(sizeof(HostnameInfo) <= 3050) ? 1 : -1];
char sizecheck_DNSServer [(sizeof(DNSServer) <= 320) ? 1 : -1];
char sizecheck_DNSServer [(sizeof(DNSServer) <= 328) ? 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];
......
......@@ -27,6 +27,7 @@
* understand why variable y is not of type "char*" just proves the point that poor code
* layout leads people to unfortunate misunderstandings about how the C language really works.)
*/
#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
#include "DNSCommon.h"
#include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
......@@ -158,8 +159,12 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
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;
......@@ -501,7 +506,7 @@ mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
mDNSAddr DNSAddr;
DNSAddr.type = mDNSAddrType_IPv4;
DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, &DNSAddr, UnicastDNSPort, mDNSfalse, 0);
mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, &DNSAddr, UnicastDNSPort, mDNSfalse, 0, mDNSfalse);
numOfServers++;
}
}
......@@ -710,16 +715,10 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf
{
struct ipv6_mreq imr6;
struct sockaddr_in6 bindAddr6;
#if defined(IPV6_RECVPKTINFO)
if (err == 0)
{
err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVPKTINFO, &kOn, sizeof(kOn));
if (err < 0) { err = errno; perror("setsockopt - IPV6_RECVPKTINFO"); }
}
#elif defined(IPV6_PKTINFO)
#if defined(IPV6_PKTINFO)
if (err == 0)
{
err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_PKTINFO, &kOn, sizeof(kOn));
err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_PKTINFO, &kOn, sizeof(kOn));
if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); }
}
#else
......@@ -728,7 +727,7 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf
#if defined(IPV6_HOPLIMIT)
if (err == 0)
{
err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_HOPLIMIT, &kOn, sizeof(kOn));
err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_HOPLIMIT, &kOn, sizeof(kOn));
if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); }
}
#endif
......@@ -846,6 +845,7 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct
// 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;
......
......@@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mDNSUNP.h"
#include <errno.h>
......@@ -81,7 +82,7 @@ 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 *ifi, *ifihead, **ifipnext;
struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
FILE *fp;
char addr[8][5];
int flags, myflags, index, plen, scope;
......@@ -91,6 +92,8 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
struct sockaddr_in6 *sin6;
struct in6_addr *addrptr;
int err;
int sockfd = -1;
struct ifreq ifr;
res0=NULL;
ifihead = NULL;
......@@ -98,6 +101,10 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
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],
......@@ -114,8 +121,10 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
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 */
......@@ -160,9 +169,25 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
/* Add interface index */
ifi->ifi_index = index;
/* If interface is in /proc then it is up*/
ifi->ifi_flags = IFF_UP;
/* 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;
freeaddrinfo(res0);
res0=NULL;
}
......@@ -179,6 +204,9 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
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
......@@ -186,7 +214,7 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
struct ifi_info *get_ifi_info(int family, int doaliases)
{
int junk;
struct ifi_info *ifi, *ifihead, **ifipnext;
struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
int sockfd, sockf6, len, lastlen, flags, myflags;
#ifdef NOT_HAVE_IF_NAMETOINDEX
int index = 200;
......@@ -278,9 +306,11 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
if (ifi == NULL) {
goto gotError;
}
*ifipnext = ifi; /* prev points to this new one */
ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
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 */
ifi->ifi_flags = flags; /* IFF_xxx values */
ifi->ifi_myflags = myflags; /* IFI_xxx values */
#ifndef NOT_HAVE_IF_NAMETOINDEX
......@@ -309,7 +339,23 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
#ifdef SIOCGIFNETMASK
if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) goto gotError;
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;
}
}
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;
......@@ -384,7 +430,22 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
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) goto gotError;
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;
}
}
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;
......@@ -575,9 +636,9 @@ struct in_pktinfo
}
#endif
#if defined(IPV6_PKTINFO) && HAVE_IPV6
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
cmptr->cmsg_type == IPV6_PKTINFO) {
#if defined(IPV6_PKTINFO) && HAVE_IPV6
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
cmptr->cmsg_type == IPV6_2292_PKTINFO) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
......@@ -596,7 +657,7 @@ struct in_pktinfo
#if defined(IPV6_HOPLIMIT) && HAVE_IPV6
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
cmptr->cmsg_type == IPV6_HOPLIMIT) {
cmptr->cmsg_type == IPV6_2292_HOPLIMIT) {
*ttl = *(int*)CMSG_DATA(cmptr);
continue;
}
......
......@@ -25,6 +25,15 @@
#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
......
#include <QtCore/QCoreApplication>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
return a.exec();
}