1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 #ifndef UNICAST_DISABLED
22 // Implementation Notes
24 // DNS Proxy listens on port 53 (UDPv4v6 & TCPv4v6) for DNS queries. It handles only
25 // the "Query" opcode of the DNS protocol described in RFC 1035. For all other opcodes, it returns
26 // "Not Implemented" error. The platform interface mDNSPlatformInitDNSProxySkts
27 // sets up the sockets and whenever it receives a packet, it calls ProxyTCPCallback or ProxyUDPCallback
28 // defined here. For TCP socket, the platform does the "accept" and only sends the received packets
29 // on the newly accepted socket. A single UDP socket (per address family) is used to send/recv
30 // requests/responses from all clients. For TCP, there is one socket per request. Hence, there is some
31 // extra state that needs to be disposed at the end.
33 // When a DNS request is received, ProxyCallbackCommon checks for malformed packet etc. and also checks
34 // for duplicates, before creating DNSProxyClient state and starting a question with the "core"
35 // (mDNS_StartQuery). When the callback for the question happens, it gathers all the necessary
36 // resource records, constructs a response and sends it back to the client.
38 // - Question callback is called with only one resource record at a time. We need all the resource
39 // records to construct the response. Hence, we lookup all the records ourselves.
41 // - The response may not fit the client's buffer size. In that case, we need to set the truncate bit
42 // and the client would retry using TCP.
44 // - The client may have set the DNSSEC OK bit in the EDNS0 option and that means we also have to
45 // return the RRSIGs or the NSEC records with the RRSIGs in the Additional section. We need to
46 // ask the "core" to fetch the DNSSEC records and do the validation if the CD bit is not set.
48 // Once the response is sent to the client, the client state is disposed. When there is no response
49 // from the "core", it eventually times out and we will not find any answers in the cache and we send a
50 // "NXDomain" response back. Thus, we don't need any special timers to reap the client state in the case
53 typedef struct DNSProxyClient_struct DNSProxyClient
;
55 struct DNSProxyClient_struct
{
58 mDNSAddr addr
; // Client's IP address
59 mDNSIPPort port
; // Client's port number
60 mDNSOpaque16 msgid
; // DNS msg id
61 mDNSInterfaceID interfaceID
; // Interface on which we received the request
62 void *socket
; // Return socket
63 mDNSBool tcp
; // TCP or UDP ?
64 mDNSOpaque16 requestFlags
; // second 16 bit word in the DNSMessageHeader of the request
65 mDNSu8
*optRR
; // EDNS0 option
66 mDNSu16 optLen
; // Total Length of the EDNS0 option
67 mDNSu16 rcvBufSize
; // How much can the client receive ?
68 mDNSBool DNSSECOK
; // DNSSEC OK ?
69 void *context
; // Platform context to be disposed if non-NULL
70 domainname qname
; // q->qname can't be used for duplicate check
71 DNSQuestion q
; // as it can change underneath us for CNAMEs
74 #define MIN_DNS_MESSAGE_SIZE 512
75 DNSProxyClient
*DNSProxyClients
;
77 mDNSlocal
void FreeDNSProxyClient(DNSProxyClient
*pc
)
80 mDNSPlatformMemFree(pc
->optRR
);
81 mDNSPlatformMemFree(pc
);
84 mDNSlocal mDNSBool
ParseEDNS0(DNSProxyClient
*pc
, const mDNSu8
*ptr
, int length
, const mDNSu8
*limit
)
86 if (ptr
+ length
> limit
)
88 LogInfo("ParseEDNS0: Not enough space in the packet");
91 // Skip the root label
93 mDNSu16 rrtype
= (mDNSu16
) ((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
94 if (rrtype
!= kDNSType_OPT
)
96 LogInfo("ParseEDNS0: Not the right type %d", rrtype
);
99 mDNSu16 rrclass
= (mDNSu16
) ((mDNSu16
)ptr
[2] << 8 | ptr
[3]);
101 mDNSu8 rcode
= ptr
[4];
102 mDNSu8 version
= ptr
[5];
103 mDNSu16 flag
= (mDNSu16
) ((mDNSu16
)ptr
[6] << 8 | ptr
[7]);
104 debugf("rrtype is %s, length is %d, rcode %d, version %d, flag 0x%x", DNSTypeName(rrtype
), rrclass
, rcode
, version
, flag
);
106 pc
->rcvBufSize
= rrclass
;
107 pc
->DNSSECOK
= ptr
[6] & 0x80;
112 mDNSexport mDNSu8
*DNSProxySetAttributes(DNSQuestion
*q
, DNSMessageHeader
*h
, DNSMessage
*msg
, mDNSu8
*ptr
, mDNSu8
*limit
)
114 DNSProxyClient
*pc
= (DNSProxyClient
*)q
->QuestionContext
;
118 h
->flags
= pc
->requestFlags
;
121 if (ptr
+ pc
->optLen
> limit
)
123 LogInfo("DNSProxySetAttributes: Cannot set EDNS0 option start %p, OptLen %d, end %p", ptr
, pc
->optLen
, limit
);
127 mDNSPlatformMemCopy(ptr
, pc
->optRR
, pc
->optLen
);
133 mDNSlocal mDNSu8
*AddEDNS0Option(mDNS
*const m
, mDNSu8
*ptr
, mDNSu8
*limit
)
137 if (ptr
+ 11 > limit
)
139 LogInfo("AddEDNS0Option: not enough space");
142 m
->omsg
.h
.numAdditionals
++;
144 ptr
[1] = (mDNSu8
) (kDNSType_OPT
>> 8);
145 ptr
[2] = (mDNSu8
) (kDNSType_OPT
& 0xFF);
146 ptr
[3] = (mDNSu8
) (len
>> 8);
147 ptr
[4] = (mDNSu8
) (len
& 0xFF);
149 ptr
[6] = 0; // version
152 ptr
[9] = 0; // rdlength
153 ptr
[10] = 0; // rdlength
155 debugf("AddEDNS0 option");
160 // Currently RD and CD bit should be copied if present in the request or cleared if
161 // not present in the request. RD bit is normally set in the response and hence the
162 // cache reflects the right value. CD bit behaves differently. If the CD bit is set
163 // the first time, the cache retains it, if it is present in response (assuming the
164 // upstream server does it right). Next time through we should not use the cached
165 // value of the CD bit blindly. It depends on whether it was in the request or not.
166 mDNSlocal mDNSOpaque16
SetResponseFlags(DNSProxyClient
*pc
, const mDNSOpaque16 responseFlags
)
168 mDNSOpaque16 rFlags
= responseFlags
;
170 if (pc
->requestFlags
.b
[0] & kDNSFlag0_RD
)
171 rFlags
.b
[0] |= kDNSFlag0_RD
;
173 rFlags
.b
[0] &= ~kDNSFlag0_RD
;
175 if (pc
->requestFlags
.b
[1] & kDNSFlag1_CD
)
176 rFlags
.b
[1] |= kDNSFlag1_CD
;
178 rFlags
.b
[1] &= ~kDNSFlag1_CD
;
183 mDNSlocal mDNSu8
*AddResourceRecords(mDNS
*const m
, DNSProxyClient
*pc
, mDNSu8
**prevptr
, mStatus
*error
)
188 int len
= sizeof(DNSMessageHeader
);
189 mDNSu8
*orig
= m
->omsg
.data
;
190 mDNSBool first
= mDNStrue
;
191 mDNSu8
*ptr
= mDNSNULL
;
194 CacheRecord
*nsec
= mDNSNULL
;
195 CacheRecord
*soa
= mDNSNULL
;
196 CacheRecord
*cname
= mDNSNULL
;
198 domainname tempQName
;
199 mDNSu32 tempQNameHash
;
201 *error
= mStatus_NoError
;
212 limit
= m
->omsg
.data
+ MIN_DNS_MESSAGE_SIZE
;
216 limit
= (pc
->rcvBufSize
> AbsoluteMaxDNSMessageData
? m
->omsg
.data
+ AbsoluteMaxDNSMessageData
: m
->omsg
.data
+ pc
->rcvBufSize
);
221 // For TCP, limit is not determined by EDNS0 but by 16 bit rdlength field and
222 // AbsoluteMaxDNSMessageData is smaller than 64k.
223 limit
= m
->omsg
.data
+ AbsoluteMaxDNSMessageData
;
225 LogInfo("AddResourceRecords: Limit is %d", limit
- m
->omsg
.data
);
227 AssignDomainName(&tempQName
, &pc
->qname
);
228 tempQNameHash
= DomainNameHashValue(&tempQName
);
231 nsec
= soa
= cname
= mDNSNULL
;
232 slot
= HashSlot(&tempQName
);
234 cg
= CacheGroupForName(m
, slot
, tempQNameHash
, &tempQName
);
237 LogInfo("AddResourceRecords: CacheGroup not found for %##s", tempQName
.c
);
238 *error
= mStatus_NoSuchRecord
;
241 // Set ValidatingResponse so that you can get RRSIGs also matching
244 pc
->q
.ValidatingResponse
= 1;
245 for (cr
= cg
->members
; cr
; cr
= cr
->next
)
247 if (SameNameRecordAnswersQuestion(&cr
->resrec
, &pc
->q
))
251 // If this is the first time, initialize the header and the question.
252 // This code needs to be here so that we can use the responseFlags from the
254 mDNSOpaque16 responseFlags
= SetResponseFlags(pc
, cr
->responseFlags
);
255 InitializeDNSMessage(&m
->omsg
.h
, pc
->msgid
, responseFlags
);
256 ptr
= putQuestion(&m
->omsg
, m
->omsg
.data
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
, &pc
->qname
, pc
->q
.qtype
, pc
->q
.qclass
);
259 LogInfo("AddResourceRecords: putQuestion NULL for %##s (%s)", &pc
->qname
.c
, DNSTypeName(pc
->q
.qtype
));
264 // - For NegativeAnswers there is nothing to add
265 // - If DNSSECOK is set, we also automatically lookup the RRSIGs which
266 // will also be returned. If the client is explicitly looking up
267 // a DNSSEC record (e.g., DNSKEY, DS) we should return the response.
268 // DNSSECOK bit only influences whether we add the RRSIG or not.
269 if (cr
->resrec
.RecordType
!= kDNSRecordTypePacketNegative
)
271 LogInfo("AddResourceRecords: Answering question with %s", CRDisplayString(m
, cr
));
272 ttl
= cr
->resrec
.rroriginalttl
- (now
- cr
->TimeRcvd
) / mDNSPlatformOneSecond
;
273 ptr
= PutResourceRecordTTLWithLimit(&m
->omsg
, ptr
, &m
->omsg
.h
.numAnswers
, &cr
->resrec
, ttl
, limit
);
282 // If we have nsecs (wildcard expanded answer or negative response), add them
283 // in the additional section below if the DNSSECOK bit is set
284 if (pc
->DNSSECOK
&& cr
->nsec
)
286 LogInfo("AddResourceRecords: nsec set for %s", CRDisplayString(m
,cr
));
291 LogInfo("AddResourceRecords: soa set for %s", CRDisplayString(m
,cr
));
294 // If we are using CNAME to answer a question and CNAME is not the type we
295 // are looking for, note down the CNAME record so that we can follow them
296 // later. Before we follow the CNAME, print the RRSIGs and any nsec (wildcard
298 if ((pc
->q
.qtype
!= cr
->resrec
.rrtype
) && cr
->resrec
.rrtype
== kDNSType_CNAME
)
300 LogInfo("AddResourceRecords: cname set for %s", CRDisplayString(m
,cr
));
305 // Along with the nsec records, we also cache the SOA record. For non-DNSSEC question, we need
306 // to send the SOA back. Normally we either cache the SOA record (non-DNSSEC question) pointed
307 // to by "cr->soa" or the NSEC/SOA records along with their RRSIGs (DNSSEC question) pointed to
308 // by "cr->nsec". Two cases:
310 // - if we issue a DNSSEC question followed by non-DNSSEC question for the same name,
311 // we only have the nsec records and we need to filter the SOA record alone for the
312 // non-DNSSEC questions.
314 // - if we issue a non-DNSSEC question followed by DNSSEC question for the same name,
315 // the "core" flushes the cache entry and re-issue the question with EDNS0/DOK bit and
316 // in this case we return all the DNSSEC records we have.
317 for (; nsec
; nsec
= nsec
->next
)
319 if (!pc
->DNSSECOK
&& DNSSECRecordType(nsec
->resrec
.rrtype
))
321 LogInfo("AddResourceRecords:NSEC Answering question with %s", CRDisplayString(m
, nsec
));
322 ttl
= nsec
->resrec
.rroriginalttl
- (now
- nsec
->TimeRcvd
) / mDNSPlatformOneSecond
;
323 ptr
= PutResourceRecordTTLWithLimit(&m
->omsg
, ptr
, &m
->omsg
.h
.numAuthorities
, &nsec
->resrec
, ttl
, limit
);
334 LogInfo("AddResourceRecords: SOA Answering question with %s", CRDisplayString(m
, soa
));
335 ptr
= PutResourceRecordTTLWithLimit(&m
->omsg
, ptr
, &m
->omsg
.h
.numAuthorities
, &soa
->resrec
, soa
->resrec
.rroriginalttl
, limit
);
346 AssignDomainName(&tempQName
, &cname
->resrec
.rdata
->u
.name
);
347 tempQNameHash
= DomainNameHashValue(&tempQName
);
352 LogInfo("AddResourceRecords: Did not find any valid ResourceRecords");
353 *error
= mStatus_NoSuchRecord
;
358 ptr
= AddEDNS0Option(m
, ptr
, limit
);
365 // orig = ptr; Commented out to avoid ‘value never read’ error message
367 LogInfo("AddResourceRecord: Added %d bytes to the packet", len
);
371 mDNSlocal
void ProxyClientCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
373 DNSProxyClient
*pc
= question
->QuestionContext
;
374 DNSProxyClient
**ppc
= &DNSProxyClients
;
382 LogInfo("ProxyClientCallback: ResourceRecord %s", RRDisplayString(m
, answer
));
384 // We asked for validation and not timed out yet, then wait for the DNSSEC result.
385 // We have to set the AD bit in the response if it is secure which can't be done
386 // till we get the DNSSEC result back (indicated by QC_dnssec).
387 if (question
->ValidationRequired
)
394 if (((now
- question
->StopTime
) < 0) && AddRecord
!= QC_dnssec
)
396 LogInfo("ProxyClientCallback: No DNSSEC answer yet for Question %##s (%s), AddRecord %d, answer %s", question
->qname
.c
,
397 DNSTypeName(question
->qtype
), AddRecord
, RRDisplayString(m
, answer
));
402 if (answer
->RecordType
!= kDNSRecordTypePacketNegative
)
404 if (answer
->rrtype
!= question
->qtype
)
406 // Wait till we get called for the real response
407 LogInfo("ProxyClientCallback: Received %s, not answering yet", RRDisplayString(m
, answer
));
411 ptr
= AddResourceRecords(m
, pc
, &prevptr
, &error
);
414 LogInfo("ProxyClientCallback: AddResourceRecords NULL for %##s (%s)", &pc
->qname
.c
, DNSTypeName(pc
->q
.qtype
));
415 if (error
== mStatus_NoError
&& prevptr
)
417 // No space to add the record. Set the Truncate bit for UDP.
419 // TBD: For TCP, we need to send the rest of the data. But finding out what is left
420 // is harder. We should allocate enough buffer in the first place to send all
424 m
->omsg
.h
.flags
.b
[0] |= kDNSFlag0_TC
;
429 LogInfo("ProxyClientCallback: ERROR!! Not enough space to return in TCP for %##s (%s)", &pc
->qname
.c
, DNSTypeName(pc
->q
.qtype
));
435 mDNSOpaque16 flags
= { { kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
, kDNSFlag1_RC_ServFail
} };
436 // We could not find the record for some reason. Return a response, so that the client
437 // is not waiting forever.
438 LogInfo("ProxyClientCallback: No response");
439 if (!mDNSOpaque16IsZero(pc
->q
.responseFlags
))
440 flags
= pc
->q
.responseFlags
;
441 InitializeDNSMessage(&m
->omsg
.h
, pc
->msgid
, flags
);
442 ptr
= putQuestion(&m
->omsg
, m
->omsg
.data
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
, &pc
->qname
, pc
->q
.qtype
, pc
->q
.qclass
);
445 LogInfo("ProxyClientCallback: putQuestion NULL for %##s (%s)", &pc
->qname
.c
, DNSTypeName(pc
->q
.qtype
));
450 if (question
->ValidationRequired
)
452 if (question
->ValidationState
== DNSSECValDone
&& question
->ValidationStatus
== DNSSEC_Secure
)
454 LogInfo("ProxyClientCallback: Setting AD bit for Question %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
455 m
->omsg
.h
.flags
.b
[1] |= kDNSFlag1_AD
;
459 // If some external resolver sets the AD bit and we did not validate the response securely, don't set
460 // the AD bit. It is possible that we did not see all the records that the upstream resolver saw or
461 // a buggy implementation somewhere.
462 if (m
->omsg
.h
.flags
.b
[1] & kDNSFlag1_AD
)
464 LogInfo("ProxyClientCallback: AD bit set in the response for response that was not validated locally %##s (%s)",
465 question
->qname
.c
, DNSTypeName(question
->qtype
));
466 m
->omsg
.h
.flags
.b
[1] &= ~kDNSFlag1_AD
;
471 debugf("ProxyClientCallback: InterfaceID is %p for response to client", pc
->interfaceID
);
475 mDNSSendDNSMessage(m
, &m
->omsg
, ptr
, pc
->interfaceID
, (UDPSocket
*)pc
->socket
, &pc
->addr
, pc
->port
, mDNSNULL
, mDNSNULL
, mDNSfalse
);
479 mDNSSendDNSMessage(m
, &m
->omsg
, ptr
, pc
->interfaceID
, mDNSNULL
, &pc
->addr
, pc
->port
, (TCPSocket
*)pc
->socket
, mDNSNULL
, mDNSfalse
);
483 mDNS_StopQuery(m
, question
);
485 while (*ppc
&& *ppc
!= pc
)
489 LogMsg("ProxyClientCallback: question %##s (%s) not found", question
->qname
.c
, DNSTypeName(question
->qtype
));
493 mDNSPlatformDisposeProxyContext(pc
->context
);
494 FreeDNSProxyClient(pc
);
497 mDNSlocal
void SendError(mDNS
*const m
, void *socket
, void *const pkt
, const mDNSu8
*const end
, const mDNSAddr
*dstaddr
,
498 const mDNSIPPort dstport
, const mDNSInterfaceID InterfaceID
, mDNSBool tcp
, void *context
, mDNSu8 rcode
)
500 int pktlen
= (int)(end
- (mDNSu8
*)pkt
);
501 DNSMessage
*msg
= (DNSMessage
*)pkt
;
503 // RFC 1035 requires that we copy the question back and RFC 2136 is okay with sending nothing
504 // in the body or send back whatever we get for updates. It is easy to return whatever we get
505 // in the question back to the responder. We return as much as we can fit in our standard
507 if (pktlen
> AbsoluteMaxDNSMessageData
)
508 pktlen
= AbsoluteMaxDNSMessageData
;
510 mDNSPlatformMemCopy(&m
->omsg
.h
, &msg
->h
, sizeof(DNSMessageHeader
));
511 m
->omsg
.h
.flags
.b
[0] |= kDNSFlag0_QR_Response
;
512 m
->omsg
.h
.flags
.b
[1] = rcode
;
513 mDNSPlatformMemCopy(m
->omsg
.data
, (mDNSu8
*)&msg
->h
.numQuestions
, pktlen
);
516 mDNSSendDNSMessage(m
, &m
->omsg
, (mDNSu8
*)&m
->omsg
+ pktlen
, InterfaceID
, socket
, dstaddr
, dstport
, mDNSNULL
, mDNSNULL
,
521 mDNSSendDNSMessage(m
, &m
->omsg
, (mDNSu8
*)&m
->omsg
+ pktlen
, InterfaceID
, mDNSNULL
, dstaddr
, dstport
, (TCPSocket
*)socket
,
522 mDNSNULL
, mDNSfalse
);
524 mDNSPlatformDisposeProxyContext(context
);
527 mDNSlocal DNSQuestion
*IsDuplicateClient(const mDNS
*const m
, const mDNSAddr
*const addr
, const mDNSIPPort port
, const mDNSOpaque16 id
,
528 const DNSQuestion
*const question
)
534 for (pc
= DNSProxyClients
; pc
; pc
= pc
->next
)
536 if (mDNSSameAddress(&pc
->addr
, addr
) &&
537 mDNSSameIPPort(pc
->port
, port
) &&
538 mDNSSameOpaque16(pc
->msgid
, id
) &&
539 pc
->q
.qtype
== question
->qtype
&&
540 pc
->q
.qclass
== question
->qclass
&&
541 SameDomainName(&pc
->qname
, &question
->qname
))
543 LogInfo("IsDuplicateClient: Found a duplicate client in the list");
550 mDNSlocal mDNSBool
CheckDNSProxyIpIntf(const mDNS
*const m
, mDNSInterfaceID InterfaceID
)
553 mDNSu32 ip_ifindex
= (mDNSu32
)(unsigned long)InterfaceID
;
555 LogInfo("CheckDNSProxyIpIntf: Check for ifindex[%d] in stored input interface list: [%d] [%d] [%d] [%d] [%d]",
556 ip_ifindex
, m
->dp_ipintf
[0], m
->dp_ipintf
[1], m
->dp_ipintf
[2], m
->dp_ipintf
[3], m
->dp_ipintf
[4]);
560 for (i
= 0; i
< MaxIp
; i
++)
562 if (ip_ifindex
== m
->dp_ipintf
[i
])
567 LogMsg("CheckDNSProxyIpIntf: ifindex[%d] not in stored input interface list: [%d] [%d] [%d] [%d] [%d]",
568 ip_ifindex
, m
->dp_ipintf
[0], m
->dp_ipintf
[1], m
->dp_ipintf
[2], m
->dp_ipintf
[3], m
->dp_ipintf
[4]);
574 mDNSlocal
void ProxyCallbackCommon(mDNS
*const m
, void *socket
, void *const pkt
, const mDNSu8
*const end
, const mDNSAddr
*const srcaddr
,
575 const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, const mDNSIPPort dstport
, const mDNSInterfaceID InterfaceID
, mDNSBool tcp
, void *context
)
577 DNSMessage
*msg
= (DNSMessage
*)pkt
;
580 DNSQuestion q
, *qptr
;
582 const mDNSu8
*optRR
= mDNSNULL
;
584 DNSProxyClient
**ppc
= &DNSProxyClients
;
589 debugf("ProxyCallbackCommon: DNS Query coming from InterfaceID %p", InterfaceID
);
590 // Ignore if the DNS Query is not from a Valid Input InterfaceID
591 if (!CheckDNSProxyIpIntf(m
, InterfaceID
))
593 LogMsg("ProxyCallbackCommon: Rejecting DNS Query coming from InterfaceID %p", InterfaceID
);
597 if ((unsigned)(end
- (mDNSu8
*)pkt
) < sizeof(DNSMessageHeader
))
599 debugf("ProxyCallbackCommon: DNS Message from %#a:%d to %#a:%d length %d too short", srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), end
- (mDNSu8
*)pkt
);
603 QR_OP
= (mDNSu8
)(msg
->h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
604 if (QR_OP
!= kDNSFlag0_QR_Query
)
606 LogInfo("ProxyCallbackCommon: Not a query(%d) for pkt from %#a:%d", QR_OP
, srcaddr
, mDNSVal16(srcport
));
607 SendError(m
, socket
, pkt
, end
, srcaddr
, srcport
, InterfaceID
, tcp
, context
, kDNSFlag1_RC_NotImpl
);
611 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
612 ptr
= (mDNSu8
*)&msg
->h
.numQuestions
;
613 msg
->h
.numQuestions
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
614 msg
->h
.numAnswers
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]);
615 msg
->h
.numAuthorities
= (mDNSu16
)((mDNSu16
)ptr
[4] << 8 | ptr
[5]);
616 msg
->h
.numAdditionals
= (mDNSu16
)((mDNSu16
)ptr
[6] << 8 | ptr
[7]);
618 if (msg
->h
.numQuestions
!= 1 || msg
->h
.numAnswers
|| msg
->h
.numAuthorities
)
620 LogInfo("ProxyCallbackCommon: Malformed pkt from %#a:%d, Q:%d, An:%d, Au:%d", srcaddr
, mDNSVal16(srcport
),
621 msg
->h
.numQuestions
, msg
->h
.numAnswers
, msg
->h
.numAuthorities
);
622 SendError(m
, socket
, pkt
, end
, srcaddr
, srcport
, InterfaceID
, tcp
, context
, kDNSFlag1_RC_FormErr
);
626 ptr
= getQuestion(msg
, ptr
, end
, InterfaceID
, &q
);
629 LogInfo("ProxyCallbackCommon: Question cannot be parsed for pkt from %#a:%d", srcaddr
, mDNSVal16(srcport
));
630 SendError(m
, socket
, pkt
, end
, srcaddr
, srcport
, InterfaceID
, tcp
, context
, kDNSFlag1_RC_FormErr
);
635 LogInfo("ProxyCallbackCommon: Question %##s (%s)", q
.qname
.c
, DNSTypeName(q
.qtype
));
637 ptr
= LocateOptRR(msg
, end
, 0);
641 ptr
= skipResourceRecord(msg
, ptr
, end
);
642 // Be liberal and ignore the EDNS0 option if we can't parse it properly
645 LogInfo("ProxyCallbackCommon: EDNS0 cannot be parsed for pkt from %#a:%d, ignoring", srcaddr
, mDNSVal16(srcport
));
649 optLen
= ptr
- optRR
;
650 LogInfo("ProxyCallbackCommon: EDNS0 opt length %d present in Question %##s (%s)", optLen
, q
.qname
.c
, DNSTypeName(q
.qtype
));
655 LogInfo("ProxyCallbackCommon: EDNS0 opt not present in Question %##s (%s), ptr %p", q
.qname
.c
, DNSTypeName(q
.qtype
), ptr
);
658 qptr
= IsDuplicateClient(m
, srcaddr
, srcport
, msg
->h
.id
, &q
);
661 LogInfo("ProxyCallbackCommon: Found a duplicate for pkt from %#a:%d, ignoring this", srcaddr
, mDNSVal16(srcport
));
664 pc
= mDNSPlatformMemAllocate(sizeof(DNSProxyClient
));
667 LogMsg("ProxyCallbackCommon: Memory failure for pkt from %#a:%d, ignoring this", srcaddr
, mDNSVal16(srcport
));
670 mDNSPlatformMemZero(pc
, sizeof(DNSProxyClient
));
673 pc
->msgid
= msg
->h
.id
;
674 pc
->interfaceID
= InterfaceID
; // input interface
677 pc
->requestFlags
= msg
->h
.flags
;
678 pc
->context
= context
;
679 AssignDomainName(&pc
->qname
, &q
.qname
);
682 if (!ParseEDNS0(pc
, optRR
, optLen
, end
))
684 LogInfo("ProxyCallbackCommon: Invalid EDNS0 option for pkt from %#a:%d, ignoring this", srcaddr
, mDNSVal16(srcport
));
688 pc
->optRR
= mDNSPlatformMemAllocate(optLen
);
691 LogMsg("ProxyCallbackCommon: Memory failure for pkt from %#a:%d, ignoring this", srcaddr
, mDNSVal16(srcport
));
692 FreeDNSProxyClient(pc
);
695 mDNSPlatformMemCopy(pc
->optRR
, optRR
, optLen
);
700 debugf("ProxyCallbackCommon: DNS Query forwarding to interface index %d", m
->dp_opintf
);
701 mDNS_SetupQuestion(&pc
->q
, (mDNSInterfaceID
)(unsigned long)m
->dp_opintf
, &q
.qname
, q
.qtype
, ProxyClientCallback
, pc
);
702 pc
->q
.TimeoutQuestion
= 1;
703 // Set ReturnIntermed so that we get the negative responses
704 pc
->q
.ReturnIntermed
= mDNStrue
;
705 pc
->q
.ProxyQuestion
= mDNStrue
;
706 pc
->q
.ProxyDNSSECOK
= pc
->DNSSECOK
;
707 pc
->q
.responseFlags
= zeroID
;
710 if (!(msg
->h
.flags
.b
[1] & kDNSFlag1_CD
) && pc
->q
.qtype
!= kDNSType_RRSIG
&& pc
->q
.qtype
!= kDNSQType_ANY
)
712 LogInfo("ProxyCallbackCommon: Setting Validation required bit for %#a:%d, validating %##s (%s)", srcaddr
, mDNSVal16(srcport
),
713 q
.qname
.c
, DNSTypeName(q
.qtype
));
714 pc
->q
.ValidationRequired
= DNSSEC_VALIDATION_SECURE
;
718 LogInfo("ProxyCallbackCommon: CD bit not set OR not a valid type for %#a:%d, not validating %##s (%s)", srcaddr
, mDNSVal16(srcport
),
719 q
.qname
.c
, DNSTypeName(q
.qtype
));
724 LogInfo("ProxyCallbackCommon: DNSSEC OK bit not set for %#a:%d, not validating %##s (%s)", srcaddr
, mDNSVal16(srcport
),
725 q
.qname
.c
, DNSTypeName(q
.qtype
));
729 ppc
= &((*ppc
)->next
);
732 mDNS_StartQuery(m
, &pc
->q
);
735 mDNSexport
void ProxyUDPCallback(mDNS
*const m
, void *socket
, void *const pkt
, const mDNSu8
*const end
, const mDNSAddr
*const srcaddr
,
736 const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, const mDNSIPPort dstport
, const mDNSInterfaceID InterfaceID
, void *context
)
738 LogInfo("ProxyUDPCallback: DNS Message from %#a:%d to %#a:%d length %d", srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), end
- (mDNSu8
*)pkt
);
739 ProxyCallbackCommon(m
, socket
, pkt
, end
, srcaddr
, srcport
, dstaddr
, dstport
, InterfaceID
, mDNSfalse
, context
);
742 mDNSexport
void ProxyTCPCallback(mDNS
*const m
, void *socket
, void *const pkt
, const mDNSu8
*const end
, const mDNSAddr
*const srcaddr
,
743 const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, const mDNSIPPort dstport
, const mDNSInterfaceID InterfaceID
, void *context
)
745 LogInfo("ProxyTCPCallback: DNS Message from %#a:%d to %#a:%d length %d", srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), end
- (mDNSu8
*)pkt
);
747 // If the connection was closed from the other side or incoming packet does not match stored input interface list, locate the client
748 // state and free it.
749 if (((end
- (mDNSu8
*)pkt
) == 0) || (!CheckDNSProxyIpIntf(m
, InterfaceID
)))
751 DNSProxyClient
**ppc
= &DNSProxyClients
;
752 DNSProxyClient
**prevpc
;
755 while (*ppc
&& (*ppc
)->socket
!= socket
)
762 mDNSPlatformDisposeProxyContext(socket
);
763 LogMsg("ProxyTCPCallback: socket cannot be found");
766 *prevpc
= (*ppc
)->next
;
767 LogInfo("ProxyTCPCallback: free");
768 mDNSPlatformDisposeProxyContext(socket
);
769 FreeDNSProxyClient(*ppc
);
772 ProxyCallbackCommon(m
, socket
, pkt
, end
, srcaddr
, srcport
, dstaddr
, dstport
, InterfaceID
, mDNStrue
, context
);
775 mDNSexport
void DNSProxyInit(mDNS
*const m
, mDNSu32 IpIfArr
[MaxIp
], mDNSu32 OpIf
)
779 // Store DNSProxy Interface fields in mDNS struct
780 for (i
= 0; i
< MaxIp
; i
++)
781 m
->dp_ipintf
[i
] = IpIfArr
[i
];
784 LogInfo("DNSProxyInit Storing interface list: Input [%d, %d, %d, %d, %d] Output [%d]", m
->dp_ipintf
[0],
785 m
->dp_ipintf
[1], m
->dp_ipintf
[2], m
->dp_ipintf
[3], m
->dp_ipintf
[4], m
->dp_opintf
);
788 mDNSexport
void DNSProxyTerminate(mDNS
*const m
)
792 // Clear DNSProxy Interface fields from mDNS struct
793 for (i
= 0; i
< MaxIp
; i
++)
797 LogInfo("DNSProxyTerminate Cleared interface list: Input [%d, %d, %d, %d, %d] Output [%d]", m
->dp_ipintf
[0],
798 m
->dp_ipintf
[1], m
->dp_ipintf
[2], m
->dp_ipintf
[3], m
->dp_ipintf
[4], m
->dp_opintf
);
800 #else // UNICAST_DISABLED
802 mDNSexport
void ProxyUDPCallback(mDNS
*const m
, void *socket
, void *const pkt
, const mDNSu8
*const end
, const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, const mDNSIPPort dstport
, const mDNSInterfaceID InterfaceID
, void *context
)
816 mDNSexport
void ProxyTCPCallback(mDNS
*const m
, void *socket
, void *const pkt
, const mDNSu8
*const end
, const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, const mDNSIPPort dstport
, const mDNSInterfaceID InterfaceID
, void *context
)
830 mDNSexport
void DNSProxyInit(mDNS
*const m
, mDNSu32 IpIfArr
[MaxIp
], mDNSu32 OpIf
)
836 extern void DNSProxyTerminate(mDNS
*const m
)
842 #endif // UNICAST_DISABLED