k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/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 TestShouldSkipService(t *testing.T) { 46 testCases := []struct { 47 service *v1.Service 48 shouldSkip bool 49 }{ 50 { 51 // Cluster IP is None 52 service: &v1.Service{ 53 ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}, 54 Spec: v1.ServiceSpec{ 55 ClusterIP: v1.ClusterIPNone, 56 }, 57 }, 58 shouldSkip: true, 59 }, 60 { 61 // Cluster IP is empty 62 service: &v1.Service{ 63 ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}, 64 Spec: v1.ServiceSpec{ 65 ClusterIP: "", 66 }, 67 }, 68 shouldSkip: true, 69 }, 70 { 71 // ExternalName type service 72 service: &v1.Service{ 73 ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}, 74 Spec: v1.ServiceSpec{ 75 ClusterIP: "1.2.3.4", 76 Type: v1.ServiceTypeExternalName, 77 }, 78 }, 79 shouldSkip: true, 80 }, 81 { 82 // ClusterIP type service with ClusterIP set 83 service: &v1.Service{ 84 ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}, 85 Spec: v1.ServiceSpec{ 86 ClusterIP: "1.2.3.4", 87 Type: v1.ServiceTypeClusterIP, 88 }, 89 }, 90 shouldSkip: false, 91 }, 92 { 93 // NodePort type service with ClusterIP set 94 service: &v1.Service{ 95 ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}, 96 Spec: v1.ServiceSpec{ 97 ClusterIP: "1.2.3.4", 98 Type: v1.ServiceTypeNodePort, 99 }, 100 }, 101 shouldSkip: false, 102 }, 103 { 104 // LoadBalancer type service with ClusterIP set 105 service: &v1.Service{ 106 ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}, 107 Spec: v1.ServiceSpec{ 108 ClusterIP: "1.2.3.4", 109 Type: v1.ServiceTypeLoadBalancer, 110 }, 111 }, 112 shouldSkip: false, 113 }, 114 } 115 116 for i := range testCases { 117 skip := ShouldSkipService(testCases[i].service) 118 if skip != testCases[i].shouldSkip { 119 t.Errorf("case %d: expect %v, got %v", i, testCases[i].shouldSkip, skip) 120 } 121 } 122 } 123 124 func TestAppendPortIfNeeded(t *testing.T) { 125 testCases := []struct { 126 name string 127 addr string 128 port int32 129 expect string 130 }{ 131 { 132 name: "IPv4 all-zeros bind address has port", 133 addr: "0.0.0.0:12345", 134 port: 23456, 135 expect: "0.0.0.0:12345", 136 }, 137 { 138 name: "non-zeros IPv4 config", 139 addr: "9.8.7.6", 140 port: 12345, 141 expect: "9.8.7.6:12345", 142 }, 143 { 144 name: "IPv6 \"[::]\" bind address has port", 145 addr: "[::]:12345", 146 port: 23456, 147 expect: "[::]:12345", 148 }, 149 { 150 name: "IPv6 config", 151 addr: "fd00:1::5", 152 port: 23456, 153 expect: "[fd00:1::5]:23456", 154 }, 155 { 156 name: "Invalid IPv6 Config", 157 addr: "[fd00:1::5]", 158 port: 12345, 159 expect: "[fd00:1::5]", 160 }, 161 } 162 163 for i := range testCases { 164 got := AppendPortIfNeeded(testCases[i].addr, testCases[i].port) 165 if testCases[i].expect != got { 166 t.Errorf("case %s: expected %v, got %v", testCases[i].name, testCases[i].expect, got) 167 } 168 } 169 } 170 171 func TestMapIPsByIPFamily(t *testing.T) { 172 testCases := []struct { 173 desc string 174 ipString []string 175 wantIPv6 bool 176 expectCorrect []string 177 expectIncorrect []string 178 }{ 179 { 180 desc: "empty input IPv4", 181 ipString: []string{}, 182 wantIPv6: false, 183 expectCorrect: nil, 184 expectIncorrect: nil, 185 }, 186 { 187 desc: "empty input IPv6", 188 ipString: []string{}, 189 wantIPv6: true, 190 expectCorrect: nil, 191 expectIncorrect: nil, 192 }, 193 { 194 desc: "want IPv4 and receive IPv6", 195 ipString: []string{"fd00:20::1"}, 196 wantIPv6: false, 197 expectCorrect: nil, 198 expectIncorrect: []string{"fd00:20::1"}, 199 }, 200 { 201 desc: "want IPv6 and receive IPv4", 202 ipString: []string{"192.168.200.2"}, 203 wantIPv6: true, 204 expectCorrect: nil, 205 expectIncorrect: []string{"192.168.200.2"}, 206 }, 207 { 208 desc: "want IPv6 and receive IPv4 and IPv6", 209 ipString: []string{"192.168.200.2", "192.1.34.23", "fd00:20::1", "2001:db9::3"}, 210 wantIPv6: true, 211 expectCorrect: []string{"fd00:20::1", "2001:db9::3"}, 212 expectIncorrect: []string{"192.168.200.2", "192.1.34.23"}, 213 }, 214 { 215 desc: "want IPv4 and receive IPv4 and IPv6", 216 ipString: []string{"192.168.200.2", "192.1.34.23", "fd00:20::1", "2001:db9::3"}, 217 wantIPv6: false, 218 expectCorrect: []string{"192.168.200.2", "192.1.34.23"}, 219 expectIncorrect: []string{"fd00:20::1", "2001:db9::3"}, 220 }, 221 { 222 desc: "want IPv4 and receive IPv4 only", 223 ipString: []string{"192.168.200.2", "192.1.34.23"}, 224 wantIPv6: false, 225 expectCorrect: []string{"192.168.200.2", "192.1.34.23"}, 226 expectIncorrect: nil, 227 }, 228 { 229 desc: "want IPv6 and receive IPv4 only", 230 ipString: []string{"192.168.200.2", "192.1.34.23"}, 231 wantIPv6: true, 232 expectCorrect: nil, 233 expectIncorrect: []string{"192.168.200.2", "192.1.34.23"}, 234 }, 235 { 236 desc: "want IPv4 and receive IPv6 only", 237 ipString: []string{"fd00:20::1", "2001:db9::3"}, 238 wantIPv6: false, 239 expectCorrect: nil, 240 expectIncorrect: []string{"fd00:20::1", "2001:db9::3"}, 241 }, 242 { 243 desc: "want IPv6 and receive IPv6 only", 244 ipString: []string{"fd00:20::1", "2001:db9::3"}, 245 wantIPv6: true, 246 expectCorrect: []string{"fd00:20::1", "2001:db9::3"}, 247 expectIncorrect: nil, 248 }, 249 } 250 251 for _, testcase := range testCases { 252 t.Run(testcase.desc, func(t *testing.T) { 253 ipFamily := v1.IPv4Protocol 254 otherIPFamily := v1.IPv6Protocol 255 256 if testcase.wantIPv6 { 257 ipFamily = v1.IPv6Protocol 258 otherIPFamily = v1.IPv4Protocol 259 } 260 261 ipMap := MapIPsByIPFamily(testcase.ipString) 262 263 var ipStr []string 264 for _, ip := range ipMap[ipFamily] { 265 ipStr = append(ipStr, ip.String()) 266 } 267 if !reflect.DeepEqual(testcase.expectCorrect, ipStr) { 268 t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectCorrect, ipMap[ipFamily]) 269 } 270 ipStr = nil 271 for _, ip := range ipMap[otherIPFamily] { 272 ipStr = append(ipStr, ip.String()) 273 } 274 if !reflect.DeepEqual(testcase.expectIncorrect, ipStr) { 275 t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectIncorrect, ipMap[otherIPFamily]) 276 } 277 }) 278 } 279 } 280 281 func TestMapCIDRsByIPFamily(t *testing.T) { 282 testCases := []struct { 283 desc string 284 ipString []string 285 wantIPv6 bool 286 expectCorrect []string 287 expectIncorrect []string 288 }{ 289 { 290 desc: "empty input IPv4", 291 ipString: []string{}, 292 wantIPv6: false, 293 expectCorrect: nil, 294 expectIncorrect: nil, 295 }, 296 { 297 desc: "empty input IPv6", 298 ipString: []string{}, 299 wantIPv6: true, 300 expectCorrect: nil, 301 expectIncorrect: nil, 302 }, 303 { 304 desc: "want IPv4 and receive IPv6", 305 ipString: []string{"fd00:20::/64"}, 306 wantIPv6: false, 307 expectCorrect: nil, 308 expectIncorrect: []string{"fd00:20::/64"}, 309 }, 310 { 311 desc: "want IPv6 and receive IPv4", 312 ipString: []string{"192.168.200.0/24"}, 313 wantIPv6: true, 314 expectCorrect: nil, 315 expectIncorrect: []string{"192.168.200.0/24"}, 316 }, 317 { 318 desc: "want IPv6 and receive IPv4 and IPv6", 319 ipString: []string{"192.168.200.0/24", "192.1.34.0/24", "fd00:20::/64", "2001:db9::/64"}, 320 wantIPv6: true, 321 expectCorrect: []string{"fd00:20::/64", "2001:db9::/64"}, 322 expectIncorrect: []string{"192.168.200.0/24", "192.1.34.0/24"}, 323 }, 324 { 325 desc: "want IPv4 and receive IPv4 and IPv6", 326 ipString: []string{"192.168.200.0/24", "192.1.34.0/24", "fd00:20::/64", "2001:db9::/64"}, 327 wantIPv6: false, 328 expectCorrect: []string{"192.168.200.0/24", "192.1.34.0/24"}, 329 expectIncorrect: []string{"fd00:20::/64", "2001:db9::/64"}, 330 }, 331 { 332 desc: "want IPv4 and receive IPv4 only", 333 ipString: []string{"192.168.200.0/24", "192.1.34.0/24"}, 334 wantIPv6: false, 335 expectCorrect: []string{"192.168.200.0/24", "192.1.34.0/24"}, 336 expectIncorrect: nil, 337 }, 338 { 339 desc: "want IPv6 and receive IPv4 only", 340 ipString: []string{"192.168.200.0/24", "192.1.34.0/24"}, 341 wantIPv6: true, 342 expectCorrect: nil, 343 expectIncorrect: []string{"192.168.200.0/24", "192.1.34.0/24"}, 344 }, 345 { 346 desc: "want IPv4 and receive IPv6 only", 347 ipString: []string{"fd00:20::/64", "2001:db9::/64"}, 348 wantIPv6: false, 349 expectCorrect: nil, 350 expectIncorrect: []string{"fd00:20::/64", "2001:db9::/64"}, 351 }, 352 { 353 desc: "want IPv6 and receive IPv6 only", 354 ipString: []string{"fd00:20::/64", "2001:db9::/64"}, 355 wantIPv6: true, 356 expectCorrect: []string{"fd00:20::/64", "2001:db9::/64"}, 357 expectIncorrect: nil, 358 }, 359 } 360 361 for _, testcase := range testCases { 362 t.Run(testcase.desc, func(t *testing.T) { 363 ipFamily := v1.IPv4Protocol 364 otherIPFamily := v1.IPv6Protocol 365 366 if testcase.wantIPv6 { 367 ipFamily = v1.IPv6Protocol 368 otherIPFamily = v1.IPv4Protocol 369 } 370 371 cidrMap := MapCIDRsByIPFamily(testcase.ipString) 372 373 var cidrStr []string 374 for _, cidr := range cidrMap[ipFamily] { 375 cidrStr = append(cidrStr, cidr.String()) 376 } 377 var cidrStrOther []string 378 for _, cidr := range cidrMap[otherIPFamily] { 379 cidrStrOther = append(cidrStrOther, cidr.String()) 380 } 381 382 if !reflect.DeepEqual(testcase.expectCorrect, cidrStr) { 383 t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectCorrect, cidrStr) 384 } 385 if !reflect.DeepEqual(testcase.expectIncorrect, cidrStrOther) { 386 t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectIncorrect, cidrStrOther) 387 } 388 }) 389 } 390 } 391 392 func TestGetClusterIPByFamily(t *testing.T) { 393 testCases := []struct { 394 name string 395 service v1.Service 396 requestFamily v1.IPFamily 397 expectedResult string 398 }{ 399 { 400 name: "old style service ipv4. want ipv4", 401 requestFamily: v1.IPv4Protocol, 402 expectedResult: "10.0.0.10", 403 service: v1.Service{ 404 Spec: v1.ServiceSpec{ 405 ClusterIP: "10.0.0.10", 406 }, 407 }, 408 }, 409 410 { 411 name: "old style service ipv4. want ipv6", 412 requestFamily: v1.IPv6Protocol, 413 expectedResult: "", 414 service: v1.Service{ 415 Spec: v1.ServiceSpec{ 416 ClusterIP: "10.0.0.10", 417 }, 418 }, 419 }, 420 421 { 422 name: "old style service ipv6. want ipv6", 423 requestFamily: v1.IPv6Protocol, 424 expectedResult: "2000::1", 425 service: v1.Service{ 426 Spec: v1.ServiceSpec{ 427 ClusterIP: "2000::1", 428 }, 429 }, 430 }, 431 432 { 433 name: "old style service ipv6. want ipv4", 434 requestFamily: v1.IPv4Protocol, 435 expectedResult: "", 436 service: v1.Service{ 437 Spec: v1.ServiceSpec{ 438 ClusterIP: "2000::1", 439 }, 440 }, 441 }, 442 443 { 444 name: "service single stack ipv4. want ipv4", 445 requestFamily: v1.IPv4Protocol, 446 expectedResult: "10.0.0.10", 447 service: v1.Service{ 448 Spec: v1.ServiceSpec{ 449 ClusterIPs: []string{"10.0.0.10"}, 450 IPFamilies: []v1.IPFamily{v1.IPv4Protocol}, 451 }, 452 }, 453 }, 454 455 { 456 name: "service single stack ipv4. want ipv6", 457 requestFamily: v1.IPv6Protocol, 458 expectedResult: "", 459 service: v1.Service{ 460 Spec: v1.ServiceSpec{ 461 ClusterIPs: []string{"10.0.0.10"}, 462 IPFamilies: []v1.IPFamily{v1.IPv4Protocol}, 463 }, 464 }, 465 }, 466 467 { 468 name: "service single stack ipv6. want ipv6", 469 requestFamily: v1.IPv6Protocol, 470 expectedResult: "2000::1", 471 service: v1.Service{ 472 Spec: v1.ServiceSpec{ 473 ClusterIPs: []string{"2000::1"}, 474 IPFamilies: []v1.IPFamily{v1.IPv6Protocol}, 475 }, 476 }, 477 }, 478 479 { 480 name: "service single stack ipv6. want ipv4", 481 requestFamily: v1.IPv4Protocol, 482 expectedResult: "", 483 service: v1.Service{ 484 Spec: v1.ServiceSpec{ 485 ClusterIPs: []string{"2000::1"}, 486 IPFamilies: []v1.IPFamily{v1.IPv6Protocol}, 487 }, 488 }, 489 }, 490 // dual stack 491 { 492 name: "service dual stack ipv4,6. want ipv4", 493 requestFamily: v1.IPv4Protocol, 494 expectedResult: "10.0.0.10", 495 service: v1.Service{ 496 Spec: v1.ServiceSpec{ 497 ClusterIPs: []string{"10.0.0.10", "2000::1"}, 498 IPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol}, 499 }, 500 }, 501 }, 502 503 { 504 name: "service dual stack ipv4,6. want ipv6", 505 requestFamily: v1.IPv6Protocol, 506 expectedResult: "2000::1", 507 service: v1.Service{ 508 Spec: v1.ServiceSpec{ 509 ClusterIPs: []string{"10.0.0.10", "2000::1"}, 510 IPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol}, 511 }, 512 }, 513 }, 514 515 { 516 name: "service dual stack ipv6,4. want ipv6", 517 requestFamily: v1.IPv6Protocol, 518 expectedResult: "2000::1", 519 service: v1.Service{ 520 Spec: v1.ServiceSpec{ 521 ClusterIPs: []string{"2000::1", "10.0.0.10"}, 522 IPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol}, 523 }, 524 }, 525 }, 526 527 { 528 name: "service dual stack ipv6,4. want ipv4", 529 requestFamily: v1.IPv4Protocol, 530 expectedResult: "10.0.0.10", 531 service: v1.Service{ 532 Spec: v1.ServiceSpec{ 533 ClusterIPs: []string{"2000::1", "10.0.0.10"}, 534 IPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol}, 535 }, 536 }, 537 }, 538 } 539 540 for _, testCase := range testCases { 541 t.Run(testCase.name, func(t *testing.T) { 542 ip := GetClusterIPByFamily(testCase.requestFamily, &testCase.service) 543 if ip != testCase.expectedResult { 544 t.Fatalf("expected ip:%v got %v", testCase.expectedResult, ip) 545 } 546 }) 547 } 548 } 549 550 func mustParseIPAddr(str string) net.Addr { 551 a, err := net.ResolveIPAddr("ip", str) 552 if err != nil { 553 panic("mustParseIPAddr") 554 } 555 return a 556 } 557 func mustParseIPNet(str string) net.Addr { 558 _, n, err := netutils.ParseCIDRSloppy(str) 559 if err != nil { 560 panic("mustParseIPNet") 561 } 562 return n 563 } 564 func mustParseUnix(str string) net.Addr { 565 n, err := net.ResolveUnixAddr("unix", str) 566 if err != nil { 567 panic("mustParseUnix") 568 } 569 return n 570 } 571 572 type cidrValidator struct { 573 cidr *net.IPNet 574 } 575 576 func (v *cidrValidator) isValid(ip net.IP) bool { 577 return v.cidr.Contains(ip) 578 } 579 func newCidrValidator(cidr string) func(ip net.IP) bool { 580 _, n, err := netutils.ParseCIDRSloppy(cidr) 581 if err != nil { 582 panic("mustParseIPNet") 583 } 584 obj := cidrValidator{n} 585 return obj.isValid 586 } 587 588 func TestAddressSet(t *testing.T) { 589 testCases := []struct { 590 name string 591 validator func(ip net.IP) bool 592 input []net.Addr 593 expected sets.Set[string] 594 }{ 595 { 596 "Empty", 597 func(ip net.IP) bool { return false }, 598 nil, 599 nil, 600 }, 601 { 602 "Reject IPAddr x 2", 603 func(ip net.IP) bool { return false }, 604 []net.Addr{ 605 mustParseIPAddr("8.8.8.8"), 606 mustParseIPAddr("1000::"), 607 }, 608 nil, 609 }, 610 { 611 "Accept IPAddr x 2", 612 func(ip net.IP) bool { return true }, 613 []net.Addr{ 614 mustParseIPAddr("8.8.8.8"), 615 mustParseIPAddr("1000::"), 616 }, 617 sets.New("8.8.8.8", "1000::"), 618 }, 619 { 620 "Accept IPNet x 2", 621 func(ip net.IP) bool { return true }, 622 []net.Addr{ 623 mustParseIPNet("8.8.8.8/32"), 624 mustParseIPNet("1000::/128"), 625 }, 626 sets.New("8.8.8.8", "1000::"), 627 }, 628 { 629 "Accept Unix x 2", 630 func(ip net.IP) bool { return true }, 631 []net.Addr{ 632 mustParseUnix("/tmp/sock1"), 633 mustParseUnix("/tmp/sock2"), 634 }, 635 nil, 636 }, 637 { 638 "Cidr IPv4", 639 newCidrValidator("192.168.1.0/24"), 640 []net.Addr{ 641 mustParseIPAddr("8.8.8.8"), 642 mustParseIPAddr("1000::"), 643 mustParseIPAddr("192.168.1.1"), 644 }, 645 sets.New("192.168.1.1"), 646 }, 647 { 648 "Cidr IPv6", 649 newCidrValidator("1000::/64"), 650 []net.Addr{ 651 mustParseIPAddr("8.8.8.8"), 652 mustParseIPAddr("1000::"), 653 mustParseIPAddr("192.168.1.1"), 654 }, 655 sets.New("1000::"), 656 }, 657 } 658 659 for _, tc := range testCases { 660 if !tc.expected.Equal(AddressSet(tc.validator, tc.input)) { 661 t.Errorf("%s", tc.name) 662 } 663 } 664 } 665 666 func TestIsZeroCIDR(t *testing.T) { 667 testCases := []struct { 668 name string 669 input string 670 expected bool 671 }{ 672 { 673 name: "invalide cidr", 674 input: "", 675 expected: false, 676 }, 677 { 678 name: "ipv4 cidr", 679 input: "172.10.0.0/16", 680 expected: false, 681 }, 682 { 683 name: "ipv4 zero cidr", 684 input: IPv4ZeroCIDR, 685 expected: true, 686 }, 687 { 688 name: "ipv6 cidr", 689 input: "::/128", 690 expected: false, 691 }, 692 { 693 name: "ipv6 zero cidr", 694 input: IPv6ZeroCIDR, 695 expected: true, 696 }, 697 } 698 for _, tc := range testCases { 699 t.Run(tc.name, func(t *testing.T) { 700 if got := IsZeroCIDR(tc.input); tc.expected != got { 701 t.Errorf("IsZeroCIDR() = %t, want %t", got, tc.expected) 702 } 703 }) 704 } 705 }