tor-browser

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

TestLocalNetworkAccess.cpp (12327B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "TestCommon.h"
      6 #include "gtest/gtest.h"
      7 #include "mozilla/gtest/MozAssertions.h"
      8 #include "mozilla/StaticPrefs_network.h"
      9 #include "mozilla/Preferences.h"
     10 #include "mozilla/net/DNS.h"
     11 #include "nsNetUtil.h"
     12 #include "nsIOService.h"
     13 
     14 TEST(TestNetAddrLNAUtil, IPAddressSpaceCategorization)
     15 {
     16  /*--------------------------------------------------------------------------*
     17 | Network              | Description            | RFC       | Scope   |
     18 |----------------------|------------------------|-----------|------------------|
     19 127.0.0.0/8            | IPv4 Loopback          | RFC1122   | local   |
     20 10.0.0.0/8             | Private Use            | RFC1918   | private |
     21 100.64.0.0/10          | Carrier-Grade NAT      | RFC6598   | private |
     22 172.16.0.0/12          | Private Use            | RFC1918   | private |
     23 192.168.0.0/16         | Private Use            | RFC1918   | private |
     24 198.18.0.0/15          | Benchmarking           | RFC2544   | pref/local
     25 169.254.0.0/16         | Link Local             | RFC3927   | private |
     26 ::1/128                | IPv6 Loopback          | RFC4291   | local   |
     27 fc00::/7               | Unique Local           | RFC4193   | private |
     28 fe80::/10              | Link-Local Unicast     | RFC4291   | private |
     29 ::ffff:0:0/96          | IPv4-mapped            | RFC4291   | IPv4-mapped
     30 address space |
     31 *--------------------------------------------------------------------------*/
     32  using namespace mozilla::net;
     33  using namespace mozilla;
     34 
     35  struct TestCase {
     36    const char* mIp;
     37    nsILoadInfo::IPAddressSpace mExpectedSpace;
     38  };
     39 
     40  std::vector<TestCase> testCases = {
     41      // Local IPv4
     42      {"", nsILoadInfo::IPAddressSpace::Unknown},
     43      {"127.0.0.1", nsILoadInfo::IPAddressSpace::Local},
     44      {"198.18.0.0", StaticPrefs::network_lna_benchmarking_is_local()
     45                         ? nsILoadInfo::IPAddressSpace::Local
     46                         : nsILoadInfo::IPAddressSpace::Public},
     47      {"198.19.255.255", StaticPrefs::network_lna_benchmarking_is_local()
     48                             ? nsILoadInfo::IPAddressSpace::Local
     49                             : nsILoadInfo::IPAddressSpace::Public},
     50 
     51      // Private IPv4
     52      {"10.0.0.1", nsILoadInfo::IPAddressSpace::Private},
     53      {"100.64.0.1", nsILoadInfo::IPAddressSpace::Private},
     54      {"100.127.255.254", nsILoadInfo::IPAddressSpace::Private},
     55      {"172.16.0.1", nsILoadInfo::IPAddressSpace::Private},
     56      {"172.31.255.255", nsILoadInfo::IPAddressSpace::Private},
     57      {"192.168.1.1", nsILoadInfo::IPAddressSpace::Private},
     58      {"169.254.0.1", nsILoadInfo::IPAddressSpace::Private},
     59      {"169.254.255.254", nsILoadInfo::IPAddressSpace::Private},
     60 
     61      // IPv6 Local and Private
     62      {"::1", nsILoadInfo::IPAddressSpace::Local},       // Loopback
     63      {"fc00::", nsILoadInfo::IPAddressSpace::Private},  // Unique Local
     64      {"fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
     65       nsILoadInfo::IPAddressSpace::Private},
     66      {"fe80::1", nsILoadInfo::IPAddressSpace::Private},  // Link-local
     67 
     68      // IPv4-mapped IPv6 (mapped IPv4, should fall back to IPv4 classification)
     69      {"::ffff:127.0.0.1", nsILoadInfo::IPAddressSpace::Local},   // Loopback
     70      {"::ffff:10.0.0.1", nsILoadInfo::IPAddressSpace::Private},  // Private
     71      {"::ffff:1.1.1.1", nsILoadInfo::IPAddressSpace::Public},    // Public
     72 
     73      // Public IPv4
     74      {"8.8.8.8", nsILoadInfo::IPAddressSpace::Public},
     75      {"1.1.1.1", nsILoadInfo::IPAddressSpace::Public},
     76 
     77      // Public IPv6
     78      {"2001:4860:4860::8888", nsILoadInfo::IPAddressSpace::Public},
     79      {"2606:4700:4700::1111", nsILoadInfo::IPAddressSpace::Public}};
     80 
     81  for (const auto& testCase : testCases) {
     82    NetAddr addr;
     83    addr.InitFromString(nsCString(testCase.mIp));
     84    if (addr.raw.family == AF_INET) {
     85      EXPECT_EQ(addr.GetIpAddressSpace(), testCase.mExpectedSpace)
     86          << "Failed for IP: " << testCase.mIp;
     87    } else if (addr.raw.family == AF_INET6) {
     88      EXPECT_EQ(addr.GetIpAddressSpace(), testCase.mExpectedSpace)
     89          << "Failed for IP: " << testCase.mIp;
     90    } else {
     91      EXPECT_EQ(addr.GetIpAddressSpace(), nsILoadInfo::IPAddressSpace::Unknown)
     92          << "Failed for IP: " << testCase.mIp;
     93    }
     94  }
     95 }
     96 
     97 TEST(TestNetAddrLNAUtil, DefaultAndOverrideTransitions)
     98 {
     99  using mozilla::Preferences;
    100  using mozilla::net::NetAddr;
    101  using IPAddressSpace = nsILoadInfo::IPAddressSpace;
    102  struct TestCase {
    103    const char* ip;
    104    uint16_t port;
    105    IPAddressSpace defaultSpace;
    106    IPAddressSpace overrideSpace;
    107    const char* prefName;
    108  };
    109 
    110  std::vector<TestCase> testCases = {
    111      // Public -> Private
    112      {"8.8.8.8", 80, IPAddressSpace::Public, IPAddressSpace::Private,
    113       "network.lna.address_space.private.override"},
    114 
    115      // Public -> Local
    116      {"8.8.4.4", 53, IPAddressSpace::Public, IPAddressSpace::Local,
    117       "network.lna.address_space.local.override"},
    118 
    119      // Private -> Public
    120      {"192.168.0.1", 8080, IPAddressSpace::Private, IPAddressSpace::Public,
    121       "network.lna.address_space.public.override"},
    122 
    123      // Private -> Local
    124      {"10.0.0.1", 1234, IPAddressSpace::Private, IPAddressSpace::Local,
    125       "network.lna.address_space.local.override"},
    126 
    127      // Local -> Public
    128      {"127.0.0.1", 4444, IPAddressSpace::Local, IPAddressSpace::Public,
    129       "network.lna.address_space.public.override"},
    130 
    131      // Local -> Private
    132      {"127.0.0.1", 9999, IPAddressSpace::Local, IPAddressSpace::Private,
    133       "network.lna.address_space.private.override"},
    134  };
    135 
    136  for (const auto& tc : testCases) {
    137    NetAddr addr;
    138    addr.InitFromString(nsCString(tc.ip), tc.port);
    139    ASSERT_EQ(addr.GetIpAddressSpace(), tc.defaultSpace)
    140        << "Expected default space for " << tc.ip << ":" << tc.port;
    141 
    142    std::string overrideStr =
    143        std::string(tc.ip) + ":" + std::to_string(tc.port);
    144    Preferences::SetCString(tc.prefName, overrideStr.c_str());
    145 
    146    NetAddr overriddenAddr;
    147    overriddenAddr.InitFromString(nsCString(tc.ip), tc.port);
    148    ASSERT_EQ(overriddenAddr.GetIpAddressSpace(), tc.overrideSpace)
    149        << "Expected override to " << tc.overrideSpace << " for "
    150        << overrideStr;
    151 
    152    // Reset preference and confirm classification returns to default
    153    Preferences::SetCString(tc.prefName, ""_ns);
    154    NetAddr resetAddr;
    155    resetAddr.InitFromString(nsCString(tc.ip), tc.port);
    156    ASSERT_EQ(resetAddr.GetIpAddressSpace(), tc.defaultSpace)
    157        << "Expected reset back to default space for " << tc.ip;
    158  }
    159 }
    160 
    161 TEST(TestNetAddrLNAUtil, ShouldSkipDomainForLNA)
    162 {
    163  using mozilla::Preferences;
    164  // Get nsIOService instance
    165  mozilla::net::nsIOService* ioService = mozilla::net::gIOService;
    166  ASSERT_NE(ioService, nullptr);
    167 
    168  // Test with empty preference (should not skip any domains)
    169  Preferences::SetCString("network.lna.skip-domains", ""_ns);
    170  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA("example.com"_ns));
    171  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA("test.example.com"_ns));
    172  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA("localhost"_ns));
    173 
    174  // Test exact domain matching
    175  Preferences::SetCString("network.lna.skip-domains",
    176                          "example.com,test.org"_ns);
    177  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("example.com"_ns));
    178  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("test.org"_ns));
    179  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA("sub.example.com"_ns));
    180  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA("example.org"_ns));
    181  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA("notexample.com"_ns));
    182 
    183  // Test wildcard domain matching
    184  Preferences::SetCString("network.lna.skip-domains",
    185                          "*.example.com,*.test.org"_ns);
    186  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("sub.example.com"_ns));
    187  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("deep.sub.example.com"_ns));
    188  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("api.test.org"_ns));
    189  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA(
    190      "example.com"_ns));  // Should match exact domain too
    191  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA(
    192      "test.org"_ns));  // Should match exact domain too
    193  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA("example.net"_ns));
    194  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA("notexample.com"_ns));
    195 
    196  // Test more suffix wildcard patterns
    197  Preferences::SetCString("network.lna.skip-domains",
    198                          "*.local,*.internal,*.test"_ns);
    199  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("server.local"_ns));
    200  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("api.internal"_ns));
    201  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("service.test"_ns));
    202  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("deep.subdomain.local"_ns));
    203  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA(
    204      "local"_ns));  // Should match exact domain too
    205  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA(
    206      "internal"_ns));  // Should match exact domain too
    207  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA("local.example.com"_ns));
    208  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA("localhost"_ns));
    209  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA("example.com"_ns));
    210 
    211  // Test mixed patterns (exact and suffix wildcard)
    212  Preferences::SetCString(
    213      "network.lna.skip-domains",
    214      "localhost,*.dev.local,*.staging.com,production.example.com"_ns);
    215  // Exact matches
    216  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("localhost"_ns));
    217  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("production.example.com"_ns));
    218  // Suffix wildcard matches
    219  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("api.dev.local"_ns));
    220  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("web.dev.local"_ns));
    221  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("dev.local"_ns));
    222  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("test.staging.com"_ns));
    223  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("api.staging.com"_ns));
    224  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("staging.com"_ns));
    225  // Non-matches
    226  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA("example.com"_ns));
    227  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA("dev.example.com"_ns));
    228  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA("staging.example.com"_ns));
    229 
    230  // Test with whitespace and empty entries
    231  Preferences::SetCString(
    232      "network.lna.skip-domains",
    233      " example.com , , *.test.local , admin.internal  "_ns);
    234  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("example.com"_ns));
    235  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("api.test.local"_ns));
    236  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("admin.internal"_ns));
    237  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA("test.com"_ns));
    238 
    239  // Test invalid patterns (unknown patterns treated as exact match)
    240  Preferences::SetCString("network.lna.skip-domains",
    241                          "example.com,invalid.pattern"_ns);
    242  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA(
    243      "example.com"_ns));  // Valid exact match
    244  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA(
    245      "invalid.pattern"_ns));  // Treated as exact match
    246  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA("test.com"_ns));  // No match
    247 
    248  // Test case sensitivity
    249  Preferences::SetCString("network.lna.skip-domains",
    250                          "Example.COM,*.Test.ORG"_ns);
    251  EXPECT_TRUE(
    252      ioService->ShouldSkipDomainForLNA("Example.COM"_ns));  // Exact case match
    253  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA(
    254      "example.com"_ns));  // Different case (no match)
    255  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA(
    256      "api.Test.ORG"_ns));  // Wildcard case match
    257  EXPECT_FALSE(ioService->ShouldSkipDomainForLNA(
    258      "api.test.org"_ns));  // Different case (no match)
    259 
    260  // Test plain "*" matches all domains
    261  Preferences::SetCString("network.lna.skip-domains", "*"_ns);
    262  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("example.com"_ns));
    263  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("test.org"_ns));
    264  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("localhost"_ns));
    265  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("any.domain.here"_ns));
    266  EXPECT_TRUE(ioService->ShouldSkipDomainForLNA("server.local"_ns));
    267 
    268  // Reset preference for cleanup
    269  Preferences::SetCString("network.lna.skip-domains", ""_ns);
    270 }