Autogenerated with:
cp dom/.clang-format netwerk/ && mach format netwerk/**.{cpp,h,mm}
Manual fixes:
* mozurl/cbindgen.toml (including headers earlier)
* NetlinkService.h (forward-declaring a necessary struct)
* nsIWebSocketChannel.idl (forward-declaring OriginAttributes).
* nsAsyncRedirectVerifyHelper.h (forward-declaring nsIEventTarget)
* CapsuleEncoder.h gets a missing Capsule forward-decl.
* WebSocketConnectionBase.h gets some missing includes.
* HappyEyeballsConnectionAttempt gets some missing includes.
* nsUDPSocket missed nsSocketTransportService2.h for OnSocketThread().
* HttpInfo missed a forward declaration.
* MockHttpAuth missed an nsCOMPtr include.
* nsHttpAuthManager missed a forward declaration for nsIHttpAuthCache.
* WebTransportSessionProxy was using mozilla::Mutex in a member without
including it.
* win32 fixes to keep include order because windows headers suck.
* nsInputStreamPump needs an Atomics.h include.
Differential Revision: https://phabricator.services.mozilla.com/D311696
177 lines
5.2 KiB
C++
177 lines
5.2 KiB
C++
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include <arpa/inet.h>
|
|
#include <dns_sd.h>
|
|
#include <poll.h>
|
|
|
|
#include "GetAddrInfo.h"
|
|
#include "mozilla/StaticPrefs_network.h"
|
|
#include "mozilla/glean/NetwerkMetrics.h"
|
|
#include "mozilla/net/DNSPacket.h"
|
|
#include "nsIDNSService.h"
|
|
|
|
namespace mozilla::net {
|
|
|
|
#define LOG(msg, ...) \
|
|
MOZ_LOG(gGetAddrInfoLog, LogLevel::Debug, ("[DNS]: " msg, ##__VA_ARGS__))
|
|
|
|
struct DNSContext {
|
|
nsresult mRv = NS_OK;
|
|
TypeRecordResultType* mResult;
|
|
nsCString mHost;
|
|
uint32_t* mTTL;
|
|
};
|
|
|
|
// Callback for DNSServiceQueryRecord
|
|
void QueryCallback(DNSServiceRef aSDRef, DNSServiceFlags aFlags,
|
|
uint32_t aInterfaceIndex, DNSServiceErrorType aErrorCode,
|
|
const char* aFullname, uint16_t aRRType, uint16_t aRRClass,
|
|
uint16_t aRDLen, const void* aRdata, uint32_t aTtl,
|
|
void* aContext) {
|
|
struct DNSContext* context = (struct DNSContext*)aContext;
|
|
|
|
LOG("DNS response name: %s type: %u rdlen %u class %u ttl %u", aFullname,
|
|
aRRType, aRDLen, aRRClass, aTtl);
|
|
|
|
if (aErrorCode != kDNSServiceErr_NoError) {
|
|
LOG("Error resolving record: %d\n", aErrorCode);
|
|
context->mRv = NS_ERROR_UNKNOWN_HOST;
|
|
return;
|
|
}
|
|
|
|
if (NS_FAILED(context->mRv)) {
|
|
LOG("Parsing already failed for a previous record");
|
|
return;
|
|
}
|
|
|
|
// Skip intermediate records (e.g. CNAMEs) returned when
|
|
// kDNSServiceFlagsReturnIntermediates is set.
|
|
if (aRRType != TRRTYPE_HTTPSSVC) {
|
|
return;
|
|
}
|
|
|
|
// Process the rdata for HTTPS records (type 65)
|
|
if (aRDLen == 0) {
|
|
context->mRv = NS_ERROR_UNKNOWN_HOST;
|
|
return;
|
|
}
|
|
|
|
auto fullname = Substring(nsDependentCString(aFullname), 0, -1);
|
|
if (fullname.Length() && fullname.Last() == '.') {
|
|
// The fullname argument is always FQDN
|
|
fullname.Rebind(aFullname, fullname.Length() - 1);
|
|
}
|
|
|
|
struct SVCB parsed;
|
|
nsresult rv = DNSPacket::ParseHTTPS(
|
|
aRDLen, parsed, 0, (const unsigned char*)aRdata, aRDLen, fullname);
|
|
if (NS_FAILED(rv)) {
|
|
LOG("ParseHTTPS failed\n");
|
|
context->mRv = rv;
|
|
return;
|
|
}
|
|
|
|
if (parsed.mSvcDomainName.IsEmpty() && parsed.mSvcFieldPriority == 0) {
|
|
// For AliasMode SVCB RRs, a TargetName of "." indicates that the
|
|
// service is not available or does not exist.
|
|
return;
|
|
}
|
|
|
|
if (parsed.mSvcFieldPriority == 0) {
|
|
// Alias form SvcDomainName must not have the "." value (empty)
|
|
if (parsed.mSvcDomainName.IsEmpty()) {
|
|
context->mRv = NS_ERROR_UNEXPECTED;
|
|
return;
|
|
}
|
|
LOG("alias mode %s -> %s", context->mHost.get(),
|
|
parsed.mSvcDomainName.get());
|
|
context->mHost = parsed.mSvcDomainName;
|
|
ToLowerCase(context->mHost);
|
|
return;
|
|
}
|
|
|
|
if (!context->mResult->is<TypeRecordHTTPSSVC>()) {
|
|
*context->mResult = mozilla::AsVariant(CopyableTArray<SVCB>());
|
|
}
|
|
auto& results = context->mResult->as<TypeRecordHTTPSSVC>();
|
|
results.AppendElement(parsed);
|
|
*context->mTTL = std::min<uint32_t>(*context->mTTL, aTtl);
|
|
}
|
|
|
|
nsresult ResolveHTTPSRecordImpl(const nsACString& aHost,
|
|
nsIDNSService::DNSFlags aFlags,
|
|
TypeRecordResultType& aResult, uint32_t& aTTL) {
|
|
nsAutoCString host(aHost);
|
|
nsAutoCString cname;
|
|
|
|
if (xpc::IsInAutomation() &&
|
|
!StaticPrefs::network_dns_native_https_query_in_automation()) {
|
|
return NS_ERROR_UNKNOWN_HOST;
|
|
}
|
|
|
|
LOG("resolving %s\n", host.get());
|
|
TimeStamp startTime = TimeStamp::Now();
|
|
|
|
struct DNSContext context{
|
|
.mResult = &aResult,
|
|
.mHost = host,
|
|
.mTTL = &aTTL,
|
|
};
|
|
|
|
DNSServiceRef sdRef;
|
|
DNSServiceErrorType err;
|
|
|
|
err = DNSServiceQueryRecord(&sdRef, kDNSServiceFlagsReturnIntermediates,
|
|
0, // All interfaces
|
|
host.get(), TRRTYPE_HTTPSSVC, kDNSServiceClass_IN,
|
|
QueryCallback, &context);
|
|
|
|
if (err != kDNSServiceErr_NoError) {
|
|
LOG("DNSServiceQueryRecord failed: %d\n", err);
|
|
return NS_ERROR_UNKNOWN_HOST;
|
|
}
|
|
|
|
struct pollfd pfd = {
|
|
.fd = DNSServiceRefSockFD(sdRef),
|
|
.events = POLLIN,
|
|
};
|
|
|
|
// If the domain queried results in NXDOMAIN, then QueryCallback will
|
|
// never get called, and poll will hang forever. We need to use a
|
|
// timeout so that poll() eventually returns.
|
|
int result =
|
|
poll(&pfd, 1, StaticPrefs::network_dns_native_https_timeout_mac_msec());
|
|
if (result > 0 && (pfd.revents & POLLIN)) {
|
|
// Process the result
|
|
DNSServiceProcessResult(sdRef);
|
|
} else if (result < 0) {
|
|
LOG("poll() failed");
|
|
} else if (result == 0) {
|
|
LOG("poll timed out");
|
|
}
|
|
|
|
// Cleanup
|
|
DNSServiceRefDeallocate(sdRef);
|
|
mozilla::glean::networking::dns_native_https_call_time.AccumulateRawDuration(
|
|
TimeStamp::Now() - startTime);
|
|
|
|
LOG("resolving %s done %x ttl=%u", host.get(), context.mRv, aTTL);
|
|
if (NS_FAILED(context.mRv)) {
|
|
return context.mRv;
|
|
}
|
|
if (aResult.is<Nothing>()) {
|
|
// The call succeeded, but no HTTPS records were found.
|
|
return NS_ERROR_UNKNOWN_HOST;
|
|
}
|
|
if (aTTL == UINT32_MAX) {
|
|
aTTL = 60; // Defaults to 60 seconds
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
void DNSThreadShutdown() {}
|
|
|
|
} // namespace mozilla::net
|