summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/geolocation/empty_device_data_provider.cc2
-rw-r--r--chrome/browser/geolocation/gateway_data_provider_linux.cc226
-rw-r--r--chrome/browser/geolocation/gateway_data_provider_linux.h22
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--chrome/common/chrome_switches.cc2
5 files changed, 252 insertions, 2 deletions
diff --git a/chrome/browser/geolocation/empty_device_data_provider.cc b/chrome/browser/geolocation/empty_device_data_provider.cc
index b11dd79..2b95c88 100644
--- a/chrome/browser/geolocation/empty_device_data_provider.cc
+++ b/chrome/browser/geolocation/empty_device_data_provider.cc
@@ -21,7 +21,7 @@ WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() {
#endif
// Only define for platforms that lack a real gateway data provider.
-#if !defined(OS_WIN)
+#if !defined(OS_LINUX) && !defined(OS_WIN)
// static
template<>
GatewayDataProviderImplBase* GatewayDataProvider::DefaultFactoryFunction() {
diff --git a/chrome/browser/geolocation/gateway_data_provider_linux.cc b/chrome/browser/geolocation/gateway_data_provider_linux.cc
new file mode 100644
index 0000000..f1779cb
--- /dev/null
+++ b/chrome/browser/geolocation/gateway_data_provider_linux.cc
@@ -0,0 +1,226 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Provides MAC addresses of connected routers by using the /proc/net/
+// directory which contains files with network information.
+// This directory is used in most Linux based operating systems.
+
+#include "chrome/browser/geolocation/gateway_data_provider_linux.h"
+
+#include <algorithm>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <set>
+#include <string>
+#include <sys/ioctl.h>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/string_number_conversions.h"
+#include "base/string_tokenizer.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/geolocation/empty_device_data_provider.h"
+#include "chrome/browser/geolocation/gateway_data_provider_common.h"
+#include "chrome/common/chrome_switches.h"
+
+namespace {
+const unsigned int kMaxArpIterations = 30;
+const unsigned int kMaxRouteIterations = 20;
+const char kNoGateway[] = "00000000";
+const char kArpFilePath[] = "/proc/net/arp";
+const char kRouteFilePath[] = "/proc/net/route";
+
+// Converts an IP address held in a little endian paired hex format to period
+// separated decimal format. For example 0101A8C0 becomes 192.168.1.1
+std::string HexToIpv4Format(std::string& hex_address) {
+ if (hex_address.size() != 8)
+ return "";
+ std::vector<uint8> bytes;
+ base::HexStringToBytes(hex_address, &bytes);
+ if (bytes.size() != 4)
+ return "";
+ struct in_addr in;
+ uint32 ip_native_endian;
+ memcpy(&ip_native_endian, &bytes[0], 4);
+ in.s_addr = htonl(ip_native_endian);
+ return inet_ntoa(in);
+}
+
+// TODO(joth): Cache the sets of gateways and MAC addresses to avoid reading
+// through the arp table when the routing table hasn't changed.
+class LinuxGatewayApi : public GatewayDataProviderCommon::GatewayApiInterface {
+ public:
+ LinuxGatewayApi() {}
+ virtual ~LinuxGatewayApi() {}
+
+ static LinuxGatewayApi* Create() {
+ return new LinuxGatewayApi();
+ }
+
+ // GatewayApiInterface
+ virtual bool GetRouterData(GatewayData::RouterDataSet* data);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LinuxGatewayApi);
+};
+
+// Gets a set of gateways using data from /proc/net/route
+// Returns false if we cannot read the route file or we cannot classify the
+// type of network adapter.
+// Routing data is held in the following format
+// Note: "|" represents a delimeter.
+// Iface|Destination|Gateway|Flags|RefCnt|Use|Metric|Mask|MTU|Window|IRTT
+// The delimiter for this table is "\t".
+// ioctl calls are used to verify the type of network adapter, using interface
+// names from the route table.
+bool GetGateways(std::set<std::string>* gateways) {
+ FilePath route_file_path(kRouteFilePath);
+ std::string route_file;
+ if (!file_util::ReadFileToString(route_file_path, &route_file)) {
+ // Unable to read file.
+ return false;
+ }
+ StringTokenizer tokenized_route_file(route_file, "\n");
+ std::vector<std::string> route_data;
+ // Remove column labels.
+ tokenized_route_file.GetNext();
+
+ // Get rows of data.
+ while (tokenized_route_file.GetNext() &&
+ route_data.size() < kMaxRouteIterations)
+ route_data.push_back(tokenized_route_file.token());
+
+ if (route_data.empty()) {
+ // Having no data is not an error case.
+ return true;
+ }
+
+ int sock;
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock == -1)
+ return false;
+ struct ifreq network_device;
+
+ for (size_t j = 0; j < route_data.size(); ++j) {
+ // Get gateway address.
+ std::string gateway;
+ StringTokenizer tokenized_route_data(route_data[j], "\t");
+ // Check if device is an Ethernet device.
+ if (!tokenized_route_data.GetNext()) // Get Iface.
+ continue;
+ // Ensure space for the null term too.
+ if (tokenized_route_data.token().size() >=
+ arraysize(network_device.ifr_name))
+ continue;
+ memset(&network_device, 0, sizeof(network_device));
+ base::strlcpy(network_device.ifr_name,
+ tokenized_route_data.token().c_str(),
+ arraysize(network_device.ifr_name));
+ if (ioctl(sock, SIOCGIFHWADDR,
+ reinterpret_cast<char*>(&network_device)) < 0) {
+ // Could not get device type.
+ continue;
+ }
+ if (network_device.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ // Device is not an Ethernet device.
+ continue;
+ }
+ if (!tokenized_route_data.GetNext()) // Skip Destination.
+ continue;
+ if (!tokenized_route_data.GetNext()) // Get Gateway.
+ continue;
+ gateway = tokenized_route_data.token();
+ if (gateway != kNoGateway) {
+ // TODO(joth): Currently only works for gateways using IPv4.
+ std::string gateway_int_format = HexToIpv4Format(gateway);
+ if (!gateway_int_format.empty())
+ gateways->insert(gateway_int_format);
+ }
+ }
+
+ close(sock);
+ return true;
+}
+
+// Gets a RouterDataSet containing MAC addresses related to any connected
+// routers. Returns false if we cannot read the arp file.
+// The /proc/net/arp file contains arp data in the following format
+// Note: "|" represents a delimeter.
+// IP address|HW type|Flags|HW address|Mask|Device
+// The delimiter for this table is " ".
+bool GetMacAddresses(GatewayData::RouterDataSet* data,
+ std::set<std::string>* gateways) {
+ // Find MAC addresses of routers
+ FilePath arp_file_path(kArpFilePath);
+ std::string arp_file_out;
+ if (!file_util::ReadFileToString(arp_file_path, &arp_file_out)) {
+ // Unable to read file.
+ return false;
+ }
+ StringTokenizer tokenized_arp_file(arp_file_out, "\n");
+ std::vector<std::string> arp_data;
+ // Remove column labels.
+ tokenized_arp_file.GetNext();
+
+ // Get rows of data.
+ while (tokenized_arp_file.GetNext() && arp_data.size() < kMaxArpIterations)
+ arp_data.push_back(tokenized_arp_file.token());
+
+ for (size_t k = 0; k < arp_data.size(); k++) {
+ std::string ip_address;
+ StringTokenizer tokenized_arp_data(arp_data[k], " ");
+ if (!tokenized_arp_data.GetNext()) // Get IP address.
+ continue;
+ ip_address = tokenized_arp_data.token();
+ if (gateways->find(ip_address) == gateways->end())
+ continue;
+ if (!tokenized_arp_data.GetNext()) // Skip HW type.
+ continue;
+ if (!tokenized_arp_data.GetNext()) // Skip flags.
+ continue;
+ if (!tokenized_arp_data.GetNext()) // Get HW address.
+ continue;
+ RouterData router;
+ std::string mac_add;
+ mac_add = tokenized_arp_data.token();
+ std::replace(mac_add.begin(), mac_add.end(), ':', '-');
+ router.mac_address = UTF8ToUTF16(mac_add);
+ data->insert(router);
+ }
+
+ return true;
+}
+
+bool LinuxGatewayApi::GetRouterData(GatewayData::RouterDataSet* data) {
+ std::set<std::string> gateways;
+ if (!GetGateways(&gateways))
+ return false;
+ if (gateways.empty())
+ return true;
+ return GetMacAddresses(data, &gateways);
+}
+} // namespace
+
+// static
+template<>
+GatewayDataProviderImplBase* GatewayDataProvider::DefaultFactoryFunction() {
+ if (!CommandLine::ForCurrentProcess()
+ ->HasSwitch(switches::kExperimentalLocationFeatures))
+ return new EmptyDeviceDataProvider<GatewayData>();
+ return new GatewayDataProviderLinux();
+}
+
+GatewayDataProviderLinux::GatewayDataProviderLinux() {
+}
+
+GatewayDataProviderLinux::~GatewayDataProviderLinux() {
+}
+
+GatewayDataProviderCommon::GatewayApiInterface*
+ GatewayDataProviderLinux::NewGatewayApi() {
+ return LinuxGatewayApi::Create();
+}
diff --git a/chrome/browser/geolocation/gateway_data_provider_linux.h b/chrome/browser/geolocation/gateway_data_provider_linux.h
new file mode 100644
index 0000000..5d01d0b
--- /dev/null
+++ b/chrome/browser/geolocation/gateway_data_provider_linux.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_GEOLOCATION_GATEWAY_DATA_PROVIDER_LINUX_H_
+#define CHROME_BROWSER_GEOLOCATION_GATEWAY_DATA_PROVIDER_LINUX_H_
+#pragma once
+#include "chrome/browser/geolocation/gateway_data_provider_common.h"
+
+class GatewayDataProviderLinux : public GatewayDataProviderCommon {
+ public:
+ GatewayDataProviderLinux();
+
+ private:
+ virtual ~GatewayDataProviderLinux();
+
+ // GatewayDataProviderCommon
+ virtual GatewayApiInterface* NewGatewayApi();
+ DISALLOW_COPY_AND_ASSIGN(GatewayDataProviderLinux);
+};
+
+#endif // CHROME_BROWSER_GEOLOCATION_GATEWAY_DATA_PROVIDER_LINUX_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 6bbebcf..82d8823 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1644,6 +1644,8 @@
'browser/geolocation/empty_device_data_provider.h',
'browser/geolocation/gateway_data_provider_common.cc',
'browser/geolocation/gateway_data_provider_common.h',
+ 'browser/geolocation/gateway_data_provider_linux.cc',
+ 'browser/geolocation/gateway_data_provider_linux.h',
'browser/geolocation/gateway_data_provider_win.cc',
'browser/geolocation/gateway_data_provider_win.h',
'browser/geolocation/geolocation_content_settings_map.cc',
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 60dfd87..f2ba206 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -567,7 +567,7 @@ const char kEnableXSSAuditor[] = "enable-xss-auditor";
// Enables experimental features for the geolocation API.
// Current features:
// - CoreLocation support for Mac OS X 10.6
-// - Gateway location for Windows
+// - Gateway location for Linux and Windows
// - Location platform support for Windows 7
const char kExperimentalLocationFeatures[] = "experimental-location-features";