Bug 1240932 - figure out 'network id' on Linux. r=mcmanus
authorDaniel Stenberg <daniel@haxx.se>
Mon, 11 Apr 2016 06:53:00 +0200
changeset 362921 83e7a178b8263c3b4dc3ef7fb19c3f29efc6b31a
parent 362920 6cd8c193328d7cdae0686d7e5783351a09c773e6
child 362922 c015afbb2b7c60ae81ca3d8c4e1f57cfbb1f2643
push id17058
push userbmo:ttromey@mozilla.com
push dateTue, 03 May 2016 14:35:18 +0000
reviewersmcmanus
bugs1240932
milestone49.0a1
Bug 1240932 - figure out 'network id' on Linux. r=mcmanus
netwerk/system/linux/nsNotifyAddrListener_Linux.cpp
netwerk/system/linux/nsNotifyAddrListener_Linux.h
--- a/netwerk/system/linux/nsNotifyAddrListener_Linux.cpp
+++ b/netwerk/system/linux/nsNotifyAddrListener_Linux.cpp
@@ -18,16 +18,18 @@
 #include "nsServiceManagerUtils.h"
 #include "nsNotifyAddrListener_Linux.h"
 #include "nsString.h"
 #include "mozilla/Logging.h"
 
 #include "mozilla/Services.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/FileUtils.h"
+#include "mozilla/SHA1.h"
+#include "mozilla/Base64.h"
 
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 #include <cutils/properties.h>
 #endif
@@ -95,16 +97,107 @@ nsNotifyAddrListener::GetLinkType(uint32
   NS_ENSURE_ARG_POINTER(aLinkType);
 
   // XXX This function has not yet been implemented for this platform
   *aLinkType = nsINetworkLinkService::LINK_TYPE_UNKNOWN;
   return NS_OK;
 }
 
 //
+// Figure out the current "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).
+//
+void nsNotifyAddrListener::calculateNetworkId(void)
+{
+    const char *kProcRoute = "/proc/net/route"; /* IPv4 routes */
+    const char *kProcArp = "/proc/net/arp";
+
+    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];
+            sprintf(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);
+                                // This 'addition' could potentially be a
+                                // fixed number from the profile or something.
+                                nsAutoCString addition("local-rubbish");
+                                nsAutoCString output;
+                                SHA1Sum sha1;
+                                nsCString combined(mac + addition);
+                                sha1.update(combined.get(), combined.Length());
+                                uint8_t digest[SHA1Sum::kHashSize];
+                                sha1.finish(digest);
+                                nsCString newString(reinterpret_cast<char*>(digest),
+                                                    SHA1Sum::kHashSize);
+                                Base64Encode(newString, output);
+                                LOG(("networkid: id %s\n", output.get()));
+                                mNetworkId = output;
+                                break;
+                            }
+                        }
+                    }
+                }
+                fclose(farp);
+            } /* if (farp) */
+        } /* if (gw) */
+    } /* if (froute) */
+}
+
+//
 // Check if there's a network interface available to do networking on.
 //
 void nsNotifyAddrListener::checkLink(void)
 {
 #ifdef MOZ_WIDGET_GONK
     // b2g instead has NetworkManager.js which handles UP/DOWN
 #else
     struct ifaddrs *list;
@@ -247,16 +340,17 @@ void nsNotifyAddrListener::OnNetlinkMess
     }
 
     if (networkChange && mAllowChangedEvent) {
         NetworkChanged();
     }
 
     if (networkChange) {
         checkLink();
+        calculateNetworkId();
     }
 }
 
 NS_IMETHODIMP
 nsNotifyAddrListener::Run()
 {
     int netlinkSocket = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
     if (netlinkSocket < 0) {
@@ -283,16 +377,18 @@ nsNotifyAddrListener::Run()
     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) {
--- a/netwerk/system/linux/nsNotifyAddrListener_Linux.h
+++ b/netwerk/system/linux/nsNotifyAddrListener_Linux.h
@@ -56,16 +56,20 @@ private:
     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);
+    nsCString mNetworkId;
+
     // Checks if there's a network "link"
     void checkLink(void);
 
     // Deals with incoming NETLINK messages.
     void OnNetlinkMessage(int NetlinkSocket);
 
     nsCOMPtr<nsIThread> mThread;