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 }