mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
Bug 1567616 - network id based on default gateway is wrong when VPN overrides default gateway by more specific routes r=dragana
This patch implements NetlinkService which communicates with kernel via netlink socket. It keeps track of addresses, default routes, interfaces and neighbors and uses it to calculate network ID. Differential Revision: https://phabricator.services.mozilla.com/D43175 --HG-- rename : netwerk/system/linux/nsNotifyAddrListener_Linux.cpp => netwerk/system/linux/nsNetworkLinkService.cpp rename : netwerk/system/linux/nsNotifyAddrListener_Linux.h => netwerk/system/linux/nsNetworkLinkService.h extra : moz-landing-system : lando
This commit is contained in:
parent
8afaba2056
commit
390918caab
@ -6076,6 +6076,37 @@
|
||||
value: 30000
|
||||
mirror: always
|
||||
|
||||
# Allow the network changed event to get sent when a network topology or setup
|
||||
# change is noticed while running.
|
||||
- name: network.notify.changed
|
||||
type: RelaxedAtomicBool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
# Allow network detection of IPv6 related changes (bug 1245059)
|
||||
- name: network.notify.IPv6
|
||||
type: RelaxedAtomicBool
|
||||
# ifdef XP_WIN
|
||||
value: false
|
||||
# else
|
||||
value: true
|
||||
# endif
|
||||
mirror: always
|
||||
|
||||
# IP addresses that are used by netlink service to check whether default route
|
||||
# is used for outgoing traffic. They are used just to check routing rules,
|
||||
# no packets are sent to those hosts. Initially, addresses of host
|
||||
# detectportal.firefox.com were used but they don't necessarily need to be
|
||||
# updated when addresses of this host change.
|
||||
- name: network.netlink.route.check.IPv4
|
||||
type: String
|
||||
value: "23.219.91.27"
|
||||
mirror: never
|
||||
- name: network.netlink.route.check.IPv6
|
||||
type: String
|
||||
value: "2a02:26f0:40::17db:5b1b"
|
||||
mirror: never
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Prefs starting with "nglayout."
|
||||
#---------------------------------------------------------------------------
|
||||
|
@ -1489,17 +1489,6 @@ pref("logging.config.clear_on_startup", true);
|
||||
// prevents necko connecting to ports 1-5 unless the protocol
|
||||
// overrides.
|
||||
|
||||
// Allow the network changed event to get sent when a network topology or
|
||||
// setup change is noticed while running.
|
||||
pref("network.notify.changed", true);
|
||||
|
||||
// Allow network detection of IPv6 related changes (bug 1245059)
|
||||
#if defined(XP_WIN)
|
||||
pref("network.notify.IPv6", false);
|
||||
#else
|
||||
pref("network.notify.IPv6", true);
|
||||
#endif
|
||||
|
||||
// Transmit UDP busy-work to the LAN when anticipating low latency
|
||||
// network reads and on wifi to mitigate 802.11 Power Save Polling delays
|
||||
pref("network.tickle-wifi.enabled", false);
|
||||
|
@ -61,6 +61,7 @@
|
||||
#include "nsContentSecurityManager.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "mozilla/StaticPrefs_network.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
# include "nsGIOProtocolHandler.h"
|
||||
@ -83,7 +84,6 @@ using mozilla::dom::ServiceWorkerDescriptor;
|
||||
// but the old names are still used to preserve backward compatibility.
|
||||
#define NECKO_BUFFER_CACHE_COUNT_PREF "network.buffer.cache.count"
|
||||
#define NECKO_BUFFER_CACHE_SIZE_PREF "network.buffer.cache.size"
|
||||
#define NETWORK_NOTIFY_CHANGED_PREF "network.notify.changed"
|
||||
#define NETWORK_CAPTIVE_PORTAL_PREF "network.captive-portal-service.enabled"
|
||||
#define WEBRTC_PREF_PREFIX "media.peerconnection."
|
||||
#define NETWORK_DNS_PREF "network.dns."
|
||||
@ -202,7 +202,6 @@ nsIOService::nsIOService()
|
||||
mHttpHandlerAlreadyShutingDown(false),
|
||||
mNetworkLinkServiceInitialized(false),
|
||||
mChannelEventSinks(NS_CHANNEL_EVENT_SINK_CATEGORY),
|
||||
mNetworkNotifyChanged(true),
|
||||
mTotalRequests(0),
|
||||
mCacheWon(0),
|
||||
mNetWon(0),
|
||||
@ -217,7 +216,6 @@ static const char* gCallbackPrefs[] = {
|
||||
MANAGE_OFFLINE_STATUS_PREF,
|
||||
NECKO_BUFFER_CACHE_COUNT_PREF,
|
||||
NECKO_BUFFER_CACHE_SIZE_PREF,
|
||||
NETWORK_NOTIFY_CHANGED_PREF,
|
||||
NETWORK_CAPTIVE_PORTAL_PREF,
|
||||
nullptr,
|
||||
};
|
||||
@ -1267,14 +1265,6 @@ void nsIOService::PrefsChanged(const char* pref) {
|
||||
"network segment size is not a power of 2!");
|
||||
}
|
||||
|
||||
if (!pref || strcmp(pref, NETWORK_NOTIFY_CHANGED_PREF) == 0) {
|
||||
bool allow;
|
||||
nsresult rv = Preferences::GetBool(NETWORK_NOTIFY_CHANGED_PREF, &allow);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mNetworkNotifyChanged = allow;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pref || strcmp(pref, NETWORK_CAPTIVE_PORTAL_PREF) == 0) {
|
||||
nsresult rv = Preferences::GetBool(NETWORK_CAPTIVE_PORTAL_PREF,
|
||||
&gCaptivePortalEnabled);
|
||||
@ -1346,7 +1336,7 @@ nsIOService::NotifyWakeup() {
|
||||
|
||||
NS_ASSERTION(observerService, "The observer service should not be null");
|
||||
|
||||
if (observerService && mNetworkNotifyChanged) {
|
||||
if (observerService && StaticPrefs::network_notify_changed()) {
|
||||
(void)observerService->NotifyObservers(nullptr, NS_NETWORK_LINK_TOPIC,
|
||||
(u"" NS_NETWORK_LINK_DATA_CHANGED));
|
||||
}
|
||||
|
@ -216,8 +216,6 @@ class nsIOService final : public nsIIOService,
|
||||
|
||||
nsTArray<int32_t> mRestrictedPortList;
|
||||
|
||||
bool mNetworkNotifyChanged;
|
||||
|
||||
static bool sIsDataURIUniqueOpaqueOrigin;
|
||||
static bool sBlockToplevelDataUriNavigations;
|
||||
|
||||
|
@ -607,8 +607,8 @@ elif toolkit == 'android':
|
||||
}
|
||||
elif buildconfig.substs['OS_ARCH'] == 'Linux':
|
||||
link_service = {
|
||||
'type': 'nsNotifyAddrListener',
|
||||
'headers': ['/netwerk/system/linux/nsNotifyAddrListener_Linux.h'],
|
||||
'type': 'nsNetworkLinkService',
|
||||
'headers': ['/netwerk/system/linux/nsNetworkLinkService.h'],
|
||||
'init_method': 'Init',
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'Linux':
|
||||
SOURCES += [
|
||||
'nsNotifyAddrListener_Linux.cpp',
|
||||
'nsNetworkLinkService.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
150
netwerk/system/linux/nsNetworkLinkService.cpp
Normal file
150
netwerk/system/linux/nsNetworkLinkService.cpp
Normal file
@ -0,0 +1,150 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set et sw=2 ts=4: */
|
||||
/* 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 "nsIObserverService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsNetworkLinkService.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
#include "mozilla/StaticPrefs_network.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static LazyLogModule gNotifyAddrLog("nsNetworkLinkService");
|
||||
#define LOG(args) MOZ_LOG(gNotifyAddrLog, mozilla::LogLevel::Debug, args)
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsNetworkLinkService, nsINetworkLinkService, nsIObserver)
|
||||
|
||||
nsNetworkLinkService::nsNetworkLinkService() : mStatusIsKnown(false) {}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetworkLinkService::GetIsLinkUp(bool* aIsUp) {
|
||||
if (!mNetlinkSvc) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mNetlinkSvc->GetIsLinkUp(aIsUp);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetworkLinkService::GetLinkStatusKnown(bool* aIsKnown) {
|
||||
*aIsKnown = mStatusIsKnown;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetworkLinkService::GetLinkType(uint32_t* aLinkType) {
|
||||
NS_ENSURE_ARG_POINTER(aLinkType);
|
||||
|
||||
// XXX This function has not yet been implemented for this platform
|
||||
*aLinkType = nsINetworkLinkService::LINK_TYPE_UNKNOWN;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetworkLinkService::GetNetworkID(nsACString& aNetworkID) {
|
||||
if (!mNetlinkSvc) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mNetlinkSvc->GetNetworkID(aNetworkID);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetworkLinkService::Observe(nsISupports* subject, const char* topic,
|
||||
const char16_t* data) {
|
||||
if (!strcmp("xpcom-shutdown-threads", topic)) {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsNetworkLinkService::Init() {
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
if (!observerService) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
rv = observerService->AddObserver(this, "xpcom-shutdown-threads", false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mNetlinkSvc = new mozilla::net::NetlinkService();
|
||||
rv = mNetlinkSvc->Init(this);
|
||||
if (NS_FAILED(rv)) {
|
||||
mNetlinkSvc = nullptr;
|
||||
LOG(("Cannot initialize NetlinkService [rv=0x%08" PRIx32 "]",
|
||||
static_cast<uint32_t>(rv)));
|
||||
return rv;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsNetworkLinkService::Shutdown() {
|
||||
// remove xpcom shutdown observer
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
if (observerService)
|
||||
observerService->RemoveObserver(this, "xpcom-shutdown-threads");
|
||||
|
||||
if (mNetlinkSvc) {
|
||||
mNetlinkSvc->Shutdown();
|
||||
mNetlinkSvc = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsNetworkLinkService::OnNetworkChanged() {
|
||||
if (StaticPrefs::network_notify_changed()) {
|
||||
RefPtr<nsNetworkLinkService> self = this;
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"nsNetworkLinkService::OnNetworkChanged",
|
||||
[self]() { self->SendEvent(NS_NETWORK_LINK_DATA_CHANGED); }));
|
||||
}
|
||||
}
|
||||
|
||||
void nsNetworkLinkService::OnLinkUp() {
|
||||
RefPtr<nsNetworkLinkService> self = this;
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"nsNetworkLinkService::OnLinkUp",
|
||||
[self]() { self->SendEvent(NS_NETWORK_LINK_DATA_UP); }));
|
||||
}
|
||||
|
||||
void nsNetworkLinkService::OnLinkDown() {
|
||||
RefPtr<nsNetworkLinkService> self = this;
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"nsNetworkLinkService::OnLinkDown",
|
||||
[self]() { self->SendEvent(NS_NETWORK_LINK_DATA_DOWN); }));
|
||||
}
|
||||
|
||||
void nsNetworkLinkService::OnLinkStatusKnown() { mStatusIsKnown = true; }
|
||||
|
||||
/* Sends the given event. Assumes aEventID never goes out of scope (static
|
||||
* strings are ideal).
|
||||
*/
|
||||
void nsNetworkLinkService::SendEvent(const char* aEventID) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
LOG(("SendEvent: %s\n", aEventID));
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
if (observerService) {
|
||||
observerService->NotifyObservers(static_cast<nsINetworkLinkService*>(this),
|
||||
NS_NETWORK_LINK_TOPIC,
|
||||
NS_ConvertASCIItoUTF16(aEventID).get());
|
||||
}
|
||||
}
|
45
netwerk/system/linux/nsNetworkLinkService.h
Normal file
45
netwerk/system/linux/nsNetworkLinkService.h
Normal file
@ -0,0 +1,45 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set et sw=2 ts=4: */
|
||||
/* 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/. */
|
||||
#ifndef NSNETWORKLINKSERVICE_LINUX_H_
|
||||
#define NSNETWORKLINKSERVICE_LINUX_H_
|
||||
|
||||
#include "nsINetworkLinkService.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "../netlink/NetlinkService.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
|
||||
class nsNetworkLinkService : public nsINetworkLinkService,
|
||||
public nsIObserver,
|
||||
public mozilla::net::NetlinkServiceListener {
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSINETWORKLINKSERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
nsNetworkLinkService();
|
||||
nsresult Init();
|
||||
|
||||
void OnNetworkChanged() override;
|
||||
void OnLinkUp() override;
|
||||
void OnLinkDown() override;
|
||||
void OnLinkStatusKnown() override;
|
||||
|
||||
private:
|
||||
virtual ~nsNetworkLinkService() = default;
|
||||
|
||||
// Called when xpcom-shutdown-threads is received.
|
||||
nsresult Shutdown();
|
||||
|
||||
// Sends the network event.
|
||||
void SendEvent(const char* aEventID);
|
||||
|
||||
mozilla::Atomic<bool, mozilla::Relaxed> mStatusIsKnown;
|
||||
|
||||
RefPtr<mozilla::net::NetlinkService> mNetlinkSvc;
|
||||
};
|
||||
|
||||
#endif /* NSNETWORKLINKSERVICE_LINUX_H_ */
|
@ -1,617 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set et sw=2 ts=4: */
|
||||
/* 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 <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsNotifyAddrListener_Linux.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/FileUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/SHA1.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "../../base/IPv6Utils.h"
|
||||
|
||||
/* a shorter name that better explains what it does */
|
||||
#define EINTR_RETRY(x) MOZ_TEMP_FAILURE_RETRY(x)
|
||||
|
||||
// period during which to absorb subsequent network change events, in
|
||||
// milliseconds
|
||||
static const unsigned int kNetworkChangeCoalescingPeriod = 1000;
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static LazyLogModule gNotifyAddrLog("nsNotifyAddr");
|
||||
#define LOG(args) MOZ_LOG(gNotifyAddrLog, mozilla::LogLevel::Debug, args)
|
||||
|
||||
#define NETWORK_NOTIFY_CHANGED_PREF "network.notify.changed"
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsNotifyAddrListener, nsINetworkLinkService, nsIRunnable,
|
||||
nsIObserver)
|
||||
|
||||
nsNotifyAddrListener::nsNotifyAddrListener()
|
||||
: mMutex("nsNotifyAddrListener::mMutex"),
|
||||
mLinkUp(true), // assume true by default
|
||||
mStatusKnown(false),
|
||||
mAllowChangedEvent(true),
|
||||
mCoalescingActive(false) {
|
||||
mShutdownPipe[0] = -1;
|
||||
mShutdownPipe[1] = -1;
|
||||
}
|
||||
|
||||
nsNotifyAddrListener::~nsNotifyAddrListener() {
|
||||
MOZ_ASSERT(!mThread, "nsNotifyAddrListener thread shutdown failed");
|
||||
|
||||
if (mShutdownPipe[0] != -1) {
|
||||
EINTR_RETRY(close(mShutdownPipe[0]));
|
||||
}
|
||||
if (mShutdownPipe[1] != -1) {
|
||||
EINTR_RETRY(close(mShutdownPipe[1]));
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNotifyAddrListener::GetIsLinkUp(bool* aIsUp) {
|
||||
// XXX This function has not yet been implemented for this platform
|
||||
*aIsUp = mLinkUp;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNotifyAddrListener::GetLinkStatusKnown(bool* aIsUp) {
|
||||
// XXX This function has not yet been implemented for this platform
|
||||
*aIsUp = mStatusKnown;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNotifyAddrListener::GetLinkType(uint32_t* aLinkType) {
|
||||
NS_ENSURE_ARG_POINTER(aLinkType);
|
||||
|
||||
// XXX This function has not yet been implemented for this platform
|
||||
*aLinkType = nsINetworkLinkService::LINK_TYPE_UNKNOWN;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNotifyAddrListener::GetNetworkID(nsACString& aNetworkID) {
|
||||
MutexAutoLock lock(mMutex);
|
||||
aNetworkID = mNetworkId;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Figure out the current IPv4 "network identification" string.
|
||||
//
|
||||
// It detects the IP of the default gateway in the routing table, then the MAC
|
||||
// address of that IP in the ARP table before it hashes that string (to avoid
|
||||
// information leakage).
|
||||
//
|
||||
static bool ipv4NetworkId(SHA1Sum* sha1) {
|
||||
const char* kProcRoute = "/proc/net/route"; /* IPv4 routes */
|
||||
const char* kProcArp = "/proc/net/arp";
|
||||
bool found = false;
|
||||
|
||||
FILE* froute = fopen(kProcRoute, "r");
|
||||
if (froute) {
|
||||
char buffer[512];
|
||||
uint32_t gw = 0;
|
||||
char* l = fgets(buffer, sizeof(buffer), froute);
|
||||
if (l) {
|
||||
/* skip the title line */
|
||||
while (l) {
|
||||
char interf[32];
|
||||
uint32_t dest;
|
||||
uint32_t gateway;
|
||||
l = fgets(buffer, sizeof(buffer), froute);
|
||||
if (l) {
|
||||
buffer[511] = 0; /* as a precaution */
|
||||
int val = sscanf(buffer, "%31s %x %x", interf, &dest, &gateway);
|
||||
if ((3 == val) && !dest) {
|
||||
gw = gateway;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(froute);
|
||||
|
||||
if (gw) {
|
||||
/* create a string to search for in the arp table */
|
||||
char searchfor[16];
|
||||
SprintfLiteral(searchfor, "%d.%d.%d.%d", gw & 0xff, (gw >> 8) & 0xff,
|
||||
(gw >> 16) & 0xff, gw >> 24);
|
||||
|
||||
FILE* farp = fopen(kProcArp, "r");
|
||||
if (farp) {
|
||||
l = fgets(buffer, sizeof(buffer), farp);
|
||||
while (l) {
|
||||
/* skip the title line */
|
||||
l = fgets(buffer, sizeof(buffer), farp);
|
||||
if (l) {
|
||||
buffer[511] = 0; /* as a precaution */
|
||||
int p[4];
|
||||
char type[16];
|
||||
char flags[16];
|
||||
char hw[32];
|
||||
if (7 == sscanf(buffer, "%u.%u.%u.%u %15s %15s %31s", &p[0], &p[1],
|
||||
&p[2], &p[3], type, flags, hw)) {
|
||||
uint32_t searchip =
|
||||
p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
||||
if (gw == searchip) {
|
||||
LOG(("networkid: MAC %s\n", hw));
|
||||
nsAutoCString mac(hw);
|
||||
sha1->update(mac.get(), mac.Length());
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(farp);
|
||||
} /* if (farp) */
|
||||
} /* if (gw) */
|
||||
} /* if (froute) */
|
||||
return found;
|
||||
}
|
||||
|
||||
// Figure out the current IPv6 "network identification" string.
|
||||
//
|
||||
static bool ipv6NetworkId(SHA1Sum* sha1) {
|
||||
bool found = false;
|
||||
FILE* ifs = fopen("/proc/net/if_inet6", "r");
|
||||
if (ifs) {
|
||||
char buffer[512];
|
||||
char ip6[40];
|
||||
int devnum;
|
||||
int preflen;
|
||||
int scope;
|
||||
int flags;
|
||||
char name[40];
|
||||
|
||||
char* l = fgets(buffer, sizeof(buffer), ifs);
|
||||
// 2a001a28120000090000000000000002 02 40 00 80 eth0
|
||||
// +------------------------------+ ++ ++ ++ ++ ++
|
||||
// | | | | | |
|
||||
// 1 2 3 4 5 6
|
||||
//
|
||||
// 1. IPv6 address displayed in 32 hexadecimal chars without colons as
|
||||
// separator
|
||||
//
|
||||
// 2. Netlink device number (interface index) in hexadecimal.
|
||||
//
|
||||
// 3. Prefix length in hexadecimal number of bits
|
||||
//
|
||||
// 4. Scope value (see kernel source include/net/ipv6.h and
|
||||
// net/ipv6/addrconf.c for more)
|
||||
//
|
||||
// 5. Interface flags (see include/linux/rtnetlink.h and net/ipv6/addrconf.c
|
||||
// for more)
|
||||
//
|
||||
// 6. Device name
|
||||
//
|
||||
while (l) {
|
||||
memset(ip6, 0, sizeof(ip6));
|
||||
if (6 == sscanf(buffer, "%32[0-9a-f] %02x %02x %02x %02x %31s", ip6,
|
||||
&devnum, &preflen, &scope, &flags, name)) {
|
||||
unsigned char id6[16];
|
||||
memset(id6, 0, sizeof(id6));
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
char buf[3];
|
||||
buf[0] = ip6[i * 2];
|
||||
buf[1] = ip6[i * 2 + 1];
|
||||
buf[2] = 0;
|
||||
// convert from hex
|
||||
id6[i] = (unsigned char)strtol(buf, nullptr, 16);
|
||||
}
|
||||
|
||||
if (net::utils::ipv6_scope(id6) == IPV6_SCOPE_GLOBAL) {
|
||||
unsigned char prefix[16];
|
||||
memset(prefix, 0, sizeof(prefix));
|
||||
uint8_t maskit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe};
|
||||
int bits = preflen;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
uint8_t mask = (bits >= 8) ? 0xff : maskit[bits];
|
||||
prefix[i] = id6[i] & mask;
|
||||
bits -= 8;
|
||||
if (bits <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// We hash the IPv6 prefix and prefix length in order to
|
||||
// differentiate between networks with a different prefix length
|
||||
// For example: 2a00:/16 and 2a00:0/32
|
||||
sha1->update(prefix, 16);
|
||||
sha1->update(&preflen, sizeof(preflen));
|
||||
found = true;
|
||||
LOG(("networkid: found global IPv6 address %s/%d\n", ip6, preflen));
|
||||
}
|
||||
}
|
||||
l = fgets(buffer, sizeof(buffer), ifs);
|
||||
}
|
||||
fclose(ifs);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
// Figure out the "network identification".
|
||||
//
|
||||
void nsNotifyAddrListener::calculateNetworkId(void) {
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "Must not be called on the main thread");
|
||||
SHA1Sum sha1;
|
||||
bool found4 = ipv4NetworkId(&sha1);
|
||||
bool found6 = ipv6NetworkId(&sha1);
|
||||
|
||||
if (found4 || found6) {
|
||||
// This 'addition' could potentially be a fixed number from the
|
||||
// profile or something.
|
||||
nsAutoCString addition("local-rubbish");
|
||||
nsAutoCString output;
|
||||
sha1.update(addition.get(), addition.Length());
|
||||
uint8_t digest[SHA1Sum::kHashSize];
|
||||
sha1.finish(digest);
|
||||
nsAutoCString newString(reinterpret_cast<char*>(digest),
|
||||
SHA1Sum::kHashSize);
|
||||
nsresult rv = Base64Encode(newString, output);
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
LOG(("networkid: id %s\n", output.get()));
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mNetworkId != output) {
|
||||
// new id
|
||||
if (found4 && !found6) {
|
||||
Telemetry::Accumulate(Telemetry::NETWORK_ID2, 1); // IPv4 only
|
||||
} else if (!found4 && found6) {
|
||||
Telemetry::Accumulate(Telemetry::NETWORK_ID2, 3); // IPv6 only
|
||||
} else {
|
||||
Telemetry::Accumulate(Telemetry::NETWORK_ID2, 4); // Both!
|
||||
}
|
||||
mNetworkId = output;
|
||||
} else {
|
||||
// same id
|
||||
LOG(("Same network id"));
|
||||
Telemetry::Accumulate(Telemetry::NETWORK_ID2, 2);
|
||||
}
|
||||
} else {
|
||||
// no id
|
||||
LOG(("No network id"));
|
||||
MutexAutoLock lock(mMutex);
|
||||
mNetworkId.Truncate();
|
||||
Telemetry::Accumulate(Telemetry::NETWORK_ID2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Check if there's a network interface available to do networking on.
|
||||
//
|
||||
void nsNotifyAddrListener::checkLink(void) {
|
||||
struct ifaddrs* list;
|
||||
struct ifaddrs* ifa;
|
||||
bool link = false;
|
||||
bool prevLinkUp = mLinkUp;
|
||||
|
||||
if (getifaddrs(&list)) return;
|
||||
|
||||
// Walk through the linked list, maintaining head pointer so we can free
|
||||
// list later
|
||||
|
||||
for (ifa = list; ifa != nullptr; ifa = ifa->ifa_next) {
|
||||
int family;
|
||||
if (ifa->ifa_addr == nullptr) continue;
|
||||
|
||||
family = ifa->ifa_addr->sa_family;
|
||||
|
||||
if ((family == AF_INET || family == AF_INET6) &&
|
||||
(ifa->ifa_flags & IFF_RUNNING) && !(ifa->ifa_flags & IFF_LOOPBACK)) {
|
||||
// An interface that is UP and not loopback
|
||||
link = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mLinkUp = link;
|
||||
freeifaddrs(list);
|
||||
|
||||
if (prevLinkUp != mLinkUp) {
|
||||
// UP/DOWN status changed, send appropriate UP/DOWN event
|
||||
SendEvent(mLinkUp ? NS_NETWORK_LINK_DATA_UP : NS_NETWORK_LINK_DATA_DOWN);
|
||||
}
|
||||
}
|
||||
|
||||
void nsNotifyAddrListener::OnNetlinkMessage(int aNetlinkSocket) {
|
||||
struct nlmsghdr* nlh;
|
||||
|
||||
// The buffer size below, (4095) was chosen partly based on testing and
|
||||
// partly on existing sample source code using this size. It needs to be
|
||||
// large enough to hold the netlink messages from the kernel.
|
||||
char buffer[4095];
|
||||
struct rtattr* attr;
|
||||
int attr_len;
|
||||
const struct ifaddrmsg* newifam;
|
||||
|
||||
ssize_t rc = EINTR_RETRY(recv(aNetlinkSocket, buffer, sizeof(buffer), 0));
|
||||
if (rc < 0) {
|
||||
return;
|
||||
}
|
||||
size_t netlink_bytes = rc;
|
||||
|
||||
nlh = reinterpret_cast<struct nlmsghdr*>(buffer);
|
||||
|
||||
bool networkChange = false;
|
||||
|
||||
for (; NLMSG_OK(nlh, netlink_bytes); nlh = NLMSG_NEXT(nlh, netlink_bytes)) {
|
||||
char prefixaddr[INET6_ADDRSTRLEN];
|
||||
char localaddr[INET6_ADDRSTRLEN];
|
||||
char* addr = nullptr;
|
||||
prefixaddr[0] = localaddr[0] = '\0';
|
||||
|
||||
if (NLMSG_DONE == nlh->nlmsg_type) {
|
||||
break;
|
||||
}
|
||||
|
||||
LOG(("nsNotifyAddrListener::OnNetlinkMessage: new/deleted address\n"));
|
||||
newifam = reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(nlh));
|
||||
|
||||
if ((newifam->ifa_family != AF_INET) && (newifam->ifa_family != AF_INET6)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
attr = IFA_RTA(newifam);
|
||||
attr_len = IFA_PAYLOAD(nlh);
|
||||
for (; attr_len && RTA_OK(attr, attr_len);
|
||||
attr = RTA_NEXT(attr, attr_len)) {
|
||||
if (attr->rta_type == IFA_ADDRESS) {
|
||||
if (newifam->ifa_family == AF_INET) {
|
||||
struct in_addr* in = (struct in_addr*)RTA_DATA(attr);
|
||||
inet_ntop(AF_INET, in, prefixaddr, INET_ADDRSTRLEN);
|
||||
} else {
|
||||
struct in6_addr* in = (struct in6_addr*)RTA_DATA(attr);
|
||||
inet_ntop(AF_INET6, in, prefixaddr, INET6_ADDRSTRLEN);
|
||||
}
|
||||
} else if (attr->rta_type == IFA_LOCAL) {
|
||||
if (newifam->ifa_family == AF_INET) {
|
||||
struct in_addr* in = (struct in_addr*)RTA_DATA(attr);
|
||||
inet_ntop(AF_INET, in, localaddr, INET_ADDRSTRLEN);
|
||||
} else {
|
||||
struct in6_addr* in = (struct in6_addr*)RTA_DATA(attr);
|
||||
inet_ntop(AF_INET6, in, localaddr, INET6_ADDRSTRLEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (localaddr[0]) {
|
||||
addr = localaddr;
|
||||
} else if (prefixaddr[0]) {
|
||||
addr = prefixaddr;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (nlh->nlmsg_type == RTM_NEWADDR) {
|
||||
LOG(
|
||||
("nsNotifyAddrListener::OnNetlinkMessage: a new address "
|
||||
"- %s.",
|
||||
addr));
|
||||
struct ifaddrmsg* ifam;
|
||||
nsCString addrStr;
|
||||
addrStr.Assign(addr);
|
||||
if (auto entry = mAddressInfo.LookupForAdd(addrStr)) {
|
||||
ifam = entry.Data();
|
||||
LOG(
|
||||
("nsNotifyAddrListener::OnNetlinkMessage: the address "
|
||||
"already known."));
|
||||
if (memcmp(ifam, newifam, sizeof(struct ifaddrmsg))) {
|
||||
LOG(
|
||||
("nsNotifyAddrListener::OnNetlinkMessage: but "
|
||||
"the address info has been changed."));
|
||||
networkChange = true;
|
||||
memcpy(ifam, newifam, sizeof(struct ifaddrmsg));
|
||||
}
|
||||
} else {
|
||||
networkChange = true;
|
||||
ifam = (struct ifaddrmsg*)malloc(sizeof(struct ifaddrmsg));
|
||||
memcpy(ifam, newifam, sizeof(struct ifaddrmsg));
|
||||
entry.OrInsert([ifam]() { return ifam; });
|
||||
}
|
||||
} else {
|
||||
LOG(
|
||||
("nsNotifyAddrListener::OnNetlinkMessage: an address "
|
||||
"has been deleted - %s.",
|
||||
addr));
|
||||
networkChange = true;
|
||||
nsCString addrStr;
|
||||
addrStr.Assign(addr);
|
||||
mAddressInfo.Remove(addrStr);
|
||||
}
|
||||
}
|
||||
|
||||
if (networkChange && mAllowChangedEvent) {
|
||||
NetworkChanged();
|
||||
}
|
||||
|
||||
if (networkChange) {
|
||||
checkLink();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNotifyAddrListener::Run() {
|
||||
int netlinkSocket = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if (netlinkSocket < 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
struct sockaddr_nl addr;
|
||||
memset(&addr, 0, sizeof(addr)); // clear addr
|
||||
|
||||
addr.nl_family = AF_NETLINK;
|
||||
addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
|
||||
|
||||
if (bind(netlinkSocket, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
// failure!
|
||||
EINTR_RETRY(close(netlinkSocket));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// switch the socket into non-blocking
|
||||
int flags = fcntl(netlinkSocket, F_GETFL, 0);
|
||||
(void)fcntl(netlinkSocket, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
struct pollfd fds[2];
|
||||
fds[0].fd = mShutdownPipe[0];
|
||||
fds[0].events = POLLIN;
|
||||
fds[0].revents = 0;
|
||||
|
||||
fds[1].fd = netlinkSocket;
|
||||
fds[1].events = POLLIN;
|
||||
fds[1].revents = 0;
|
||||
|
||||
calculateNetworkId();
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
bool shutdown = false;
|
||||
int pollWait = -1;
|
||||
while (!shutdown) {
|
||||
int rc = EINTR_RETRY(poll(fds, 2, pollWait));
|
||||
|
||||
if (rc > 0) {
|
||||
if (fds[0].revents & POLLIN) {
|
||||
// shutdown, abort the loop!
|
||||
LOG(("thread shutdown received, dying...\n"));
|
||||
shutdown = true;
|
||||
} else if (fds[1].revents & POLLIN) {
|
||||
LOG(("netlink message received, handling it...\n"));
|
||||
OnNetlinkMessage(netlinkSocket);
|
||||
}
|
||||
} else if (rc < 0) {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
break;
|
||||
}
|
||||
if (mCoalescingActive) {
|
||||
// check if coalescing period should continue
|
||||
double period = (TimeStamp::Now() - mChangeTime).ToMilliseconds();
|
||||
if (period >= kNetworkChangeCoalescingPeriod) {
|
||||
SendEvent(NS_NETWORK_LINK_DATA_CHANGED);
|
||||
mCoalescingActive = false;
|
||||
pollWait = -1; // restore to default
|
||||
} else {
|
||||
// wait no longer than to the end of the period
|
||||
pollWait = static_cast<int>(kNetworkChangeCoalescingPeriod - period);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EINTR_RETRY(close(netlinkSocket));
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNotifyAddrListener::Observe(nsISupports* subject, const char* topic,
|
||||
const char16_t* data) {
|
||||
if (!strcmp("xpcom-shutdown-threads", topic)) {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsNotifyAddrListener::Init(void) {
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
if (!observerService) return NS_ERROR_FAILURE;
|
||||
|
||||
nsresult rv =
|
||||
observerService->AddObserver(this, "xpcom-shutdown-threads", false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
Preferences::AddBoolVarCache(&mAllowChangedEvent, NETWORK_NOTIFY_CHANGED_PREF,
|
||||
true);
|
||||
|
||||
if (-1 == pipe(mShutdownPipe)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = NS_NewNamedThread("Link Monitor", getter_AddRefs(mThread), this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsNotifyAddrListener::Shutdown(void) {
|
||||
// remove xpcom shutdown observer
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
if (observerService)
|
||||
observerService->RemoveObserver(this, "xpcom-shutdown-threads");
|
||||
|
||||
LOG(("write() to signal thread shutdown\n"));
|
||||
|
||||
// awake the thread to make it terminate
|
||||
ssize_t rc = EINTR_RETRY(write(mShutdownPipe[1], "1", 1));
|
||||
LOG(("write() returned %d, errno == %d\n", (int)rc, errno));
|
||||
|
||||
nsresult rv = mThread->Shutdown();
|
||||
|
||||
// Have to break the cycle here, otherwise nsNotifyAddrListener holds
|
||||
// onto the thread and the thread holds onto the nsNotifyAddrListener
|
||||
// via its mRunnable
|
||||
mThread = nullptr;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* A network event has been registered. Delay the actual sending of the event
|
||||
* for a while and absorb subsequent events in the mean time in an effort to
|
||||
* squash potentially many triggers into a single event.
|
||||
* Only ever called from the same thread.
|
||||
*/
|
||||
nsresult nsNotifyAddrListener::NetworkChanged() {
|
||||
if (mCoalescingActive) {
|
||||
LOG(("NetworkChanged: absorbed an event (coalescing active)\n"));
|
||||
} else {
|
||||
// A fresh trigger!
|
||||
mChangeTime = TimeStamp::Now();
|
||||
mCoalescingActive = true;
|
||||
LOG(("NetworkChanged: coalescing period started\n"));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Sends the given event. Assumes aEventID never goes out of scope (static
|
||||
* strings are ideal).
|
||||
*/
|
||||
nsresult nsNotifyAddrListener::SendEvent(const char* aEventID) {
|
||||
if (!aEventID) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
LOG(("SendEvent: %s\n", aEventID));
|
||||
nsresult rv = NS_OK;
|
||||
calculateNetworkId();
|
||||
nsCOMPtr<nsIRunnable> event = new ChangeEvent(this, aEventID);
|
||||
if (NS_FAILED(rv = NS_DispatchToMainThread(event)))
|
||||
NS_WARNING("Failed to dispatch ChangeEvent");
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNotifyAddrListener::ChangeEvent::Run() {
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
if (observerService)
|
||||
observerService->NotifyObservers(mService, NS_NETWORK_LINK_TOPIC,
|
||||
NS_ConvertASCIItoUTF16(mEventID).get());
|
||||
return NS_OK;
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set et sw=2 ts=4: */
|
||||
/* 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/. */
|
||||
#ifndef NSNOTIFYADDRLISTENER_LINUX_H_
|
||||
#define NSNOTIFYADDRLISTENER_LINUX_H_
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "nsINetworkLinkService.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsClassHashtable.h"
|
||||
|
||||
class nsNotifyAddrListener : public nsINetworkLinkService,
|
||||
public nsIRunnable,
|
||||
public nsIObserver {
|
||||
virtual ~nsNotifyAddrListener();
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSINETWORKLINKSERVICE
|
||||
NS_DECL_NSIRUNNABLE
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
nsNotifyAddrListener();
|
||||
nsresult Init(void);
|
||||
|
||||
private:
|
||||
class ChangeEvent : public mozilla::Runnable {
|
||||
public:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
ChangeEvent(nsINetworkLinkService* aService, const char* aEventID)
|
||||
: mozilla::Runnable("nsNotifyAddrListener::ChangeEvent"),
|
||||
mService(aService),
|
||||
mEventID(aEventID) {}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsINetworkLinkService> mService;
|
||||
const char* mEventID;
|
||||
};
|
||||
|
||||
// Called when xpcom-shutdown-threads is received.
|
||||
nsresult Shutdown(void);
|
||||
|
||||
// Called when a network change was detected
|
||||
nsresult NetworkChanged();
|
||||
|
||||
// Sends the network event.
|
||||
nsresult SendEvent(const char* aEventID);
|
||||
|
||||
// Figure out the current "network identification"
|
||||
void calculateNetworkId(void);
|
||||
|
||||
mozilla::Mutex mMutex;
|
||||
nsCString mNetworkId;
|
||||
|
||||
// Checks if there's a network "link"
|
||||
void checkLink(void);
|
||||
|
||||
// Deals with incoming NETLINK messages.
|
||||
void OnNetlinkMessage(int NetlinkSocket);
|
||||
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
|
||||
// The network is up.
|
||||
bool mLinkUp;
|
||||
|
||||
// The network's up/down status is known.
|
||||
bool mStatusKnown;
|
||||
|
||||
// A pipe to signal shutdown with.
|
||||
int mShutdownPipe[2];
|
||||
|
||||
// Network changed events are enabled
|
||||
bool mAllowChangedEvent;
|
||||
|
||||
// Flag set while coalescing change events
|
||||
bool mCoalescingActive;
|
||||
|
||||
// Time stamp for first event during coalescing
|
||||
mozilla::TimeStamp mChangeTime;
|
||||
|
||||
// Seen Ip addresses. For Ipv6 addresses some time router renews their
|
||||
// lifetime and we should not detect this as a network link change, so we
|
||||
// keep info about all seen addresses.
|
||||
nsClassHashtable<nsCStringHashKey, struct ifaddrmsg> mAddressInfo;
|
||||
};
|
||||
|
||||
#endif /* NSNOTIFYADDRLISTENER_LINUX_H_ */
|
@ -30,9 +30,6 @@ class nsNetworkLinkService : public nsINetworkLinkService, public nsIObserver {
|
||||
bool mLinkUp;
|
||||
bool mStatusKnown;
|
||||
|
||||
// Toggles allowing the sending of network-changed event.
|
||||
bool mAllowChangedEvent;
|
||||
|
||||
SCNetworkReachabilityRef mReachability;
|
||||
CFRunLoopRef mCFRunLoop;
|
||||
CFRunLoopSourceRef mRunLoopSource;
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include "nsNetCID.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/StaticPrefs_network.h"
|
||||
#include "mozilla/SHA1.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
@ -72,7 +72,6 @@ NS_IMPL_ISUPPORTS(nsNetworkLinkService, nsINetworkLinkService, nsIObserver)
|
||||
nsNetworkLinkService::nsNetworkLinkService()
|
||||
: mLinkUp(true),
|
||||
mStatusKnown(false),
|
||||
mAllowChangedEvent(true),
|
||||
mReachability(nullptr),
|
||||
mCFRunLoop(nullptr),
|
||||
mRunLoopSource(nullptr),
|
||||
@ -407,8 +406,6 @@ nsresult nsNetworkLinkService::Init(void) {
|
||||
rv = observerService->AddObserver(this, "xpcom-shutdown", false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
Preferences::AddBoolVarCache(&mAllowChangedEvent, NETWORK_NOTIFY_CHANGED_PREF, true);
|
||||
|
||||
// If the network reachability API can reach 0.0.0.0 without
|
||||
// requiring a connection, there is a network interface available.
|
||||
struct sockaddr_in addr;
|
||||
@ -553,7 +550,7 @@ void nsNetworkLinkService::SendEvent(bool aNetworkChanged) {
|
||||
|
||||
const char* event;
|
||||
if (aNetworkChanged) {
|
||||
if (!mAllowChangedEvent) {
|
||||
if (!StaticPrefs::network_notify_changed()) {
|
||||
return;
|
||||
}
|
||||
event = NS_NETWORK_LINK_DATA_CHANGED;
|
||||
|
@ -14,4 +14,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
||||
DIRS += ['android']
|
||||
|
||||
elif CONFIG['OS_ARCH'] == 'Linux':
|
||||
DIRS += ['linux']
|
||||
DIRS += [
|
||||
'linux',
|
||||
'netlink'
|
||||
]
|
||||
|
1449
netwerk/system/netlink/NetlinkService.cpp
Normal file
1449
netwerk/system/netlink/NetlinkService.cpp
Normal file
File diff suppressed because it is too large
Load Diff
136
netwerk/system/netlink/NetlinkService.h
Normal file
136
netwerk/system/netlink/NetlinkService.h
Normal file
@ -0,0 +1,136 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set et sw=2 ts=4: */
|
||||
/* 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/. */
|
||||
#ifndef NETLINKSERVICE_H_
|
||||
#define NETLINKSERVICE_H_
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#include "nsINetworkLinkService.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "mozilla/SHA1.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
#if defined(NIGHTLY_BUILD) || defined(MOZ_DEV_EDITION) || defined(DEBUG)
|
||||
# define NL_DEBUG_LOG
|
||||
#endif
|
||||
|
||||
class NetlinkAddress;
|
||||
class NetlinkNeighbor;
|
||||
class NetlinkLink;
|
||||
class NetlinkRoute;
|
||||
class NetlinkMsg;
|
||||
|
||||
class NetlinkServiceListener : public nsISupports {
|
||||
public:
|
||||
virtual void OnNetworkChanged() = 0;
|
||||
virtual void OnLinkUp() = 0;
|
||||
virtual void OnLinkDown() = 0;
|
||||
virtual void OnLinkStatusKnown() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~NetlinkServiceListener() = default;
|
||||
};
|
||||
|
||||
class NetlinkService : public nsIRunnable {
|
||||
virtual ~NetlinkService();
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
NetlinkService();
|
||||
nsresult Init(NetlinkServiceListener* aListener);
|
||||
nsresult Shutdown();
|
||||
void GetNetworkID(nsACString& aNetworkID);
|
||||
void GetIsLinkUp(bool* aIsUp);
|
||||
|
||||
private:
|
||||
void EnqueueGenMsg(uint16_t aMsgType, uint8_t aFamily);
|
||||
void EnqueueRtMsg(uint8_t aFamily, void* aAddress);
|
||||
void RemovePendingMsg();
|
||||
|
||||
mozilla::Mutex mMutex;
|
||||
|
||||
void OnNetlinkMessage(int aNetlinkSocket);
|
||||
void OnLinkMessage(struct nlmsghdr* aNlh);
|
||||
void OnAddrMessage(struct nlmsghdr* aNlh);
|
||||
void OnRouteMessage(struct nlmsghdr* aNlh);
|
||||
void OnNeighborMessage(struct nlmsghdr* aNlh);
|
||||
void OnRouteCheckResult(struct nlmsghdr* aNlh);
|
||||
|
||||
void CheckLinks();
|
||||
|
||||
void TriggerNetworkIDCalculation();
|
||||
int GetPollWait();
|
||||
bool CalculateIDForFamily(uint8_t aFamily, mozilla::SHA1Sum* aSHA1);
|
||||
void CalculateNetworkID();
|
||||
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
|
||||
bool mInitialScanFinished;
|
||||
|
||||
// A pipe to signal shutdown with.
|
||||
int mShutdownPipe[2];
|
||||
|
||||
// Is true if preference network.netlink.route.check.IPv4 was successfully
|
||||
// parsed and stored to mRouteCheckIPv4
|
||||
bool mDoRouteCheckIPv4;
|
||||
struct in_addr mRouteCheckIPv4;
|
||||
|
||||
// Is true if preference network.netlink.route.check.IPv6 was successfully
|
||||
// parsed and stored to mRouteCheckIPv6
|
||||
bool mDoRouteCheckIPv6;
|
||||
struct in6_addr mRouteCheckIPv6;
|
||||
|
||||
pid_t mPid;
|
||||
uint32_t mMsgId;
|
||||
|
||||
bool mLinkUp;
|
||||
|
||||
// Flag indicating that network ID could change and should be recalculated.
|
||||
// Calculation is postponed until we receive responses to all enqueued
|
||||
// messages.
|
||||
bool mRecalculateNetworkId;
|
||||
|
||||
// Time stamp of setting mRecalculateNetworkId to true
|
||||
mozilla::TimeStamp mTriggerTime;
|
||||
|
||||
nsCString mNetworkId;
|
||||
|
||||
// All IPv4 and IPv6 addresses received via netlink
|
||||
nsTArray<nsAutoPtr<NetlinkAddress> > mAddresses;
|
||||
// All neighbors, key is an address
|
||||
nsClassHashtable<nsCStringHashKey, NetlinkNeighbor> mNeighbors;
|
||||
// All interfaces keyed by interface index
|
||||
nsClassHashtable<nsUint32HashKey, NetlinkLink> mLinks;
|
||||
// Default IPv4 routes
|
||||
nsTArray<nsAutoPtr<NetlinkRoute> > mIPv4Routes;
|
||||
// Default IPv6 routes
|
||||
nsTArray<nsAutoPtr<NetlinkRoute> > mIPv6Routes;
|
||||
|
||||
// Route for mRouteCheckIPv4 address
|
||||
nsAutoPtr<NetlinkRoute> mIPv4RouteCheckResult;
|
||||
// Route for mRouteCheckIPv6 address
|
||||
nsAutoPtr<NetlinkRoute> mIPv6RouteCheckResult;
|
||||
|
||||
nsTArray<nsAutoPtr<NetlinkMsg> > mOutgoingMessages;
|
||||
|
||||
RefPtr<NetlinkServiceListener> mListener;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* NETLINKSERVICE_H_ */
|
12
netwerk/system/netlink/moz.build
Normal file
12
netwerk/system/netlink/moz.build
Normal file
@ -0,0 +1,12 @@
|
||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'Linux':
|
||||
SOURCES += [
|
||||
'NetlinkService.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
@ -34,7 +34,7 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsCRT.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/StaticPrefs_network.h"
|
||||
#include "mozilla/SHA1.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
@ -115,8 +115,6 @@ nsNotifyAddrListener::nsNotifyAddrListener()
|
||||
mCheckEvent(nullptr),
|
||||
mShutdown(false),
|
||||
mIPInterfaceChecksum(0),
|
||||
mAllowChangedEvent(true),
|
||||
mIPv6Changes(false),
|
||||
mCoalescingActive(false) {
|
||||
InitIphlpapi();
|
||||
}
|
||||
@ -276,7 +274,8 @@ nsNotifyAddrListener::Run() {
|
||||
|
||||
DWORD waitTime = INFINITE;
|
||||
|
||||
if (!sNotifyIpInterfaceChange || !sCancelMibChangeNotify2 || !mIPv6Changes) {
|
||||
if (!sNotifyIpInterfaceChange || !sCancelMibChangeNotify2 ||
|
||||
!StaticPrefs::network_notify_IPv6()) {
|
||||
// For Windows versions which are older than Vista which lack
|
||||
// NotifyIpInterfaceChange. Note this means no IPv6 support.
|
||||
HANDLE ev = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
@ -350,10 +349,6 @@ nsresult nsNotifyAddrListener::Init(void) {
|
||||
observerService->AddObserver(this, "xpcom-shutdown-threads", false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
Preferences::AddBoolVarCache(&mAllowChangedEvent, NETWORK_NOTIFY_CHANGED_PREF,
|
||||
true);
|
||||
Preferences::AddBoolVarCache(&mIPv6Changes, NETWORK_NOTIFY_IPV6_PREF, false);
|
||||
|
||||
mCheckEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
NS_ENSURE_TRUE(mCheckEvent, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
@ -649,7 +644,8 @@ void nsNotifyAddrListener::CheckLinkStatus(void) {
|
||||
|
||||
// Network is online. Topology has changed. Always send CHANGED
|
||||
// before UP - if allowed to and having cooled down.
|
||||
if (mAllowChangedEvent && (since.ToMilliseconds() > 2000)) {
|
||||
if (StaticPrefs::network_notify_changed() &&
|
||||
(since.ToMilliseconds() > 2000)) {
|
||||
NetworkChanged();
|
||||
}
|
||||
}
|
||||
|
@ -88,12 +88,6 @@ class nsNotifyAddrListener : public nsINetworkLinkService,
|
||||
// start time of the checking
|
||||
mozilla::TimeStamp mStartTime;
|
||||
|
||||
// Network changed events are enabled
|
||||
bool mAllowChangedEvent;
|
||||
|
||||
// Check for IPv6 network changes
|
||||
bool mIPv6Changes;
|
||||
|
||||
// Flag set while coalescing change events
|
||||
bool mCoalescingActive;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user