github.com/noisysockets/noisysockets@v0.21.2-0.20240515114641-7f467e651c90/internal/dns/addrselect/addrselect_test.go (about) 1 // SPDX-License-Identifier: MPL-2.0 2 /* 3 * Copyright (C) 2024 The Noisy Sockets Authors. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * Portions of this file are based on code originally from the Go project, 10 * 11 * Copyright (c) 2015 The Go Authors. All rights reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions are 15 * met: 16 * 17 * * Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * * Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following disclaimer 21 * in the documentation and/or other materials provided with the 22 * distribution. 23 * * Neither the name of Google Inc. nor the names of its 24 * contributors may be used to endorse or promote products derived from 25 * this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 31 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 32 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 33 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 package addrselect 41 42 import ( 43 "net/netip" 44 "reflect" 45 "testing" 46 47 "github.com/noisysockets/noisysockets/network" 48 ) 49 50 func TestSortByRFC6724(t *testing.T) { 51 tests := []struct { 52 in []netip.Addr 53 srcs []netip.Addr 54 want []netip.Addr 55 reverse bool // also test it starting backwards 56 }{ 57 // Examples from RFC 6724 section 10.2: 58 59 // Prefer matching scope. 60 { 61 in: []netip.Addr{ 62 netip.MustParseAddr("2001:db8:1::1"), 63 netip.MustParseAddr("198.51.100.121"), 64 }, 65 srcs: []netip.Addr{ 66 netip.MustParseAddr("2001:db8:1::2"), 67 netip.MustParseAddr("169.254.13.78"), 68 }, 69 want: []netip.Addr{ 70 netip.MustParseAddr("2001:db8:1::1"), 71 netip.MustParseAddr("198.51.100.121"), 72 }, 73 reverse: true, 74 }, 75 76 // Prefer matching scope. 77 { 78 in: []netip.Addr{ 79 netip.MustParseAddr("2001:db8:1::1"), 80 netip.MustParseAddr("198.51.100.121"), 81 }, 82 srcs: []netip.Addr{ 83 netip.MustParseAddr("fe80::1"), 84 netip.MustParseAddr("198.51.100.117"), 85 }, 86 want: []netip.Addr{ 87 netip.MustParseAddr("198.51.100.121"), 88 netip.MustParseAddr("2001:db8:1::1"), 89 }, 90 reverse: true, 91 }, 92 93 // Prefer higher precedence. 94 { 95 in: []netip.Addr{ 96 netip.MustParseAddr("2001:db8:1::1"), 97 netip.MustParseAddr("10.1.2.3"), 98 }, 99 srcs: []netip.Addr{ 100 netip.MustParseAddr("2001:db8:1::2"), 101 netip.MustParseAddr("10.1.2.4"), 102 }, 103 want: []netip.Addr{ 104 netip.MustParseAddr("2001:db8:1::1"), 105 netip.MustParseAddr("10.1.2.3"), 106 }, 107 reverse: true, 108 }, 109 110 // Prefer smaller scope. 111 { 112 in: []netip.Addr{ 113 netip.MustParseAddr("2001:db8:1::1"), 114 netip.MustParseAddr("fe80::1"), 115 }, 116 srcs: []netip.Addr{ 117 netip.MustParseAddr("2001:db8:1::2"), 118 netip.MustParseAddr("fe80::2"), 119 }, 120 want: []netip.Addr{ 121 netip.MustParseAddr("fe80::1"), 122 netip.MustParseAddr("2001:db8:1::1"), 123 }, 124 reverse: true, 125 }, 126 127 // Issue 13283. Having a 10/8 source address does not 128 // mean we should prefer 23/8 destination addresses. 129 { 130 in: []netip.Addr{ 131 netip.MustParseAddr("54.83.193.112"), 132 netip.MustParseAddr("184.72.238.214"), 133 netip.MustParseAddr("23.23.172.185"), 134 netip.MustParseAddr("75.101.148.21"), 135 netip.MustParseAddr("23.23.134.56"), 136 netip.MustParseAddr("23.21.50.150"), 137 }, 138 srcs: []netip.Addr{ 139 netip.MustParseAddr("10.2.3.4"), 140 netip.MustParseAddr("10.2.3.4"), 141 netip.MustParseAddr("10.2.3.4"), 142 netip.MustParseAddr("10.2.3.4"), 143 netip.MustParseAddr("10.2.3.4"), 144 netip.MustParseAddr("10.2.3.4"), 145 }, 146 want: []netip.Addr{ 147 netip.MustParseAddr("54.83.193.112"), 148 netip.MustParseAddr("184.72.238.214"), 149 netip.MustParseAddr("23.23.172.185"), 150 netip.MustParseAddr("75.101.148.21"), 151 netip.MustParseAddr("23.23.134.56"), 152 netip.MustParseAddr("23.21.50.150"), 153 }, 154 reverse: false, 155 }, 156 } 157 for i, tt := range tests { 158 inCopy := make([]netip.Addr, len(tt.in)) 159 copy(inCopy, tt.in) 160 srcCopy := make([]netip.Addr, len(tt.in)) 161 copy(srcCopy, tt.srcs) 162 SortByRFC6724withSrcs(network.Host(), inCopy, srcCopy) 163 if !reflect.DeepEqual(inCopy, tt.want) { 164 t.Errorf("test %d:\nin = %s\ngot: %s\nwant: %s\n", i, tt.in, inCopy, tt.want) 165 } 166 if tt.reverse { 167 copy(inCopy, tt.in) 168 copy(srcCopy, tt.srcs) 169 for j := 0; j < len(inCopy)/2; j++ { 170 k := len(inCopy) - j - 1 171 inCopy[j], inCopy[k] = inCopy[k], inCopy[j] 172 srcCopy[j], srcCopy[k] = srcCopy[k], srcCopy[j] 173 } 174 SortByRFC6724withSrcs(network.Host(), inCopy, srcCopy) 175 if !reflect.DeepEqual(inCopy, tt.want) { 176 t.Errorf("test %d, starting backwards:\nin = %s\ngot: %s\nwant: %s\n", i, tt.in, inCopy, tt.want) 177 } 178 } 179 180 } 181 182 } 183 184 func TestRFC6724PolicyTableOrder(t *testing.T) { 185 for i := 0; i < len(rfc6724policyTable)-1; i++ { 186 if !(rfc6724policyTable[i].Prefix.Bits() >= rfc6724policyTable[i+1].Prefix.Bits()) { 187 t.Errorf("rfc6724policyTable item number %d sorted in wrong order = %d bits, next item = %d bits;", i, rfc6724policyTable[i].Prefix.Bits(), rfc6724policyTable[i+1].Prefix.Bits()) 188 } 189 } 190 } 191 192 func TestRFC6724PolicyTableContent(t *testing.T) { 193 expectedRfc6724policyTable := policyTable{ 194 { 195 Prefix: netip.MustParsePrefix("::1/128"), 196 Precedence: 50, 197 Label: 0, 198 }, 199 { 200 Prefix: netip.MustParsePrefix("::ffff:0:0/96"), 201 Precedence: 35, 202 Label: 4, 203 }, 204 { 205 Prefix: netip.MustParsePrefix("::/96"), 206 Precedence: 1, 207 Label: 3, 208 }, 209 { 210 Prefix: netip.MustParsePrefix("2001::/32"), 211 Precedence: 5, 212 Label: 5, 213 }, 214 { 215 Prefix: netip.MustParsePrefix("2002::/16"), 216 Precedence: 30, 217 Label: 2, 218 }, 219 { 220 Prefix: netip.MustParsePrefix("3ffe::/16"), 221 Precedence: 1, 222 Label: 12, 223 }, 224 { 225 Prefix: netip.MustParsePrefix("fec0::/10"), 226 Precedence: 1, 227 Label: 11, 228 }, 229 { 230 Prefix: netip.MustParsePrefix("fc00::/7"), 231 Precedence: 3, 232 Label: 13, 233 }, 234 { 235 Prefix: netip.MustParsePrefix("::/0"), 236 Precedence: 40, 237 Label: 1, 238 }, 239 } 240 if !reflect.DeepEqual(rfc6724policyTable, expectedRfc6724policyTable) { 241 t.Errorf("rfc6724policyTable has wrong contend = %v; want %v", rfc6724policyTable, expectedRfc6724policyTable) 242 } 243 } 244 245 func TestRFC6724PolicyTableClassify(t *testing.T) { 246 tests := []struct { 247 ip netip.Addr 248 want policyTableEntry 249 }{ 250 { 251 ip: netip.MustParseAddr("127.0.0.1"), 252 want: policyTableEntry{ 253 Prefix: netip.MustParsePrefix("::ffff:0:0/96"), 254 Precedence: 35, 255 Label: 4, 256 }, 257 }, 258 { 259 ip: netip.MustParseAddr("2601:645:8002:a500:986f:1db8:c836:bd65"), 260 want: policyTableEntry{ 261 Prefix: netip.MustParsePrefix("::/0"), 262 Precedence: 40, 263 Label: 1, 264 }, 265 }, 266 { 267 ip: netip.MustParseAddr("::1"), 268 want: policyTableEntry{ 269 Prefix: netip.MustParsePrefix("::1/128"), 270 Precedence: 50, 271 Label: 0, 272 }, 273 }, 274 { 275 ip: netip.MustParseAddr("2002::ab12"), 276 want: policyTableEntry{ 277 Prefix: netip.MustParsePrefix("2002::/16"), 278 Precedence: 30, 279 Label: 2, 280 }, 281 }, 282 } 283 for i, tt := range tests { 284 got := rfc6724policyTable.Classify(tt.ip) 285 if !reflect.DeepEqual(got, tt.want) { 286 t.Errorf("%d. Classify(%s) = %v; want %v", i, tt.ip, got, tt.want) 287 } 288 } 289 } 290 291 func TestRFC6724ClassifyScope(t *testing.T) { 292 tests := []struct { 293 ip netip.Addr 294 want scope 295 }{ 296 {netip.MustParseAddr("127.0.0.1"), scopeLinkLocal}, // rfc6724#section-3.2 297 {netip.MustParseAddr("::1"), scopeLinkLocal}, // rfc4007#section-4 298 {netip.MustParseAddr("169.254.1.2"), scopeLinkLocal}, // rfc6724#section-3.2 299 {netip.MustParseAddr("fec0::1"), scopeSiteLocal}, 300 {netip.MustParseAddr("8.8.8.8"), scopeGlobal}, 301 302 {netip.MustParseAddr("ff02::"), scopeLinkLocal}, // IPv6 multicast 303 {netip.MustParseAddr("ff05::"), scopeSiteLocal}, // IPv6 multicast 304 {netip.MustParseAddr("ff04::"), scopeAdminLocal}, // IPv6 multicast 305 {netip.MustParseAddr("ff0e::"), scopeGlobal}, // IPv6 multicast 306 307 {netip.AddrFrom16([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xe0, 0, 0, 0}), scopeGlobal}, // IPv4 link-local multicast as 16 bytes 308 {netip.AddrFrom16([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xe0, 2, 2, 2}), scopeGlobal}, // IPv4 global multicast as 16 bytes 309 {netip.AddrFrom4([4]byte{0xe0, 0, 0, 0}), scopeGlobal}, // IPv4 link-local multicast as 4 bytes 310 {netip.AddrFrom4([4]byte{0xe0, 2, 2, 2}), scopeGlobal}, // IPv4 global multicast as 4 bytes 311 } 312 for i, tt := range tests { 313 got := classifyScope(tt.ip) 314 if got != tt.want { 315 t.Errorf("%d. classifyScope(%s) = %x; want %x", i, tt.ip, got, tt.want) 316 } 317 } 318 } 319 320 func TestRFC6724CommonPrefixLength(t *testing.T) { 321 tests := []struct { 322 a netip.Addr 323 b netip.Addr 324 want int 325 }{ 326 {netip.MustParseAddr("fe80::1"), netip.MustParseAddr("fe80::2"), 64}, 327 {netip.MustParseAddr("fe81::1"), netip.MustParseAddr("fe80::2"), 15}, 328 {netip.MustParseAddr("127.0.0.1"), netip.MustParseAddr("fe80::1"), 0}, // diff size 329 {netip.AddrFrom4([4]byte{1, 2, 3, 4}), netip.AddrFrom4([4]byte{1, 2, 3, 4}), 32}, 330 {netip.AddrFrom4([4]byte{1, 2, 255, 255}), netip.AddrFrom4([4]byte{1, 2, 0, 0}), 16}, 331 {netip.AddrFrom4([4]byte{1, 2, 127, 255}), netip.AddrFrom4([4]byte{1, 2, 0, 0}), 17}, 332 {netip.AddrFrom4([4]byte{1, 2, 63, 255}), netip.AddrFrom4([4]byte{1, 2, 0, 0}), 18}, 333 {netip.AddrFrom4([4]byte{1, 2, 31, 255}), netip.AddrFrom4([4]byte{1, 2, 0, 0}), 19}, 334 {netip.AddrFrom4([4]byte{1, 2, 15, 255}), netip.AddrFrom4([4]byte{1, 2, 0, 0}), 20}, 335 {netip.AddrFrom4([4]byte{1, 2, 7, 255}), netip.AddrFrom4([4]byte{1, 2, 0, 0}), 21}, 336 {netip.AddrFrom4([4]byte{1, 2, 3, 255}), netip.AddrFrom4([4]byte{1, 2, 0, 0}), 22}, 337 {netip.AddrFrom4([4]byte{1, 2, 1, 255}), netip.AddrFrom4([4]byte{1, 2, 0, 0}), 23}, 338 {netip.AddrFrom4([4]byte{1, 2, 0, 255}), netip.AddrFrom4([4]byte{1, 2, 0, 0}), 24}, 339 } 340 for i, tt := range tests { 341 got := commonPrefixLen(tt.a, tt.b) 342 if got != tt.want { 343 t.Errorf("%d. commonPrefixLen(%s, %s) = %d; want %d", i, tt.a, tt.b, got, tt.want) 344 } 345 } 346 }