tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 516286fcfcb6d4c50c269a7f76b40bc3af566c26
parent 7f239a90c98674e59c153eef3ff1122ed4ce3270
Author: smayya <smayya@mozilla.com>
Date:   Sat,  1 Nov 2025 12:59:47 +0000

Bug 1992696 - Add console logging for Local Network Access. r=necko-reviewers,Gijs,jesup

This patch adds browser and web console logging for Local Network Access (LNA)
events to improve debugging and visibility:

- Added localized strings in necko.properties for two console messages
- Log in ProcessLNAActions (before permission prompt): includes all context
  except prompt_action
- Reports error to ReportToConsoleByWindowID (Web Console/F12) for better visibility
 or Browser Console if former fails
- Messages are info-level under "Security" category

Differential Revision: https://phabricator.services.mozilla.com/D269207

Diffstat:
Mnetwerk/locales/en-US/necko.properties | 5+++++
Mnetwerk/protocol/http/HttpChannelChild.cpp | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mnetwerk/protocol/http/HttpChannelChild.h | 13+++++++++++++
Mnetwerk/protocol/http/HttpChannelParent.cpp | 10++++++++++
Mnetwerk/protocol/http/HttpChannelParent.h | 6++++++
Mnetwerk/protocol/http/PHttpChannel.ipdl | 6++++++
Mnetwerk/protocol/http/nsHttpChannel.cpp | 114++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mnetwerk/protocol/http/nsHttpChannel.h | 23++++++++++++++---------
Mnetwerk/protocol/http/nsHttpTransaction.cpp | 5+++++
9 files changed, 297 insertions(+), 36 deletions(-)

