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:
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())) {