k8s.io/kubernetes@v1.29.3/pkg/proxy/util/utils_test.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package util 18 19 import ( 20 "net" 21 "reflect" 22 "testing" 23 24 v1 "k8s.io/api/core/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/util/sets" 27 netutils "k8s.io/utils/net" 28 ) 29 30 func TestValidateWorks(t *testing.T) { 31 if isValidEndpoint("", 0) { 32 t.Errorf("Didn't fail for empty set") 33 } 34 if isValidEndpoint("foobar", 0) { 35 t.Errorf("Didn't fail with invalid port") 36 } 37 if isValidEndpoint("foobar", -1) { 38 t.Errorf("Didn't fail with a negative port") 39 } 40 if !isValidEndpoint("foobar", 8080) { 41 t.Errorf("Failed a valid config.") 42 } 43 } 44 45 func TestBuildPortsToEndpointsMap(t *testing.T) { 46 endpoints := &v1.Endpoints{ 47 ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "testnamespace"}, 48 Subsets: []v1.EndpointSubset{ 49 { 50 Addresses: []v1.EndpointAddress{ 51 {IP: "10.0.0.1"}, 52 {IP: "10.0.0.2"}, 53 }, 54 Ports: []v1.EndpointPort{ 55 {Name: "http", Port: 80}, 56 {Name: "https", Port: 443}, 57 }, 58 }, 59 { 60 Addresses: []v1.EndpointAddress{ 61 {IP: "10.0.0.1"}, 62 {IP: "10.0.0.3"}, 63 }, 64 Ports: []v1.EndpointPort{ 65 {Name: "http", Port: 8080}, 66 {Name: "dns", Port: 53}, 67 }, 68 }, 69 { 70 Addresses: []v1.EndpointAddress{}, 71 Ports: []v1.EndpointPort{ 72 {Name: "http", Port: 8888}, 73 {Name: "ssh", Port: 22}, 74 }, 75 }, 76 { 77 Addresses: []v1.EndpointAddress{ 78 {IP: "10.0.0.1"}, 79 }, 80 Ports: []v1.EndpointPort{}, 81 }, 82 }, 83 } 84 expectedPortsToEndpoints := map[string][]string{ 85 "http": {"10.0.0.1:80", "10.0.0.2:80", "10.0.0.1:8080", "10.0.0.3:8080"}, 86 "https": {"10.0.0.1:443", "10.0.0.2:443"}, 87 "dns": {"10.0.0.1:53", "10.0.0.3:53"}, 88 } 89 90 portsToEndpoints := BuildPortsToEndpointsMap(endpoints) 91 if !reflect.DeepEqual(expectedPortsToEndpoints, portsToEndpoints) { 92 t.Errorf("expected ports to endpoints not seen") 93 } 94 } 95 96 func TestShouldSkipService(t *testing.T) { 97 testCases := []struct { 98 service *v1.Service 99 shouldSkip bool 100 }{ 101 { 102 // Cluster IP is None 103 service: &v1.Service{ 104 ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}, 105 Spec: v1.ServiceSpec{ 106 ClusterIP: v1.ClusterIPNone, 107 }, 108 }, 109 shouldSkip: true, 110 }, 111 { 112 // Cluster IP is empty 113 service: &v1.Service{ 114 ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}, 115 Spec: v1.ServiceSpec{ 116 ClusterIP: "", 117 }, 118 }, 119 shouldSkip: true, 120 }, 121 { 122 // ExternalName type service 123 service: &v1.Service{ 124 ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}, 125 Spec: v1.ServiceSpec{ 126 ClusterIP: "1.2.3.4", 127 Type: v1.ServiceTypeExternalName, 128 }, 129 }, 130 shouldSkip: true, 131 }, 132 { 133 // ClusterIP type service with ClusterIP set 134 service: &v1.Service{ 135 ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}, 136 Spec: v1.ServiceSpec{ 137 ClusterIP: "1.2.3.4", 138 Type: v1.ServiceTypeClusterIP, 139 }, 140 }, 141 shouldSkip: false, 142 }, 143 { 144 // NodePort type service with ClusterIP set 145 service: &v1.Service{ 146 ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}, 147 Spec: v1.ServiceSpec{ 148 ClusterIP: "1.2.3.4", 149 Type: v1.ServiceTypeNodePort, 150 }, 151 }, 152 shouldSkip: false, 153 }, 154 { 155 // LoadBalancer type service with ClusterIP set 156 service: &v1.Service{ 157 ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}, 158 Spec: v1.ServiceSpec{ 159 ClusterIP: "1.2.3.4", 160 Type: v1.ServiceTypeLoadBalancer, 161 }, 162 }, 163 shouldSkip: false, 164 }, 165 } 166 167 for i := range testCases { 168 skip := ShouldSkipService(testCases[i].service) 169 if skip != testCases[i].shouldSkip { 170 t.Errorf("case %d: expect %v, got %v", i, testCases[i].shouldSkip, skip) 171 } 172 } 173 } 174 175 func TestAppendPortIfNeeded(t *testing.T) { 176 testCases := []struct { 177 name string 178 addr string 179 port int32 180 expect string 181 }{ 182 { 183 name: "IPv4 all-zeros bind address has port", 184 addr: "0.0.0.0:12345", 185 port: 23456, 186 expect: "0.0.0.0:12345", 187 }, 188 { 189 name: "non-zeros IPv4 config", 190 addr: "9.8.7.6", 191 port: 12345, 192 expect: "9.8.7.6:12345", 193 }, 194 { 195 name: "IPv6 \"[::]\" bind address has port", 196 addr: "[::]:12345", 197 port: 23456, 198 expect: "[::]:12345", 199 }, 200 { 201 name: "IPv6 config", 202 addr: "fd00:1::5", 203 port: 23456, 204 expect: "[fd00:1::5]:23456", 205 }, 206 { 207 name: "Invalid IPv6 Config", 208 addr: "[fd00:1::5]", 209 port: 12345, 210 expect: "[fd00:1::5]", 211 }, 212 } 213 214 for i := range testCases { 215 got := AppendPortIfNeeded(testCases[i].addr, testCases[i].port) 216 if testCases[i].expect != got { 217 t.Errorf("case %s: expected %v, got %v", testCases[i].name, testCases[i].expect, got) 218 } 219 } 220 } 221 222 func TestShuffleStrings(t *testing.T) { 223 var src []string 224 dest := ShuffleStrings(src) 225 226 if dest != nil { 227 t.Errorf("ShuffleStrings for a nil slice got a non-nil slice") 228 } 229 230 src = []string{"a", "b", "c", "d", "e", "f"} 231 dest = ShuffleStrings(src) 232 233 if len(src) != len(dest) { 234 t.Errorf("Shuffled slice is wrong length, expected %v got %v", len(src), len(dest)) 235 } 236 237 m := make(map[string]bool, len(dest)) 238 for _, s := range dest { 239 m[s] = true 240 } 241 242 for _, k := range src { 243 if _, exists := m[k]; !exists { 244 t.Errorf("Element %v missing from shuffled slice", k) 245 } 246 } 247 } 248 249 func TestMapIPsByIPFamily(t *testing.T) { 250 testCases := []struct { 251 desc string 252 ipString []string 253 wantIPv6 bool 254 expectCorrect []string 255 expectIncorrect []string 256 }{ 257 { 258 desc: "empty input IPv4", 259 ipString: []string{}, 260 wantIPv6: false, 261 expectCorrect: nil, 262 expectIncorrect: nil, 263 }, 264 { 265 desc: "empty input IPv6", 266 ipString: []string{}, 267 wantIPv6: true, 268 expectCorrect: nil, 269 expectIncorrect: nil, 270 }, 271 { 272 desc: "want IPv4 and receive IPv6", 273 ipString: []string{"fd00:20::1"}, 274 wantIPv6: false, 275 expectCorrect: nil, 276 expectIncorrect: []string{"fd00:20::1"}, 277 }, 278 { 279 desc: "want IPv6 and receive IPv4", 280 ipString: []string{"192.168.200.2"}, 281 wantIPv6: true, 282 expectCorrect: nil, 283 expectIncorrect: []string{"192.168.200.2"}, 284 }, 285 { 286 desc: "want IPv6 and receive IPv4 and IPv6", 287 ipString: []string{"192.168.200.2", "192.1.34.23", "fd00:20::1", "2001:db9::3"}, 288 wantIPv6: true, 289 expectCorrect: []string{"fd00:20::1", "2001:db9::3"}, 290 expectIncorrect: []string{"192.168.200.2", "192.1.34.23"}, 291 }, 292 { 293 desc: "want IPv4 and receive IPv4 and IPv6", 294 ipString: []string{"192.168.200.2", "192.1.34.23", "fd00:20::1", "2001:db9::3"}, 295 wantIPv6: false, 296 expectCorrect: []string{"192.168.200.2", "192.1.34.23"}, 297 expectIncorrect: []string{"fd00:20::1", "2001:db9::3"}, 298 }, 299 { 300 desc: "want IPv4 and receive IPv4 only", 301 ipString: []string{"192.168.200.2", "192.1.34.23"}, 302 wantIPv6: false, 303 expectCorrect: []string{"192.168.200.2", "192.1.34.23"}, 304 expectIncorrect: nil, 305 }, 306 { 307 desc: "want IPv6 and receive IPv4 only", 308 ipString: []string{"192.168.200.2", "192.1.34.23"}, 309 wantIPv6: true, 310 expectCorrect: nil, 311 expectIncorrect: []string{"192.168.200.2", "192.1.34.23"}, 312 }, 313 { 314 desc: "want IPv4 and receive IPv6 only", 315 ipString: []string{"fd00:20::1", "2001:db9::3"}, 316 wantIPv6: false, 317 expectCorrect: nil, 318 expectIncorrect: []string{"fd00:20::1", "2001:db9::3"}, 319 }, 320 { 321 desc: "want IPv6 and receive IPv6 only", 322 ipString: []string{"fd00:20::1", "2001:db9::3"}, 323 wantIPv6: true, 324 expectCorrect: []string{"fd00:20::1", "2001:db9::3"}, 325 expectIncorrect: nil, 326 }, 327 } 328 329 for _, testcase := range testCases { 330 t.Run(testcase.desc, func(t *testing.T) { 331 ipFamily := v1.IPv4Protocol 332 otherIPFamily := v1.IPv6Protocol 333 334 if testcase.wantIPv6 { 335 ipFamily = v1.IPv6Protocol 336 otherIPFamily = v1.IPv4Protocol 337 } 338 339 ipMap := MapIPsByIPFamily(testcase.ipString) 340 341 if !reflect.DeepEqual(testcase.expectCorrect, ipMap[ipFamily]) { 342 t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectCorrect, ipMap[ipFamily]) 343 } 344 if !reflect.DeepEqual(testcase.expectIncorrect, ipMap[otherIPFamily]) { 345 t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectIncorrect, ipMap[otherIPFamily]) 346 } 347 }) 348 } 349 } 350 351 func TestMapCIDRsByIPFamily(t *testing.T) { 352 testCases := []struct { 353 desc string 354 ipString []string 355 wantIPv6 bool 356 expectCorrect []string 357 expectIncorrect []string 358 }{ 359 { 360 desc: "empty input IPv4", 361 ipString: []string{}, 362 wantIPv6: false, 363 expectCorrect: nil, 364 expectIncorrect: nil, 365 }, 366 { 367 desc: "empty input IPv6", 368 ipString: []string{}, 369 wantIPv6: true, 370 expectCorrect: nil, 371 expectIncorrect: nil, 372 }, 373 { 374 desc: "want IPv4 and receive IPv6", 375 ipString: []string{"fd00:20::1/64"}, 376 wantIPv6: false, 377 expectCorrect: nil, 378 expectIncorrect: []string{"fd00:20::1/64"}, 379 }, 380 { 381 desc: "want IPv6 and receive IPv4", 382 ipString: []string{"192.168.200.2/24"}, 383 wantIPv6: true, 384 expectCorrect: nil, 385 expectIncorrect: []string{"192.168.200.2/24"}, 386 }, 387 { 388 desc: "want IPv6 and receive IPv4 and IPv6", 389 ipString: []string{"192.168.200.2/24", "192.1.34.23/24", "fd00:20::1/64", "2001:db9::3/64"}, 390 wantIPv6: true, 391 expectCorrect: []string{"fd00:20::1/64", "2001:db9::3/64"}, 392 expectIncorrect: []string{"192.168.200.2/24", "192.1.34.23/24"}, 393 }, 394 { 395 desc: "want IPv4 and receive IPv4 and IPv6", 396 ipString: []string{"192.168.200.2/24", "192.1.34.23/24", "fd00:20::1/64", "2001:db9::3/64"}, 397 wantIPv6: false, 398 expectCorrect: []string{"192.168.200.2/24", "192.1.34.23/24"}, 399 expectIncorrect: []string{"fd00:20::1/64", "2001:db9::3/64"}, 400 }, 401 { 402 desc: "want IPv4 and receive IPv4 only", 403 ipString: []string{"192.168.200.2/24", "192.1.34.23/24"}, 404 wantIPv6: false, 405 expectCorrect: []string{"192.168.200.2/24", "192.1.34.23/24"}, 406 expectIncorrect: nil, 407 }, 408 { 409 desc: "want IPv6 and receive IPv4 only", 410 ipString: []string{"192.168.200.2/24", "192.1.34.23/24"}, 411 wantIPv6: true, 412 expectCorrect: nil, 413 expectIncorrect: []string{"192.168.200.2/24", "192.1.34.23/24"}, 414 }, 415 { 416 desc: "want IPv4 and receive IPv6 only", 417 ipString: []string{"fd00:20::1/64", "2001:db9::3/64"}, 418 wantIPv6: false, 419 expectCorrect: nil, 420 expectIncorrect: []string{"fd00:20::1/64", "2001:db9::3/64"}, 421 }, 422 { 423 desc: "want IPv6 and receive IPv6 only", 424 ipString: []string{"fd00:20::1/64", "2001:db9::3/64"}, 425 wantIPv6: true, 426 expectCorrect: []string{"fd00:20::1/64", "2001:db9::3/64"}, 427 expectIncorrect: nil, 428 }, 429 } 430 431 for _, testcase := range testCases { 432 t.Run(testcase.desc, func(t *testing.T) { 433 ipFamily := v1.IPv4Protocol 434 otherIPFamily := v1.IPv6Protocol 435 436 if testcase.wantIPv6 { 437 ipFamily = v1.IPv6Protocol 438 otherIPFamily = v1.IPv4Protocol 439 } 440 441 cidrMap := MapCIDRsByIPFamily(testcase.ipString) 442 443 if !reflect.DeepEqual(testcase.expectCorrect, cidrMap[ipFamily]) { 444 t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectCorrect, cidrMap[ipFamily]) 445 } 446 if !reflect.DeepEqual(testcase.expectIncorrect, cidrMap[otherIPFamily]) { 447 t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectIncorrect, cidrMap[otherIPFamily]) 448 } 449 }) 450 } 451 } 452 453 func TestGetClusterIPByFamily(t *testing.T) { 454 testCases := []struct { 455 name string 456 service v1.Service 457 requestFamily v1.IPFamily 458 expectedResult string 459 }{ 460 { 461 name: "old style service ipv4. want ipv4", 462 requestFamily: v1.IPv4Protocol, 463 expectedResult: "10.0.0.10", 464 service: v1.Service{ 465 Spec: v1.ServiceSpec{ 466 ClusterIP: "10.0.0.10", 467 }, 468 }, 469 }, 470 471 { 472 name: "old style service ipv4. want ipv6", 473 requestFamily: v1.IPv6Protocol, 474 expectedResult: "", 475 service: v1.Service{ 476 Spec: v1.ServiceSpec{ 477 ClusterIP: "10.0.0.10", 478 }, 479 }, 480 }, 481 482 { 483 name: "old style service ipv6. want ipv6", 484 requestFamily: v1.IPv6Protocol, 485 expectedResult: "2000::1", 486 service: v1.Service{ 487 Spec: v1.ServiceSpec{ 488 ClusterIP: "2000::1", 489 }, 490 }, 491 }, 492 493 { 494 name: "old style service ipv6. want ipv4", 495 requestFamily: v1.IPv4Protocol, 496 expectedResult: "", 497 service: v1.Service{ 498 Spec: v1.ServiceSpec{ 499 ClusterIP: "2000::1", 500 }, 501 }, 502 }, 503 504 { 505 name: "service single stack ipv4. want ipv4", 506 requestFamily: v1.IPv4Protocol, 507 expectedResult: "10.0.0.10", 508 service: v1.Service{ 509 Spec: v1.ServiceSpec{ 510 ClusterIPs: []string{"10.0.0.10"}, 511 IPFamilies: []v1.IPFamily{v1.IPv4Protocol}, 512 }, 513 }, 514 }, 515 516 { 517 name: "service single stack ipv4. want ipv6", 518 requestFamily: v1.IPv6Protocol, 519 expectedResult: "", 520 service: v1.Service{ 521 Spec: v1.ServiceSpec{ 522 ClusterIPs: []string{"10.0.0.10"}, 523 IPFamilies: []v1.IPFamily{v1.IPv4Protocol}, 524 }, 525 }, 526 }, 527 528 { 529 name: "service single stack ipv6. want ipv6", 530 requestFamily: v1.IPv6Protocol, 531 expectedResult: "2000::1", 532 service: v1.Service{ 533 Spec: v1.ServiceSpec{ 534 ClusterIPs: []string{"2000::1"}, 535 IPFamilies: []v1.IPFamily{v1.IPv6Protocol}, 536 }, 537 }, 538 }, 539 540 { 541 name: "service single stack ipv6. want ipv4", 542 requestFamily: v1.IPv4Protocol, 543 expectedResult: "", 544 service: v1.Service{ 545 Spec: v1.ServiceSpec{ 546 ClusterIPs: []string{"2000::1"}, 547 IPFamilies: []v1.IPFamily{v1.IPv6Protocol}, 548 }, 549 }, 550 }, 551 // dual stack 552 { 553 name: "service dual stack ipv4,6. want ipv4", 554 requestFamily: v1.IPv4Protocol, 555 expectedResult: "10.0.0.10", 556 service: v1.Service{ 557 Spec: v1.ServiceSpec{ 558 ClusterIPs: []string{"10.0.0.10", "2000::1"}, 559 IPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol}, 560 }, 561 }, 562 }, 563 564 { 565 name: "service dual stack ipv4,6. want ipv6", 566 requestFamily: v1.IPv6Protocol, 567 expectedResult: "2000::1", 568 service: v1.Service{ 569 Spec: v1.ServiceSpec{ 570 ClusterIPs: []string{"10.0.0.10", "2000::1"}, 571 IPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol}, 572 }, 573 }, 574 }, 575 576 { 577 name: "service dual stack ipv6,4. want ipv6", 578 requestFamily: v1.IPv6Protocol, 579 expectedResult: "2000::1", 580 service: v1.Service{ 581 Spec: v1.ServiceSpec{ 582 ClusterIPs: []string{"2000::1", "10.0.0.10"}, 583 IPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol}, 584 }, 585 }, 586 }, 587 588 { 589 name: "service dual stack ipv6,4. want ipv4", 590 requestFamily: v1.IPv4Protocol, 591 expectedResult: "10.0.0.10", 592 service: v1.Service{ 593 Spec: v1.ServiceSpec{ 594 ClusterIPs: []string{"2000::1", "10.0.0.10"}, 595 IPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol}, 596 }, 597 }, 598 }, 599 } 600 601 for _, testCase := range testCases { 602 t.Run(testCase.name, func(t *testing.T) { 603 ip := GetClusterIPByFamily(testCase.requestFamily, &testCase.service) 604 if ip != testCase.expectedResult { 605 t.Fatalf("expected ip:%v got %v", testCase.expectedResult, ip) 606 } 607 }) 608 } 609 } 610 611 type fakeClosable struct { 612 closed bool 613 } 614 615 func (c *fakeClosable) Close() error { 616 c.closed = true 617 return nil 618 } 619 620 func TestRevertPorts(t *testing.T) { 621 testCases := []struct { 622 replacementPorts []netutils.LocalPort 623 existingPorts []netutils.LocalPort 624 expectToBeClose []bool 625 }{ 626 { 627 replacementPorts: []netutils.LocalPort{ 628 {Port: 5001}, 629 {Port: 5002}, 630 {Port: 5003}, 631 }, 632 existingPorts: []netutils.LocalPort{}, 633 expectToBeClose: []bool{true, true, true}, 634 }, 635 { 636 replacementPorts: []netutils.LocalPort{}, 637 existingPorts: []netutils.LocalPort{ 638 {Port: 5001}, 639 {Port: 5002}, 640 {Port: 5003}, 641 }, 642 expectToBeClose: []bool{}, 643 }, 644 { 645 replacementPorts: []netutils.LocalPort{ 646 {Port: 5001}, 647 {Port: 5002}, 648 {Port: 5003}, 649 }, 650 existingPorts: []netutils.LocalPort{ 651 {Port: 5001}, 652 {Port: 5002}, 653 {Port: 5003}, 654 }, 655 expectToBeClose: []bool{false, false, false}, 656 }, 657 { 658 replacementPorts: []netutils.LocalPort{ 659 {Port: 5001}, 660 {Port: 5002}, 661 {Port: 5003}, 662 }, 663 existingPorts: []netutils.LocalPort{ 664 {Port: 5001}, 665 {Port: 5003}, 666 }, 667 expectToBeClose: []bool{false, true, false}, 668 }, 669 { 670 replacementPorts: []netutils.LocalPort{ 671 {Port: 5001}, 672 {Port: 5002}, 673 {Port: 5003}, 674 }, 675 existingPorts: []netutils.LocalPort{ 676 {Port: 5001}, 677 {Port: 5002}, 678 {Port: 5003}, 679 {Port: 5004}, 680 }, 681 expectToBeClose: []bool{false, false, false}, 682 }, 683 } 684 685 for i, tc := range testCases { 686 replacementPortsMap := make(map[netutils.LocalPort]netutils.Closeable) 687 for _, lp := range tc.replacementPorts { 688 replacementPortsMap[lp] = &fakeClosable{} 689 } 690 existingPortsMap := make(map[netutils.LocalPort]netutils.Closeable) 691 for _, lp := range tc.existingPorts { 692 existingPortsMap[lp] = &fakeClosable{} 693 } 694 RevertPorts(replacementPortsMap, existingPortsMap) 695 for j, expectation := range tc.expectToBeClose { 696 if replacementPortsMap[tc.replacementPorts[j]].(*fakeClosable).closed != expectation { 697 t.Errorf("Expect replacement localport %v to be %v in test case %v", tc.replacementPorts[j], expectation, i) 698 } 699 } 700 for _, lp := range tc.existingPorts { 701 if existingPortsMap[lp].(*fakeClosable).closed { 702 t.Errorf("Expect existing localport %v to be false in test case %v", lp, i) 703 } 704 } 705 } 706 } 707 708 func mustParseIPAddr(str string) net.Addr { 709 a, err := net.ResolveIPAddr("ip", str) 710 if err != nil { 711 panic("mustParseIPAddr") 712 } 713 return a 714 } 715 func mustParseIPNet(str string) net.Addr { 716 _, n, err := netutils.ParseCIDRSloppy(str) 717 if err != nil { 718 panic("mustParseIPNet") 719 } 720 return n 721 } 722 func mustParseUnix(str string) net.Addr { 723 n, err := net.ResolveUnixAddr("unix", str) 724 if err != nil { 725 panic("mustParseUnix") 726 } 727 return n 728 } 729 730 type cidrValidator struct { 731 cidr *net.IPNet 732 } 733 734 func (v *cidrValidator) isValid(ip net.IP) bool { 735 return v.cidr.Contains(ip) 736 } 737 func newCidrValidator(cidr string) func(ip net.IP) bool { 738 _, n, err := netutils.ParseCIDRSloppy(cidr) 739 if err != nil { 740 panic("mustParseIPNet") 741 } 742 obj := cidrValidator{n} 743 return obj.isValid 744 } 745 746 func TestAddressSet(t *testing.T) { 747 testCases := []struct { 748 name string 749 validator func(ip net.IP) bool 750 input []net.Addr 751 expected sets.Set[string] 752 }{ 753 { 754 "Empty", 755 func(ip net.IP) bool { return false }, 756 nil, 757 nil, 758 }, 759 { 760 "Reject IPAddr x 2", 761 func(ip net.IP) bool { return false }, 762 []net.Addr{ 763 mustParseIPAddr("8.8.8.8"), 764 mustParseIPAddr("1000::"), 765 }, 766 nil, 767 }, 768 { 769 "Accept IPAddr x 2", 770 func(ip net.IP) bool { return true }, 771 []net.Addr{ 772 mustParseIPAddr("8.8.8.8"), 773 mustParseIPAddr("1000::"), 774 }, 775 sets.New("8.8.8.8", "1000::"), 776 }, 777 { 778 "Accept IPNet x 2", 779 func(ip net.IP) bool { return true }, 780 []net.Addr{ 781 mustParseIPNet("8.8.8.8/32"), 782 mustParseIPNet("1000::/128"), 783 }, 784 sets.New("8.8.8.8", "1000::"), 785 }, 786 { 787 "Accept Unix x 2", 788 func(ip net.IP) bool { return true }, 789 []net.Addr{ 790 mustParseUnix("/tmp/sock1"), 791 mustParseUnix("/tmp/sock2"), 792 }, 793 nil, 794 }, 795 { 796 "Cidr IPv4", 797 newCidrValidator("192.168.1.0/24"), 798 []net.Addr{ 799 mustParseIPAddr("8.8.8.8"), 800 mustParseIPAddr("1000::"), 801 mustParseIPAddr("192.168.1.1"), 802 }, 803 sets.New("192.168.1.1"), 804 }, 805 { 806 "Cidr IPv6", 807 newCidrValidator("1000::/64"), 808 []net.Addr{ 809 mustParseIPAddr("8.8.8.8"), 810 mustParseIPAddr("1000::"), 811 mustParseIPAddr("192.168.1.1"), 812 }, 813 sets.New("1000::"), 814 }, 815 } 816 817 for _, tc := range testCases { 818 if !tc.expected.Equal(AddressSet(tc.validator, tc.input)) { 819 t.Errorf("%s", tc.name) 820 } 821 } 822 } 823 824 func TestIsZeroCIDR(t *testing.T) { 825 testCases := []struct { 826 name string 827 input string 828 expected bool 829 }{ 830 { 831 name: "invalide cidr", 832 input: "", 833 expected: false, 834 }, 835 { 836 name: "ipv4 cidr", 837 input: "172.10.0.0/16", 838 expected: false, 839 }, 840 { 841 name: "ipv4 zero cidr", 842 input: IPv4ZeroCIDR, 843 expected: true, 844 }, 845 { 846 name: "ipv6 cidr", 847 input: "::/128", 848 expected: false, 849 }, 850 { 851 name: "ipv6 zero cidr", 852 input: IPv6ZeroCIDR, 853 expected: true, 854 }, 855 } 856 for _, tc := range testCases { 857 t.Run(tc.name, func(t *testing.T) { 858 if got := IsZeroCIDR(tc.input); tc.expected != got { 859 t.Errorf("IsZeroCIDR() = %t, want %t", got, tc.expected) 860 } 861 }) 862 } 863 }