diff --git a/netwerk/locales/en-US/necko.properties b/netwerk/locales/en-US/necko.properties @@ -108,3 +108,8 @@ APIDeprecationWarning=Warning: ‘%1$S’ deprecated, please use ‘%2$S’ ResourceBlockedORB=The resource at “%1$S” was blocked by OpaqueResponseBlocking. Reason: “%2$S”. InvalidHTTPResponseStatusLine=The status line of the HTTP response is invalid + +# LOCALIZATION NOTE (LocalNetworkAccessDetected): %1$S is top-level site, %2$S is initiator, %3$S is target URL, %4$S is target IP, %5$S is port, %6$S is mechanism (e.g., fetch, xhr, websocket), %7$S is secure context (true or false), %8$S is prompt action (values: "Allow", "Deny", or "(empty)" if no prompt shown) +LocalNetworkAccessDetected=Local Network Access detected: top-level site “%1$S”, initiator “%2$S”, accessing target “%3$S” (%4$S:%5$S) via %6$S. Secure context: %7$S, prompt action: %8$S +# LOCALIZATION NOTE (LocalNetworkAccessPermissionRequired): %1$S is top-level site, %2$S is initiator, %3$S is target URL, %4$S is target IP, %5$S is port, %6$S is mechanism (e.g., fetch, xhr, websocket), %7$S is secure context (true or false) +LocalNetworkAccessPermissionRequired=Local Network Access permission required: top-level site “%1$S”, initiator “%2$S”, attempting to access target “%3$S” (%4$S:%5$S) via %6$S. Secure context: %7$S diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp @@ -18,6 +18,7 @@ #include "mozilla/dom/ServiceWorkerUtils.h" #include "mozilla/dom/BrowserChild.h" #include "mozilla/dom/LinkStyle.h" +#include "mozilla/dom/ReferrerInfo.h" #include "mozilla/extensions/StreamFilterParent.h" #include "mozilla/ipc/IPCStreamUtils.h" #include "mozilla/net/NeckoChild.h" @@ -1485,6 +1486,137 @@ mozilla::ipc::IPCResult HttpChannelChild::RecvReportSecurityMessage( return IPC_OK(); } +mozilla::ipc::IPCResult HttpChannelChild::RecvReportLNAToConsole( + const NetAddr& aPeerAddr, const nsACString& aMessageType, + const nsACString& aPromptAction, const nsACString& aTopLevelSite) { + nsCOMPtr<nsILoadInfo> loadInfo = LoadInfo(); + nsCOMPtr<nsIURI> uri; + GetURI(getter_AddRefs(uri)); + + if (!loadInfo || !uri) { + return IPC_OK(); + } + + // Use top-level site passed from parent process via IPC. + // This is necessary because in cross-site scenarios with Fission, + // the content process cannot access the top-level document which + // exists in a different process. + nsAutoCString topLevelSite(aTopLevelSite); + + // Get initiator (triggering principal) + nsAutoCString initiator; + nsCOMPtr<nsIPrincipal> triggeringPrincipal; + loadInfo->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal)); + if (triggeringPrincipal) { + nsCOMPtr<nsIURI> triggeringURI = triggeringPrincipal->GetURI(); + if (triggeringURI) { + initiator = triggeringURI->GetSpecOrDefault(); + } + } + + // Get target URL (full spec shown to users for clarity) + nsAutoCString targetURL; + targetURL = uri->GetSpecOrDefault(); + + // Get target IP address from passed NetAddr + nsCString targetIp = aPeerAddr.ToString(); + + // Get port + uint16_t port = 0; + (void)aPeerAddr.GetPort(&port); + + // Determine request mechanism from LoadInfo + nsAutoCString mechanism; + ExtContentPolicyType contentType = loadInfo->GetExternalContentPolicyType(); + switch (contentType) { + case ExtContentPolicyType::TYPE_WEBSOCKET: + mechanism.AssignLiteral("websocket"); + break; + case ExtContentPolicyType::TYPE_WEB_TRANSPORT: + mechanism.AssignLiteral("webtransport"); + break; + case ExtContentPolicyType::TYPE_FETCH: + mechanism.AssignLiteral("fetch"); + break; + case ExtContentPolicyType::TYPE_XMLHTTPREQUEST: + mechanism.AssignLiteral("xhr"); + break; + default: + if (uri->SchemeIs("https")) { + mechanism.AssignLiteral("https"); + } else { + mechanism.AssignLiteral("http"); + } + break; + } + + // Check if the originating context is secure (required by LNA spec) + bool isSecureContext = false; + if (triggeringPrincipal) { + isSecureContext = triggeringPrincipal->GetIsOriginPotentiallyTrustworthy(); + } + + // Build console parameters + AutoTArray<nsString, 8> consoleParams; + CopyUTF8toUTF16( + topLevelSite.IsEmpty() ? nsAutoCString("(empty)") : topLevelSite, + *consoleParams.AppendElement()); + CopyUTF8toUTF16(initiator.IsEmpty() ? nsAutoCString("(empty)") : initiator, + *consoleParams.AppendElement()); + CopyUTF8toUTF16(targetURL.IsEmpty() ? nsAutoCString("(empty)") : targetURL, + *consoleParams.AppendElement()); + CopyUTF8toUTF16(targetIp, *consoleParams.AppendElement()); + consoleParams.AppendElement()->AppendInt(port); + CopyUTF8toUTF16(mechanism, *consoleParams.AppendElement()); + CopyUTF8toUTF16( + isSecureContext ? nsAutoCString("True") : nsAutoCString("False"), + *consoleParams.AppendElement()); + + // Add prompt action if provided (for LocalNetworkAccessDetected message) + if (!aPromptAction.IsEmpty()) { + CopyUTF8toUTF16(aPromptAction, *consoleParams.AppendElement()); + } + + // Build the formatted message with stack trace + nsAutoString formattedMsg; + nsContentUtils::FormatLocalizedString(nsContentUtils::eNECKO_PROPERTIES, + PromiseFlatCString(aMessageType).get(), + consoleParams, formattedMsg); + + // Append stack trace to the message if available + const char* callStack = GetCallStack(); + if (callStack && callStack[0] != '\0') { + formattedMsg.AppendLiteral("\n"); + formattedMsg.Append(NS_ConvertUTF8toUTF16(callStack)); + } + + uint64_t innerWindowID = 0; + loadInfo->GetInnerWindowID(&innerWindowID); + + nsCOMPtr<nsIURI> sourceURI = uri; // fallback to target + if (triggeringPrincipal) { + nsCOMPtr<nsIURI> principalURI = triggeringPrincipal->GetURI(); + if (principalURI) { + sourceURI = principalURI; + } + } + + // Report to web console + if (innerWindowID) { + nsContentUtils::ReportToConsoleByWindowID( + formattedMsg, nsIScriptError::infoFlag, "Security"_ns, innerWindowID, + mozilla::SourceLocation(sourceURI.get())); + } else { + RefPtr<dom::Document> doc; + loadInfo->GetLoadingDocument(getter_AddRefs(doc)); + nsContentUtils::ReportToConsoleNonLocalized( + formattedMsg, nsIScriptError::infoFlag, "Security"_ns, doc, + mozilla::SourceLocation(sourceURI.get())); + } + + return IPC_OK(); +} + mozilla::ipc::IPCResult HttpChannelChild::RecvRedirect1Begin( const uint32_t& aRegistrarId, nsIURI* aNewUri, const uint32_t& aNewLoadFlags, const uint32_t& aRedirectFlags, @@ -2140,6 +2272,25 @@ HttpChannelChild::GetSecurityInfo(nsITransportSecurityInfo** aSecurityInfo) { NS_IMETHODIMP HttpChannelChild::AsyncOpen(nsIStreamListener* aListener) { + // Capture JavaScript stack for LNA console logging only if: + // 1. LNA blocking is enabled + // 2. This is a cross-origin request (LNA only applies to cross-origin) + if (StaticPrefs::network_lna_blocking() && + ReferrerInfo::IsCrossOriginRequest(this)) { + JSContext* cx = nsContentUtils::GetCurrentJSContext(); + if (cx) { + JS::UniqueChars chars = xpc_PrintJSStack(cx, + /*showArgs=*/false, + /*showLocals=*/false, + /*showThisProps=*/false); + if (chars) { + size_t len = strlen(chars.get()); + mCallStack = mozilla::MakeUnique<char[]>(len + 1); + memcpy(mCallStack.get(), chars.get(), len + 1); + } + } + } + AUTO_PROFILER_LABEL("HttpChannelChild::AsyncOpen", NETWORK); LOG(("HttpChannelChild::AsyncOpen [this=%p uri=%s]\n", this, mSpec.get())); diff --git a/netwerk/protocol/http/HttpChannelChild.h b/netwerk/protocol/http/HttpChannelChild.h @@ -143,6 +143,11 @@ class HttpChannelChild final : public PHttpChannelChild, void RegisterStreamFilter( RefPtr<extensions::StreamFilterParent>& aStreamFilter); + // Get the captured JavaScript call stack for LNA console logging + const char* GetCallStack() const { + return mCallStack ? mCallStack.get() : nullptr; + } + protected: mozilla::ipc::IPCResult RecvOnStartRequestSent() override; mozilla::ipc::IPCResult RecvFailedAsyncOpen(const nsresult& status) override; @@ -160,6 +165,11 @@ class HttpChannelChild final : public PHttpChannelChild, mozilla::ipc::IPCResult RecvReportSecurityMessage( const nsAString& messageTag, const nsAString& messageCategory) override; + mozilla::ipc::IPCResult RecvReportLNAToConsole( + const NetAddr& aPeerAddr, const nsACString& aMessageType, + const nsACString& aPromptAction, + const nsACString& aTopLevelSite) override; + mozilla::ipc::IPCResult RecvSetPriority(const int16_t& aPriority) override; mozilla::ipc::IPCResult RecvOriginalCacheInputStreamAvailable( @@ -420,6 +430,9 @@ class HttpChannelChild final : public PHttpChannelChild, // get stuck in a loop. uint8_t mAlreadyReleased : 1; + // JavaScript stack captured during AsyncOpen for LNA console logging + mozilla::UniquePtr<char[]> mCallStack; + void CleanupRedirectingChannel(nsresult rv); // Calls OnStartRequest and/or OnStopRequest on our listener in case we didn't diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp @@ -2043,6 +2043,16 @@ void HttpChannelParent::DoSendSetPriority(int16_t aValue) { } } +void HttpChannelParent::DoSendReportLNAToConsole( + const NetAddr& aPeerAddr, const nsACString& aMessageType, + const nsACString& aPromptAction, const nsACString& aTopLevelSite) { + if (!mIPCClosed) { + (void)SendReportLNAToConsole(aPeerAddr, nsCString(aMessageType), + nsCString(aPromptAction), + nsCString(aTopLevelSite)); + } +} + nsresult HttpChannelParent::LogBlockedCORSRequest(const nsAString& aMessage, const nsACString& aCategory, bool aIsWarning) { diff --git a/netwerk/protocol/http/HttpChannelParent.h b/netwerk/protocol/http/HttpChannelParent.h @@ -96,6 +96,12 @@ class HttpChannelParent final : public nsIInterfaceRequestor, // Calls SendSetPriority if mIPCClosed is false. void DoSendSetPriority(int16_t aValue); + // Calls SendReportLNAToConsole if mIPCClosed is false. + void DoSendReportLNAToConsole(const NetAddr& aPeerAddr, + const nsACString& aMessageType, + const nsACString& aPromptAction, + const nsACString& aTopLevelSite); + // Callback while background channel is ready. void OnBackgroundParentReady(HttpBackgroundChannelParent* aBgParent); // Callback while background channel is destroyed. diff --git a/netwerk/protocol/http/PHttpChannel.ipdl b/netwerk/protocol/http/PHttpChannel.ipdl @@ -120,6 +120,12 @@ child: // channel. async ReportSecurityMessage(nsString messageTag, nsString messageCategory); + // Report Local Network Access information to console in content process + // where CallingScriptLocationString() can access JS context. + // topLevelSite must be passed from parent process because with Fission, + // cross-site content processes cannot access top-level document in another process. + async ReportLNAToConsole(NetAddr peerAddr, nsCString messageType, nsCString promptAction, nsCString topLevelSite); + // Tell child to delete channel (all IPDL deletes must be done from child to // avoid races: see bug 591708). async DeleteSelf(); diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp @@ -137,6 +137,7 @@ #include "HttpTrafficAnalyzer.h" #include "mozilla/net/SocketProcessParent.h" #include "mozilla/dom/SecFetch.h" +#include "mozilla/dom/WindowGlobalParent.h" #include "mozilla/net/TRRService.h" #include "LNAPermissionRequest.h" #include "nsUnknownDecoder.h" @@ -8616,6 +8617,48 @@ nsHttpChannel::GetEssentialDomainCategory(nsCString& domain) { return EssentialDomainCategory::Other; } +// Helper function to send LNA access info to child process for console logging +// The child process has access to CallingScriptLocationString() which requires +// JS context +static void ReportLNAAccessToConsole(nsHttpChannel* aChannel, + const char* aMessageName, + const nsACString& aPromptAction = ""_ns) { + // Send IPC to child process to log to console with script location + nsCOMPtr<nsIParentChannel> parentChannel; + NS_QueryNotificationCallbacks(aChannel, parentChannel); + if (RefPtr<HttpChannelParent> httpParent = do_QueryObject(parentChannel)) { + NetAddr peerAddr = aChannel->GetPeerAddr(); + + // Fetch top-level site URI in parent process and pass via IPC. + // We need to fetch this here because with Fission (site isolation), + // cross-site iframes run in separate content processes and cannot + // access the top-level document in a different process. + nsAutoCString topLevelSite; + nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); + if (loadInfo) { + RefPtr<mozilla::dom::BrowsingContext> bc; + loadInfo->GetBrowsingContext(getter_AddRefs(bc)); + if (bc && bc->Top() && bc->Top()->Canonical()) { + RefPtr<mozilla::dom::WindowGlobalParent> topWindowGlobal = + bc->Top()->Canonical()->GetCurrentWindowGlobal(); + if (topWindowGlobal) { + nsIPrincipal* topPrincipal = topWindowGlobal->DocumentPrincipal(); + if (topPrincipal) { + nsCOMPtr<nsIURI> topURI = topPrincipal->GetURI(); + if (topURI) { + (void)topURI->GetSpec(topLevelSite); + } + } + } + } + } + + httpParent->DoSendReportLNAToConsole(peerAddr, nsCString(aMessageName), + nsCString(aPromptAction), + topLevelSite); + } +} + nsresult nsHttpChannel::ProcessLNAActions() { if (!mTransaction) { // this could happen with rcwn enabled. @@ -8626,6 +8669,7 @@ nsresult nsHttpChannel::ProcessLNAActions() { // Suspend to block any notification to the channel. // This will get resumed in // nsHttpChannel::OnPermissionPromptResult + UpdateCurrentIpAddressSpace(); mWaitingForLNAPermission = true; Suspend(); auto permissionKey = mTransaction->GetTargetIPAddressSpace() == @@ -8656,6 +8700,9 @@ nsresult nsHttpChannel::ProcessLNAActions() { RefPtr<LNAPermissionRequest> request = new LNAPermissionRequest( std::move(permissionPromptCallback), mLoadInfo, permissionKey); + // Log to console before requesting permission + ReportLNAAccessToConsole(this, "LocalNetworkAccessPermissionRequired"); + // This invokes callback nsHttpChannel::OnPermissionPromptResult // synchronously if the permission is already granted or denied // if permission is not available we prompt the user and in that case @@ -8664,6 +8711,45 @@ nsresult nsHttpChannel::ProcessLNAActions() { return request->RequestPermission(); } +void nsHttpChannel::UpdateCurrentIpAddressSpace() { + if (!mTransaction) { + return; + } + + if (mPeerAddr.GetIpAddressSpace() == nsILoadInfo::IPAddressSpace::Unknown) { + // fetch peer address from transaction + bool isTrr; + bool echConfigUsed; + mTransaction->GetNetworkAddresses(mSelfAddr, mPeerAddr, isTrr, + mEffectiveTRRMode, mTRRSkipReason, + echConfigUsed); + } + + nsILoadInfo::IPAddressSpace docAddressSpace = mPeerAddr.GetIpAddressSpace(); + mLoadInfo->SetIpAddressSpace(docAddressSpace); + ExtContentPolicyType type = mLoadInfo->GetExternalContentPolicyType(); + if (type == ExtContentPolicy::TYPE_DOCUMENT || + type == ExtContentPolicy::TYPE_SUBDOCUMENT) { + RefPtr<mozilla::dom::BrowsingContext> bc; + mLoadInfo->GetTargetBrowsingContext(getter_AddRefs(bc)); + if (bc) { + bc->SetCurrentIPAddressSpace(docAddressSpace); + } + + if (mCacheEntry) { + // store the ipaddr information into the cache metadata entry + if (mPeerAddr.GetIpAddressSpace() != + nsILoadInfo::IPAddressSpace::Unknown) { + uint16_t port; + mPeerAddr.GetPort(&port); + mCacheEntry->SetMetaDataElement("peer-ip-address", + mPeerAddr.ToString().get()); + mCacheEntry->SetMetaDataElement("peer-port", ToString(port).c_str()); + } + } + } +} + NS_IMETHODIMP nsHttpChannel::OnStartRequest(nsIRequest* request) { nsresult rv; @@ -8825,33 +8911,7 @@ nsHttpChannel::OnStartRequest(nsIRequest* request) { if (!mProxyInfo || xpc::IsInAutomation()) { // If this is main document load or iframe store the IP Address space in // the browsing context - nsAutoCString addrPort; - mPeerAddr.ToAddrPortString(addrPort); - nsILoadInfo::IPAddressSpace docAddressSpace = - mPeerAddr.GetIpAddressSpace(); - mLoadInfo->SetIpAddressSpace(docAddressSpace); - ExtContentPolicyType type = mLoadInfo->GetExternalContentPolicyType(); - if (type == ExtContentPolicy::TYPE_DOCUMENT || - type == ExtContentPolicy::TYPE_SUBDOCUMENT) { - RefPtr<mozilla::dom::BrowsingContext> bc; - mLoadInfo->GetTargetBrowsingContext(getter_AddRefs(bc)); - if (bc) { - bc->SetCurrentIPAddressSpace(docAddressSpace); - } - - if (mCacheEntry) { - // store the ipaddr information into the cache metadata entry - if (mPeerAddr.GetIpAddressSpace() != - nsILoadInfo::IPAddressSpace::Unknown) { - uint16_t port; - mPeerAddr.GetPort(&port); - mCacheEntry->SetMetaDataElement("peer-ip-address", - mPeerAddr.ToString().get()); - mCacheEntry->SetMetaDataElement("peer-port", - ToString(port).c_str()); - } - } - } + UpdateCurrentIpAddressSpace(); } StoreResolvedByTRR(isTrr); diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h @@ -221,6 +221,7 @@ class nsHttpChannel final : public HttpBaseChannel, public: /* internal necko use only */ uint32_t GetRequestTime() const { return mRequestTime; } + const nsACString& GetLNAPromptAction() const { return mLNAPromptAction; } void AsyncOpenFinal(TimeStamp aTimeStamp); @@ -357,6 +358,7 @@ class nsHttpChannel final : public HttpBaseChannel, const nsACString& aPermissionType); void MaybeUpdateDocumentIPAddressSpaceFromCache(); nsresult ProcessLNAActions(); + void UpdateCurrentIpAddressSpace(); public: void UpdateCacheDisposition(bool aSuccessfulReval, bool aPartialContentUsed); @@ -764,14 +766,14 @@ class nsHttpChannel final : public HttpBaseChannel, void PopRedirectAsyncFunc(nsContinueRedirectionFunc func); // If this resource is eligible for tailing based on class-of-service flags - // and load flags. We don't tail Leaders/Unblocked/UrgentStart and top-level - // loads. + // and load flags. We don't tail Leaders/Unblocked/UrgentStart and + // top-level loads. bool EligibleForTailing(); // Called exclusively only from AsyncOpen or after all classification // callbacks. If this channel is 1) Tail, 2) assigned a request context, 3) - // the context is still in the tail-blocked phase, then the method will queue - // this channel. OnTailUnblock will be called after the context is + // the context is still in the tail-blocked phase, then the method will + // queue this channel. OnTailUnblock will be called after the context is // tail-unblocked or canceled. bool WaitingForTailUnblock(); @@ -829,8 +831,8 @@ class nsHttpChannel final : public HttpBaseChannel, void MaybeRaceCacheWithNetwork(); // Creates a new cache entry when network wins the race to ensure we have - // the latest version of the resource in the cache. Otherwise we might return - // an old content when navigating back in history. + // the latest version of the resource in the cache. Otherwise we might + // return an old content when navigating back in history. void MaybeCreateCacheEntryWhenRCWN(); nsresult TriggerNetworkWithDelay(uint32_t aDelay); @@ -877,9 +879,9 @@ class nsHttpChannel final : public HttpBaseChannel, TimeStamp mNavigationStartTimeStamp; - // Promise that blocks connection creation when we want to resolve the origin - // host name to be able to give the configured proxy only the resolved IP - // to not leak names. + // Promise that blocks connection creation when we want to resolve the + // origin host name to be able to give the configured proxy only the + // resolved IP to not leak names. MozPromiseHolder<DNSPromise> mDNSBlockingPromise; // When we hit DoConnect before the resolution is done, Then() will be set // here to resume DoConnect. @@ -936,6 +938,9 @@ class nsHttpChannel final : public HttpBaseChannel, Maybe<nsCString> mOpenerCallingScriptLocation; RefPtr<WebTransportSessionEventListener> mWebTransportSessionEventListener; nsMainThreadPtrHandle<nsIReplacedHttpResponse> mOverrideResponse; + // LNA telemetry: stores the user's action on the permission prompt + // Values: "allow", "deny", or empty string (no prompt shown) + nsCString mLNAPromptAction; }; } // namespace net diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -3740,6 +3740,11 @@ bool nsHttpTransaction::AllowedToConnectToIpAddressSpace( return true; } + if (mConnection) { + // update peer address required for LNA telemetry and console logging + MutexAutoLock lock(mLock); + mConnection->GetPeerAddr(&mPeerAddr); + } // Skip LNA checks if domain is in skip list if (mConnInfo && gIOService && gIOService->ShouldSkipDomainForLNA(mConnInfo->GetOrigin())) {