1/* 2Copyright 2018 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package net 18 19import ( 20 "net" 21 "testing" 22) 23 24func TestParseCIDRs(t *testing.T) { 25 testCases := []struct { 26 cidrs []string 27 errString string 28 errorExpected bool 29 }{ 30 { 31 cidrs: []string{}, 32 errString: "should not return an error for an empty slice", 33 errorExpected: false, 34 }, 35 { 36 cidrs: []string{"10.0.0.0/8", "not-a-valid-cidr", "2000::/10"}, 37 errString: "should return error for bad cidr", 38 errorExpected: true, 39 }, 40 { 41 cidrs: []string{"10.0.0.0/8", "2000::/10"}, 42 errString: "should not return error for good cidrs", 43 errorExpected: false, 44 }, 45 } 46 47 for _, tc := range testCases { 48 cidrs, err := ParseCIDRs(tc.cidrs) 49 if tc.errorExpected { 50 if err == nil { 51 t.Errorf("%v", tc.errString) 52 } 53 continue 54 } 55 if err != nil { 56 t.Errorf("%v error:%v", tc.errString, err) 57 } 58 59 // validate lengths 60 if len(cidrs) != len(tc.cidrs) { 61 t.Errorf("cidrs should be of the same lengths %v != %v", len(cidrs), len(tc.cidrs)) 62 } 63 64 } 65} 66func TestDualStackIPs(t *testing.T) { 67 testCases := []struct { 68 ips []string 69 errMessage string 70 expectedResult bool 71 expectError bool 72 }{ 73 { 74 ips: []string{"1.1.1.1"}, 75 errMessage: "should fail because length is not at least 2", 76 expectedResult: false, 77 expectError: false, 78 }, 79 { 80 ips: []string{}, 81 errMessage: "should fail because length is not at least 2", 82 expectedResult: false, 83 expectError: false, 84 }, 85 { 86 ips: []string{"1.1.1.1", "2.2.2.2", "3.3.3.3"}, 87 errMessage: "should fail because all are v4", 88 expectedResult: false, 89 expectError: false, 90 }, 91 { 92 ips: []string{"fd92:20ba:ca:34f7:ffff:ffff:ffff:ffff", "fd92:20ba:ca:34f7:ffff:ffff:ffff:fff0", "fd92:20ba:ca:34f7:ffff:ffff:ffff:fff1"}, 93 errMessage: "should fail because all are v6", 94 expectedResult: false, 95 expectError: false, 96 }, 97 { 98 ips: []string{"1.1.1.1", "not-a-valid-ip"}, 99 errMessage: "should fail because 2nd ip is invalid", 100 expectedResult: false, 101 expectError: true, 102 }, 103 { 104 ips: []string{"not-a-valid-ip", "fd92:20ba:ca:34f7:ffff:ffff:ffff:ffff"}, 105 errMessage: "should fail because 1st ip is invalid", 106 expectedResult: false, 107 expectError: true, 108 }, 109 { 110 ips: []string{"1.1.1.1", "fd92:20ba:ca:34f7:ffff:ffff:ffff:ffff"}, 111 errMessage: "expected success, but found failure", 112 expectedResult: true, 113 expectError: false, 114 }, 115 { 116 ips: []string{"fd92:20ba:ca:34f7:ffff:ffff:ffff:ffff", "1.1.1.1", "fd92:20ba:ca:34f7:ffff:ffff:ffff:fff0"}, 117 errMessage: "expected success, but found failure", 118 expectedResult: true, 119 expectError: false, 120 }, 121 { 122 ips: []string{"1.1.1.1", "fd92:20ba:ca:34f7:ffff:ffff:ffff:ffff", "10.0.0.0"}, 123 errMessage: "expected success, but found failure", 124 expectedResult: true, 125 expectError: false, 126 }, 127 { 128 ips: []string{"fd92:20ba:ca:34f7:ffff:ffff:ffff:ffff", "1.1.1.1"}, 129 errMessage: "expected success, but found failure", 130 expectedResult: true, 131 expectError: false, 132 }, 133 } 134 // for each test case, test the regular func and the string func 135 for _, tc := range testCases { 136 dualStack, err := IsDualStackIPStrings(tc.ips) 137 if err == nil && tc.expectError { 138 t.Errorf("%s", tc.errMessage) 139 continue 140 } 141 if err != nil && !tc.expectError { 142 t.Errorf("failed to run test case for %v, error: %v", tc.ips, err) 143 continue 144 } 145 if dualStack != tc.expectedResult { 146 t.Errorf("%v for %v", tc.errMessage, tc.ips) 147 } 148 } 149 150 for _, tc := range testCases { 151 ips := make([]net.IP, 0, len(tc.ips)) 152 for _, ip := range tc.ips { 153 parsedIP := net.ParseIP(ip) 154 ips = append(ips, parsedIP) 155 } 156 dualStack, err := IsDualStackIPs(ips) 157 if err == nil && tc.expectError { 158 t.Errorf("%s", tc.errMessage) 159 continue 160 } 161 if err != nil && !tc.expectError { 162 t.Errorf("failed to run test case for %v, error: %v", tc.ips, err) 163 continue 164 } 165 if dualStack != tc.expectedResult { 166 t.Errorf("%v for %v", tc.errMessage, tc.ips) 167 } 168 } 169} 170 171func TestDualStackCIDRs(t *testing.T) { 172 testCases := []struct { 173 cidrs []string 174 errMessage string 175 expectedResult bool 176 expectError bool 177 }{ 178 { 179 cidrs: []string{"10.10.10.10/8"}, 180 errMessage: "should fail because length is not at least 2", 181 expectedResult: false, 182 expectError: false, 183 }, 184 { 185 cidrs: []string{}, 186 errMessage: "should fail because length is not at least 2", 187 expectedResult: false, 188 expectError: false, 189 }, 190 { 191 cidrs: []string{"10.10.10.10/8", "20.20.20.20/8", "30.30.30.30/8"}, 192 errMessage: "should fail because all cidrs are v4", 193 expectedResult: false, 194 expectError: false, 195 }, 196 { 197 cidrs: []string{"2000::/10", "3000::/10"}, 198 errMessage: "should fail because all cidrs are v6", 199 expectedResult: false, 200 expectError: false, 201 }, 202 { 203 cidrs: []string{"10.10.10.10/8", "not-a-valid-cidr"}, 204 errMessage: "should fail because 2nd cidr is invalid", 205 expectedResult: false, 206 expectError: true, 207 }, 208 { 209 cidrs: []string{"not-a-valid-ip", "2000::/10"}, 210 errMessage: "should fail because 1st cidr is invalid", 211 expectedResult: false, 212 expectError: true, 213 }, 214 { 215 cidrs: []string{"10.10.10.10/8", "2000::/10"}, 216 errMessage: "expected success, but found failure", 217 expectedResult: true, 218 expectError: false, 219 }, 220 { 221 cidrs: []string{"2000::/10", "10.10.10.10/8"}, 222 errMessage: "expected success, but found failure", 223 expectedResult: true, 224 expectError: false, 225 }, 226 { 227 cidrs: []string{"2000::/10", "10.10.10.10/8", "3000::/10"}, 228 errMessage: "expected success, but found failure", 229 expectedResult: true, 230 expectError: false, 231 }, 232 } 233 234 // for each test case, test the regular func and the string func 235 for _, tc := range testCases { 236 dualStack, err := IsDualStackCIDRStrings(tc.cidrs) 237 if err == nil && tc.expectError { 238 t.Errorf("%s", tc.errMessage) 239 continue 240 } 241 if err != nil && !tc.expectError { 242 t.Errorf("failed to run test case for %v, error: %v", tc.cidrs, err) 243 continue 244 } 245 if dualStack != tc.expectedResult { 246 t.Errorf("%v for %v", tc.errMessage, tc.cidrs) 247 } 248 } 249 250 for _, tc := range testCases { 251 cidrs := make([]*net.IPNet, 0, len(tc.cidrs)) 252 for _, cidr := range tc.cidrs { 253 _, parsedCIDR, _ := net.ParseCIDR(cidr) 254 cidrs = append(cidrs, parsedCIDR) 255 } 256 257 dualStack, err := IsDualStackCIDRs(cidrs) 258 if err == nil && tc.expectError { 259 t.Errorf("%s", tc.errMessage) 260 continue 261 } 262 if err != nil && !tc.expectError { 263 t.Errorf("failed to run test case for %v, error: %v", tc.cidrs, err) 264 continue 265 } 266 if dualStack != tc.expectedResult { 267 t.Errorf("%v for %v", tc.errMessage, tc.cidrs) 268 } 269 } 270} 271 272func TestIsIPv6String(t *testing.T) { 273 testCases := []struct { 274 ip string 275 expectIPv6 bool 276 }{ 277 { 278 ip: "127.0.0.1", 279 expectIPv6: false, 280 }, 281 { 282 ip: "192.168.0.0", 283 expectIPv6: false, 284 }, 285 { 286 ip: "1.2.3.4", 287 expectIPv6: false, 288 }, 289 { 290 ip: "bad ip", 291 expectIPv6: false, 292 }, 293 { 294 ip: "::1", 295 expectIPv6: true, 296 }, 297 { 298 ip: "fd00::600d:f00d", 299 expectIPv6: true, 300 }, 301 { 302 ip: "2001:db8::5", 303 expectIPv6: true, 304 }, 305 } 306 for i := range testCases { 307 isIPv6 := IsIPv6String(testCases[i].ip) 308 if isIPv6 != testCases[i].expectIPv6 { 309 t.Errorf("[%d] Expect ipv6 %v, got %v", i+1, testCases[i].expectIPv6, isIPv6) 310 } 311 } 312} 313 314func TestIsIPv6(t *testing.T) { 315 testCases := []struct { 316 ip net.IP 317 expectIPv6 bool 318 }{ 319 { 320 ip: net.IPv4zero, 321 expectIPv6: false, 322 }, 323 { 324 ip: net.IPv4bcast, 325 expectIPv6: false, 326 }, 327 { 328 ip: net.ParseIP("127.0.0.1"), 329 expectIPv6: false, 330 }, 331 { 332 ip: net.ParseIP("10.20.40.40"), 333 expectIPv6: false, 334 }, 335 { 336 ip: net.ParseIP("172.17.3.0"), 337 expectIPv6: false, 338 }, 339 { 340 ip: nil, 341 expectIPv6: false, 342 }, 343 { 344 ip: net.IPv6loopback, 345 expectIPv6: true, 346 }, 347 { 348 ip: net.IPv6zero, 349 expectIPv6: true, 350 }, 351 { 352 ip: net.ParseIP("fd00::600d:f00d"), 353 expectIPv6: true, 354 }, 355 { 356 ip: net.ParseIP("2001:db8::5"), 357 expectIPv6: true, 358 }, 359 } 360 for i := range testCases { 361 isIPv6 := IsIPv6(testCases[i].ip) 362 if isIPv6 != testCases[i].expectIPv6 { 363 t.Errorf("[%d] Expect ipv6 %v, got %v", i+1, testCases[i].expectIPv6, isIPv6) 364 } 365 } 366} 367 368func TestIsIPv6CIDRString(t *testing.T) { 369 testCases := []struct { 370 desc string 371 cidr string 372 expectResult bool 373 }{ 374 { 375 desc: "ipv4 CIDR 1", 376 cidr: "10.0.0.0/8", 377 expectResult: false, 378 }, 379 { 380 desc: "ipv4 CIDR 2", 381 cidr: "192.168.0.0/16", 382 expectResult: false, 383 }, 384 { 385 desc: "ipv6 CIDR 1", 386 cidr: "::/1", 387 expectResult: true, 388 }, 389 { 390 desc: "ipv6 CIDR 2", 391 cidr: "2000::/10", 392 expectResult: true, 393 }, 394 { 395 desc: "ipv6 CIDR 3", 396 cidr: "2001:db8::/32", 397 expectResult: true, 398 }, 399 } 400 401 for _, tc := range testCases { 402 res := IsIPv6CIDRString(tc.cidr) 403 if res != tc.expectResult { 404 t.Errorf("%v: want IsIPv6CIDRString=%v, got %v", tc.desc, tc.expectResult, res) 405 } 406 } 407} 408 409func TestIsIPv6CIDR(t *testing.T) { 410 testCases := []struct { 411 desc string 412 cidr string 413 expectResult bool 414 }{ 415 { 416 desc: "ipv4 CIDR 1", 417 cidr: "10.0.0.0/8", 418 expectResult: false, 419 }, 420 { 421 desc: "ipv4 CIDR 2", 422 cidr: "192.168.0.0/16", 423 expectResult: false, 424 }, 425 { 426 desc: "ipv6 CIDR 1", 427 cidr: "::/1", 428 expectResult: true, 429 }, 430 { 431 desc: "ipv6 CIDR 2", 432 cidr: "2000::/10", 433 expectResult: true, 434 }, 435 { 436 desc: "ipv6 CIDR 3", 437 cidr: "2001:db8::/32", 438 expectResult: true, 439 }, 440 } 441 442 for _, tc := range testCases { 443 _, cidr, _ := net.ParseCIDR(tc.cidr) 444 res := IsIPv6CIDR(cidr) 445 if res != tc.expectResult { 446 t.Errorf("%v: want IsIPv6CIDR=%v, got %v", tc.desc, tc.expectResult, res) 447 } 448 } 449} 450 451func TestIsIPv4String(t *testing.T) { 452 testCases := []struct { 453 ip string 454 expectIPv4 bool 455 }{ 456 { 457 ip: "127.0.0.1", 458 expectIPv4: true, 459 }, 460 { 461 ip: "192.168.0.0", 462 expectIPv4: true, 463 }, 464 { 465 ip: "1.2.3.4", 466 expectIPv4: true, 467 }, 468 { 469 ip: "bad ip", 470 expectIPv4: false, 471 }, 472 { 473 ip: "::1", 474 expectIPv4: false, 475 }, 476 { 477 ip: "fd00::600d:f00d", 478 expectIPv4: false, 479 }, 480 { 481 ip: "2001:db8::5", 482 expectIPv4: false, 483 }, 484 } 485 for i := range testCases { 486 isIPv4 := IsIPv4String(testCases[i].ip) 487 if isIPv4 != testCases[i].expectIPv4 { 488 t.Errorf("[%d] Expect ipv4 %v, got %v", i+1, testCases[i].expectIPv4, isIPv4) 489 } 490 } 491} 492 493func TestIsIPv4(t *testing.T) { 494 testCases := []struct { 495 ip net.IP 496 expectIPv4 bool 497 }{ 498 { 499 ip: net.IPv4zero, 500 expectIPv4: true, 501 }, 502 { 503 ip: net.IPv4bcast, 504 expectIPv4: true, 505 }, 506 { 507 ip: net.ParseIP("127.0.0.1"), 508 expectIPv4: true, 509 }, 510 { 511 ip: net.ParseIP("10.20.40.40"), 512 expectIPv4: true, 513 }, 514 { 515 ip: net.ParseIP("172.17.3.0"), 516 expectIPv4: true, 517 }, 518 { 519 ip: nil, 520 expectIPv4: false, 521 }, 522 { 523 ip: net.IPv6loopback, 524 expectIPv4: false, 525 }, 526 { 527 ip: net.IPv6zero, 528 expectIPv4: false, 529 }, 530 { 531 ip: net.ParseIP("fd00::600d:f00d"), 532 expectIPv4: false, 533 }, 534 { 535 ip: net.ParseIP("2001:db8::5"), 536 expectIPv4: false, 537 }, 538 } 539 for i := range testCases { 540 isIPv4 := IsIPv4(testCases[i].ip) 541 if isIPv4 != testCases[i].expectIPv4 { 542 t.Errorf("[%d] Expect ipv4 %v, got %v", i+1, testCases[i].expectIPv4, isIPv4) 543 } 544 } 545} 546 547func TestIsIPv4CIDRString(t *testing.T) { 548 testCases := []struct { 549 desc string 550 cidr string 551 expectResult bool 552 }{ 553 { 554 desc: "ipv4 CIDR 1", 555 cidr: "10.0.0.0/8", 556 expectResult: true, 557 }, 558 { 559 desc: "ipv4 CIDR 2", 560 cidr: "192.168.0.0/16", 561 expectResult: true, 562 }, 563 { 564 desc: "ipv6 CIDR 1", 565 cidr: "::/1", 566 expectResult: false, 567 }, 568 { 569 desc: "ipv6 CIDR 2", 570 cidr: "2000::/10", 571 expectResult: false, 572 }, 573 { 574 desc: "ipv6 CIDR 3", 575 cidr: "2001:db8::/32", 576 expectResult: false, 577 }, 578 } 579 580 for _, tc := range testCases { 581 res := IsIPv4CIDRString(tc.cidr) 582 if res != tc.expectResult { 583 t.Errorf("%v: want IsIPv4CIDRString=%v, got %v", tc.desc, tc.expectResult, res) 584 } 585 } 586} 587 588func TestIsIPv4CIDR(t *testing.T) { 589 testCases := []struct { 590 desc string 591 cidr string 592 expectResult bool 593 }{ 594 { 595 desc: "ipv4 CIDR 1", 596 cidr: "10.0.0.0/8", 597 expectResult: true, 598 }, 599 { 600 desc: "ipv4 CIDR 2", 601 cidr: "192.168.0.0/16", 602 expectResult: true, 603 }, 604 { 605 desc: "ipv6 CIDR 1", 606 cidr: "::/1", 607 expectResult: false, 608 }, 609 { 610 desc: "ipv6 CIDR 2", 611 cidr: "2000::/10", 612 expectResult: false, 613 }, 614 { 615 desc: "ipv6 CIDR 3", 616 cidr: "2001:db8::/32", 617 expectResult: false, 618 }, 619 } 620 621 for _, tc := range testCases { 622 _, cidr, _ := net.ParseCIDR(tc.cidr) 623 res := IsIPv4CIDR(cidr) 624 if res != tc.expectResult { 625 t.Errorf("%v: want IsIPv4CIDR=%v, got %v", tc.desc, tc.expectResult, res) 626 } 627 } 628} 629 630func TestParsePort(t *testing.T) { 631 var tests = []struct { 632 name string 633 port string 634 allowZero bool 635 expectedPort int 636 expectedError bool 637 }{ 638 { 639 name: "valid port: 1", 640 port: "1", 641 expectedPort: 1, 642 }, 643 { 644 name: "valid port: 1234", 645 port: "1234", 646 expectedPort: 1234, 647 }, 648 { 649 name: "valid port: 65535", 650 port: "65535", 651 expectedPort: 65535, 652 }, 653 { 654 name: "invalid port: not a number", 655 port: "a", 656 expectedError: true, 657 allowZero: false, 658 }, 659 { 660 name: "invalid port: too small", 661 port: "0", 662 expectedError: true, 663 }, 664 { 665 name: "invalid port: negative", 666 port: "-10", 667 expectedError: true, 668 }, 669 { 670 name: "invalid port: too big", 671 port: "65536", 672 expectedError: true, 673 }, 674 { 675 name: "zero port: allowed", 676 port: "0", 677 allowZero: true, 678 }, 679 { 680 name: "zero port: not allowed", 681 port: "0", 682 expectedError: true, 683 }, 684 } 685 686 for _, rt := range tests { 687 t.Run(rt.name, func(t *testing.T) { 688 actualPort, actualError := ParsePort(rt.port, rt.allowZero) 689 690 if actualError != nil && !rt.expectedError { 691 t.Errorf("%s unexpected failure: %v", rt.name, actualError) 692 return 693 } 694 if actualError == nil && rt.expectedError { 695 t.Errorf("%s passed when expected to fail", rt.name) 696 return 697 } 698 if actualPort != rt.expectedPort { 699 t.Errorf("%s returned wrong port: got %d, expected %d", rt.name, actualPort, rt.expectedPort) 700 } 701 }) 702 } 703} 704 705func TestRangeSize(t *testing.T) { 706 testCases := []struct { 707 name string 708 cidr string 709 addrs int64 710 }{ 711 { 712 name: "supported IPv4 cidr", 713 cidr: "192.168.1.0/24", 714 addrs: 256, 715 }, 716 { 717 name: "unsupported IPv4 cidr", 718 cidr: "192.168.1.0/1", 719 addrs: 0, 720 }, 721 { 722 name: "unsupported IPv6 mask", 723 cidr: "2001:db8::/1", 724 addrs: 0, 725 }, 726 } 727 728 for _, tc := range testCases { 729 _, cidr, err := net.ParseCIDR(tc.cidr) 730 if err != nil { 731 t.Errorf("failed to parse cidr for test %s, unexpected error: '%s'", tc.name, err) 732 } 733 if size := RangeSize(cidr); size != tc.addrs { 734 t.Errorf("test %s failed. %s should have a range size of %d, got %d", 735 tc.name, tc.cidr, tc.addrs, size) 736 } 737 } 738} 739 740func TestGetIndexedIP(t *testing.T) { 741 testCases := []struct { 742 cidr string 743 index int 744 expectError bool 745 expectedIP string 746 }{ 747 { 748 cidr: "192.168.1.0/24", 749 index: 20, 750 expectError: false, 751 expectedIP: "192.168.1.20", 752 }, 753 { 754 cidr: "192.168.1.0/30", 755 index: 10, 756 expectError: true, 757 }, 758 { 759 cidr: "192.168.1.0/24", 760 index: 255, 761 expectError: false, 762 expectedIP: "192.168.1.255", 763 }, 764 { 765 cidr: "255.255.255.0/24", 766 index: 256, 767 expectError: true, 768 }, 769 { 770 cidr: "fd:11:b2:be::/120", 771 index: 20, 772 expectError: false, 773 expectedIP: "fd:11:b2:be::14", 774 }, 775 { 776 cidr: "fd:11:b2:be::/126", 777 index: 10, 778 expectError: true, 779 }, 780 { 781 cidr: "fd:11:b2:be::/120", 782 index: 255, 783 expectError: false, 784 expectedIP: "fd:11:b2:be::ff", 785 }, 786 { 787 cidr: "00:00:00:be::/120", 788 index: 255, 789 expectError: false, 790 expectedIP: "::be:0:0:0:ff", 791 }, 792 } 793 794 for _, tc := range testCases { 795 _, subnet, err := net.ParseCIDR(tc.cidr) 796 if err != nil { 797 t.Errorf("failed to parse cidr %s, unexpected error: '%s'", tc.cidr, err) 798 } 799 800 ip, err := GetIndexedIP(subnet, tc.index) 801 if err == nil && tc.expectError || err != nil && !tc.expectError { 802 t.Errorf("expectedError is %v and err is %s", tc.expectError, err) 803 continue 804 } 805 806 if err == nil { 807 ipString := ip.String() 808 if ipString != tc.expectedIP { 809 t.Errorf("expected %s but instead got %s", tc.expectedIP, ipString) 810 } 811 } 812 813 } 814} 815