cidr.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // Package cidr is a collection of assorted utilities for computing
  2. // network and host addresses within network ranges.
  3. //
  4. // It expects a CIDR-type address structure where addresses are divided into
  5. // some number of prefix bits representing the network and then the remaining
  6. // suffix bits represent the host.
  7. //
  8. // For example, it can help to calculate addresses for sub-networks of a
  9. // parent network, or to calculate host addresses within a particular prefix.
  10. //
  11. // At present this package is prioritizing simplicity of implementation and
  12. // de-prioritizing speed and memory usage. Thus caution is advised before
  13. // using this package in performance-critical applications or hot codepaths.
  14. // Patches to improve the speed and memory usage may be accepted as long as
  15. // they do not result in a significant increase in code complexity.
  16. package cidr
  17. import (
  18. "fmt"
  19. "math/big"
  20. "net"
  21. )
  22. // Subnet takes a parent CIDR range and creates a subnet within it
  23. // with the given number of additional prefix bits and the given
  24. // network number.
  25. //
  26. // For example, 10.3.0.0/16, extended by 8 bits, with a network number
  27. // of 5, becomes 10.3.5.0/24 .
  28. func Subnet(base *net.IPNet, newBits int, num int) (*net.IPNet, error) {
  29. return SubnetBig(base, newBits, big.NewInt(int64(num)))
  30. }
  31. // SubnetBig takes a parent CIDR range and creates a subnet within it with the
  32. // given number of additional prefix bits and the given network number. It
  33. // differs from Subnet in that it takes a *big.Int for the num, instead of an int.
  34. //
  35. // For example, 10.3.0.0/16, extended by 8 bits, with a network number of 5,
  36. // becomes 10.3.5.0/24 .
  37. func SubnetBig(base *net.IPNet, newBits int, num *big.Int) (*net.IPNet, error) {
  38. ip := base.IP
  39. mask := base.Mask
  40. parentLen, addrLen := mask.Size()
  41. newPrefixLen := parentLen + newBits
  42. if newPrefixLen > addrLen {
  43. return nil, fmt.Errorf("insufficient address space to extend prefix of %d by %d", parentLen, newBits)
  44. }
  45. maxNetNum := uint64(1<<uint64(newBits)) - 1
  46. if num.Uint64() > maxNetNum {
  47. return nil, fmt.Errorf("prefix extension of %d does not accommodate a subnet numbered %d", newBits, num)
  48. }
  49. return &net.IPNet{
  50. IP: insertNumIntoIP(ip, num, newPrefixLen),
  51. Mask: net.CIDRMask(newPrefixLen, addrLen),
  52. }, nil
  53. }
  54. // Host takes a parent CIDR range and turns it into a host IP address with the
  55. // given host number.
  56. //
  57. // For example, 10.3.0.0/16 with a host number of 2 gives 10.3.0.2.
  58. func Host(base *net.IPNet, num int) (net.IP, error) {
  59. return HostBig(base, big.NewInt(int64(num)))
  60. }
  61. // HostBig takes a parent CIDR range and turns it into a host IP address with
  62. // the given host number. It differs from Host in that it takes a *big.Int for
  63. // the num, instead of an int.
  64. //
  65. // For example, 10.3.0.0/16 with a host number of 2 gives 10.3.0.2.
  66. func HostBig(base *net.IPNet, num *big.Int) (net.IP, error) {
  67. ip := base.IP
  68. mask := base.Mask
  69. parentLen, addrLen := mask.Size()
  70. hostLen := addrLen - parentLen
  71. maxHostNum := big.NewInt(int64(1))
  72. maxHostNum.Lsh(maxHostNum, uint(hostLen))
  73. maxHostNum.Sub(maxHostNum, big.NewInt(1))
  74. numUint64 := big.NewInt(int64(num.Uint64()))
  75. if num.Cmp(big.NewInt(0)) == -1 {
  76. numUint64.Neg(num)
  77. numUint64.Sub(numUint64, big.NewInt(int64(1)))
  78. num.Sub(maxHostNum, numUint64)
  79. }
  80. if numUint64.Cmp(maxHostNum) == 1 {
  81. return nil, fmt.Errorf("prefix of %d does not accommodate a host numbered %d", parentLen, num)
  82. }
  83. var bitlength int
  84. if ip.To4() != nil {
  85. bitlength = 32
  86. } else {
  87. bitlength = 128
  88. }
  89. return insertNumIntoIP(ip, num, bitlength), nil
  90. }
  91. // AddressRange returns the first and last addresses in the given CIDR range.
  92. func AddressRange(network *net.IPNet) (net.IP, net.IP) {
  93. // the first IP is easy
  94. firstIP := network.IP
  95. // the last IP is the network address OR NOT the mask address
  96. prefixLen, bits := network.Mask.Size()
  97. if prefixLen == bits {
  98. // Easy!
  99. // But make sure that our two slices are distinct, since they
  100. // would be in all other cases.
  101. lastIP := make([]byte, len(firstIP))
  102. copy(lastIP, firstIP)
  103. return firstIP, lastIP
  104. }
  105. firstIPInt, bits := ipToInt(firstIP)
  106. hostLen := uint(bits) - uint(prefixLen)
  107. lastIPInt := big.NewInt(1)
  108. lastIPInt.Lsh(lastIPInt, hostLen)
  109. lastIPInt.Sub(lastIPInt, big.NewInt(1))
  110. lastIPInt.Or(lastIPInt, firstIPInt)
  111. return firstIP, intToIP(lastIPInt, bits)
  112. }
  113. // AddressCount returns the number of distinct host addresses within the given
  114. // CIDR range.
  115. //
  116. // Since the result is a uint64, this function returns meaningful information
  117. // only for IPv4 ranges and IPv6 ranges with a prefix size of at least 65.
  118. func AddressCount(network *net.IPNet) uint64 {
  119. prefixLen, bits := network.Mask.Size()
  120. return 1 << (uint64(bits) - uint64(prefixLen))
  121. }
  122. //VerifyNoOverlap takes a list subnets and supernet (CIDRBlock) and verifies
  123. //none of the subnets overlap and all subnets are in the supernet
  124. //it returns an error if any of those conditions are not satisfied
  125. func VerifyNoOverlap(subnets []*net.IPNet, CIDRBlock *net.IPNet) error {
  126. firstLastIP := make([][]net.IP, len(subnets))
  127. for i, s := range subnets {
  128. first, last := AddressRange(s)
  129. firstLastIP[i] = []net.IP{first, last}
  130. }
  131. for i, s := range subnets {
  132. if !CIDRBlock.Contains(firstLastIP[i][0]) || !CIDRBlock.Contains(firstLastIP[i][1]) {
  133. return fmt.Errorf("%s does not fully contain %s", CIDRBlock.String(), s.String())
  134. }
  135. for j := 0; j < len(subnets); j++ {
  136. if i == j {
  137. continue
  138. }
  139. first := firstLastIP[j][0]
  140. last := firstLastIP[j][1]
  141. if s.Contains(first) || s.Contains(last) {
  142. return fmt.Errorf("%s overlaps with %s", subnets[j].String(), s.String())
  143. }
  144. }
  145. }
  146. return nil
  147. }
  148. // PreviousSubnet returns the subnet of the desired mask in the IP space
  149. // just lower than the start of IPNet provided. If the IP space rolls over
  150. // then the second return value is true
  151. func PreviousSubnet(network *net.IPNet, prefixLen int) (*net.IPNet, bool) {
  152. startIP := checkIPv4(network.IP)
  153. previousIP := make(net.IP, len(startIP))
  154. copy(previousIP, startIP)
  155. cMask := net.CIDRMask(prefixLen, 8*len(previousIP))
  156. previousIP = Dec(previousIP)
  157. previous := &net.IPNet{IP: previousIP.Mask(cMask), Mask: cMask}
  158. if startIP.Equal(net.IPv4zero) || startIP.Equal(net.IPv6zero) {
  159. return previous, true
  160. }
  161. return previous, false
  162. }
  163. // NextSubnet returns the next available subnet of the desired mask size
  164. // starting for the maximum IP of the offset subnet
  165. // If the IP exceeds the maxium IP then the second return value is true
  166. func NextSubnet(network *net.IPNet, prefixLen int) (*net.IPNet, bool) {
  167. _, currentLast := AddressRange(network)
  168. mask := net.CIDRMask(prefixLen, 8*len(currentLast))
  169. currentSubnet := &net.IPNet{IP: currentLast.Mask(mask), Mask: mask}
  170. _, last := AddressRange(currentSubnet)
  171. last = Inc(last)
  172. next := &net.IPNet{IP: last.Mask(mask), Mask: mask}
  173. if last.Equal(net.IPv4zero) || last.Equal(net.IPv6zero) {
  174. return next, true
  175. }
  176. return next, false
  177. }
  178. //Inc increases the IP by one this returns a new []byte for the IP
  179. func Inc(IP net.IP) net.IP {
  180. IP = checkIPv4(IP)
  181. incIP := make([]byte, len(IP))
  182. copy(incIP, IP)
  183. for j := len(incIP) - 1; j >= 0; j-- {
  184. incIP[j]++
  185. if incIP[j] > 0 {
  186. break
  187. }
  188. }
  189. return incIP
  190. }
  191. //Dec decreases the IP by one this returns a new []byte for the IP
  192. func Dec(IP net.IP) net.IP {
  193. IP = checkIPv4(IP)
  194. decIP := make([]byte, len(IP))
  195. copy(decIP, IP)
  196. decIP = checkIPv4(decIP)
  197. for j := len(decIP) - 1; j >= 0; j-- {
  198. decIP[j]--
  199. if decIP[j] < 255 {
  200. break
  201. }
  202. }
  203. return decIP
  204. }
  205. func checkIPv4(ip net.IP) net.IP {
  206. // Go for some reason allocs IPv6len for IPv4 so we have to correct it
  207. if v4 := ip.To4(); v4 != nil {
  208. return v4
  209. }
  210. return ip
  211. }