randaddr_test.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. package main
  2. import (
  3. "bytes"
  4. "net"
  5. "testing"
  6. )
  7. func mustParseCIDR(s string) *net.IPNet {
  8. _, ipnet, err := net.ParseCIDR(s)
  9. if err != nil {
  10. panic(err)
  11. }
  12. return ipnet
  13. }
  14. func TestRandAddr(t *testing.T) {
  15. outer:
  16. for _, ipnet := range []*net.IPNet{
  17. mustParseCIDR("127.0.0.1/0"),
  18. mustParseCIDR("127.0.0.1/24"),
  19. mustParseCIDR("127.0.0.55/32"),
  20. mustParseCIDR("2001:db8::1234/0"),
  21. mustParseCIDR("2001:db8::1234/32"),
  22. mustParseCIDR("2001:db8::1234/128"),
  23. // Non-canonical masks (that don't consist of 1s followed by 0s)
  24. // work too, why not.
  25. &net.IPNet{
  26. IP: net.IP{1, 2, 3, 4},
  27. Mask: net.IPMask{0x00, 0x07, 0xff, 0xff},
  28. },
  29. } {
  30. for i := 0; i < 100; i++ {
  31. ip, err := randIPAddr(ipnet)
  32. if err != nil {
  33. t.Errorf("%v returned error %v", ipnet, err)
  34. continue outer
  35. }
  36. if !ipnet.Contains(ip) {
  37. t.Errorf("%v does not contain %v", ipnet, ip)
  38. continue outer
  39. }
  40. }
  41. }
  42. }
  43. func TestRandAddrUnequalLengths(t *testing.T) {
  44. for _, ipnet := range []*net.IPNet{
  45. &net.IPNet{
  46. IP: net.IP{1, 2, 3, 4},
  47. Mask: net.CIDRMask(32, 128),
  48. },
  49. &net.IPNet{
  50. IP: net.IP{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
  51. Mask: net.CIDRMask(24, 32),
  52. },
  53. &net.IPNet{
  54. IP: net.IP{1, 2, 3, 4},
  55. Mask: net.IPMask{},
  56. },
  57. &net.IPNet{
  58. IP: net.IP{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
  59. Mask: net.IPMask{},
  60. },
  61. } {
  62. _, err := randIPAddr(ipnet)
  63. if err == nil {
  64. t.Errorf("%v did not result in error, but should have", ipnet)
  65. }
  66. }
  67. }
  68. func BenchmarkRandAddr(b *testing.B) {
  69. for _, test := range []struct {
  70. label string
  71. ipnet net.IPNet
  72. }{
  73. {"IPv4/32", net.IPNet{IP: net.IP{127, 0, 0, 1}, Mask: net.CIDRMask(32, 32)}},
  74. {"IPv4/24", net.IPNet{IP: net.IP{127, 0, 0, 1}, Mask: net.CIDRMask(32, 32)}},
  75. {"IPv6/64", net.IPNet{
  76. IP: net.IP{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x34},
  77. Mask: net.CIDRMask(64, 128),
  78. }},
  79. {"IPv6/128", net.IPNet{
  80. IP: net.IP{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x34},
  81. Mask: net.CIDRMask(128, 128),
  82. }},
  83. } {
  84. b.Run(test.label, func(b *testing.B) {
  85. for i := 0; i < b.N; i++ {
  86. _, err := randIPAddr(&test.ipnet)
  87. if err != nil {
  88. b.Fatal(err)
  89. }
  90. }
  91. })
  92. }
  93. }
  94. func ipNetEqual(a, b *net.IPNet) bool {
  95. if !a.IP.Equal(b.IP) {
  96. return false
  97. }
  98. // Comparing masks for equality is a little tricky because they may be
  99. // different lengths. For masks in canonical form (those for which
  100. // Size() returns other than (0, 0)), we consider two masks equal if the
  101. // numbers of bits *not* covered by the prefix are equal; e.g.
  102. // (120, 128) is equal to (24, 32), because they both have 8 bits not in
  103. // the prefix. If either mask is not in canonical form, we require them
  104. // to be equal as byte arrays (which includes length).
  105. aOnes, aBits := a.Mask.Size()
  106. bOnes, bBits := b.Mask.Size()
  107. if aBits == 0 || bBits == 0 {
  108. return bytes.Equal(a.Mask, b.Mask)
  109. } else {
  110. return aBits-aOnes == bBits-bOnes
  111. }
  112. }
  113. func TestParseIPCIDR(t *testing.T) {
  114. // Well-formed inputs.
  115. for _, test := range []struct {
  116. input string
  117. expected *net.IPNet
  118. }{
  119. {"127.0.0.123", mustParseCIDR("127.0.0.123/32")},
  120. {"127.0.0.123/0", mustParseCIDR("127.0.0.123/0")},
  121. {"127.0.0.123/24", mustParseCIDR("127.0.0.123/24")},
  122. {"127.0.0.123/32", mustParseCIDR("127.0.0.123/32")},
  123. {"2001:db8::1234", mustParseCIDR("2001:db8::1234/128")},
  124. {"2001:db8::1234/0", mustParseCIDR("2001:db8::1234/0")},
  125. {"2001:db8::1234/32", mustParseCIDR("2001:db8::1234/32")},
  126. {"2001:db8::1234/128", mustParseCIDR("2001:db8::1234/128")},
  127. } {
  128. ipnet, err := parseIPCIDR(test.input)
  129. if err != nil {
  130. t.Errorf("%q returned error %v", test.input, err)
  131. continue
  132. }
  133. if !ipNetEqual(ipnet, test.expected) {
  134. t.Errorf("%q → %v, expected %v", test.input, ipnet, test.expected)
  135. }
  136. }
  137. // Bad inputs.
  138. for _, input := range []string{
  139. "",
  140. "1.2.3",
  141. "1.2.3/16",
  142. "2001:db8:1234",
  143. "2001:db8:1234/64",
  144. "localhost",
  145. } {
  146. _, err := parseIPCIDR(input)
  147. if err == nil {
  148. t.Errorf("%q did not result in error, but should have", input)
  149. }
  150. }
  151. }