traverse.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. package maxminddb
  2. import (
  3. "fmt"
  4. "net"
  5. )
  6. // Internal structure used to keep track of nodes we still need to visit.
  7. type netNode struct {
  8. ip net.IP
  9. bit uint
  10. pointer uint
  11. }
  12. // Networks represents a set of subnets that we are iterating over.
  13. type Networks struct {
  14. err error
  15. reader *Reader
  16. nodes []netNode
  17. lastNode netNode
  18. skipAliasedNetworks bool
  19. }
  20. var (
  21. allIPv4 = &net.IPNet{IP: make(net.IP, 4), Mask: net.CIDRMask(0, 32)}
  22. allIPv6 = &net.IPNet{IP: make(net.IP, 16), Mask: net.CIDRMask(0, 128)}
  23. )
  24. // NetworksOption are options for Networks and NetworksWithin.
  25. type NetworksOption func(*Networks)
  26. // SkipAliasedNetworks is an option for Networks and NetworksWithin that
  27. // makes them not iterate over aliases of the IPv4 subtree in an IPv6
  28. // database, e.g., ::ffff:0:0/96, 2001::/32, and 2002::/16.
  29. //
  30. // You most likely want to set this. The only reason it isn't the default
  31. // behavior is to provide backwards compatibility to existing users.
  32. func SkipAliasedNetworks(networks *Networks) {
  33. networks.skipAliasedNetworks = true
  34. }
  35. // Networks returns an iterator that can be used to traverse all networks in
  36. // the database.
  37. //
  38. // Please note that a MaxMind DB may map IPv4 networks into several locations
  39. // in an IPv6 database. This iterator will iterate over all of these locations
  40. // separately. To only iterate over the IPv4 networks once, use the
  41. // SkipAliasedNetworks option.
  42. func (r *Reader) Networks(options ...NetworksOption) *Networks {
  43. var networks *Networks
  44. if r.Metadata.IPVersion == 6 {
  45. networks = r.NetworksWithin(allIPv6, options...)
  46. } else {
  47. networks = r.NetworksWithin(allIPv4, options...)
  48. }
  49. return networks
  50. }
  51. // NetworksWithin returns an iterator that can be used to traverse all networks
  52. // in the database which are contained in a given network.
  53. //
  54. // Please note that a MaxMind DB may map IPv4 networks into several locations
  55. // in an IPv6 database. This iterator will iterate over all of these locations
  56. // separately. To only iterate over the IPv4 networks once, use the
  57. // SkipAliasedNetworks option.
  58. //
  59. // If the provided network is contained within a network in the database, the
  60. // iterator will iterate over exactly one network, the containing network.
  61. func (r *Reader) NetworksWithin(network *net.IPNet, options ...NetworksOption) *Networks {
  62. if r.Metadata.IPVersion == 4 && network.IP.To4() == nil {
  63. return &Networks{
  64. err: fmt.Errorf(
  65. "error getting networks with '%s': you attempted to use an IPv6 network in an IPv4-only database",
  66. network.String(),
  67. ),
  68. }
  69. }
  70. networks := &Networks{reader: r}
  71. for _, option := range options {
  72. option(networks)
  73. }
  74. ip := network.IP
  75. prefixLength, _ := network.Mask.Size()
  76. if r.Metadata.IPVersion == 6 && len(ip) == net.IPv4len {
  77. if networks.skipAliasedNetworks {
  78. ip = net.IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ip[0], ip[1], ip[2], ip[3]}
  79. } else {
  80. ip = ip.To16()
  81. }
  82. prefixLength += 96
  83. }
  84. pointer, bit := r.traverseTree(ip, 0, uint(prefixLength))
  85. networks.nodes = []netNode{
  86. {
  87. ip: ip,
  88. bit: uint(bit),
  89. pointer: pointer,
  90. },
  91. }
  92. return networks
  93. }
  94. // Next prepares the next network for reading with the Network method. It
  95. // returns true if there is another network to be processed and false if there
  96. // are no more networks or if there is an error.
  97. func (n *Networks) Next() bool {
  98. if n.err != nil {
  99. return false
  100. }
  101. for len(n.nodes) > 0 {
  102. node := n.nodes[len(n.nodes)-1]
  103. n.nodes = n.nodes[:len(n.nodes)-1]
  104. for node.pointer != n.reader.Metadata.NodeCount {
  105. // This skips IPv4 aliases without hardcoding the networks that the writer
  106. // currently aliases.
  107. if n.skipAliasedNetworks && n.reader.ipv4Start != 0 &&
  108. node.pointer == n.reader.ipv4Start && !isInIPv4Subtree(node.ip) {
  109. break
  110. }
  111. if node.pointer > n.reader.Metadata.NodeCount {
  112. n.lastNode = node
  113. return true
  114. }
  115. ipRight := make(net.IP, len(node.ip))
  116. copy(ipRight, node.ip)
  117. if len(ipRight) <= int(node.bit>>3) {
  118. n.err = newInvalidDatabaseError(
  119. "invalid search tree at %v/%v", ipRight, node.bit)
  120. return false
  121. }
  122. ipRight[node.bit>>3] |= 1 << (7 - (node.bit % 8))
  123. offset := node.pointer * n.reader.nodeOffsetMult
  124. rightPointer := n.reader.nodeReader.readRight(offset)
  125. node.bit++
  126. n.nodes = append(n.nodes, netNode{
  127. pointer: rightPointer,
  128. ip: ipRight,
  129. bit: node.bit,
  130. })
  131. node.pointer = n.reader.nodeReader.readLeft(offset)
  132. }
  133. }
  134. return false
  135. }
  136. // Network returns the current network or an error if there is a problem
  137. // decoding the data for the network. It takes a pointer to a result value to
  138. // decode the network's data into.
  139. func (n *Networks) Network(result any) (*net.IPNet, error) {
  140. if n.err != nil {
  141. return nil, n.err
  142. }
  143. if err := n.reader.retrieveData(n.lastNode.pointer, result); err != nil {
  144. return nil, err
  145. }
  146. ip := n.lastNode.ip
  147. prefixLength := int(n.lastNode.bit)
  148. // We do this because uses of SkipAliasedNetworks expect the IPv4 networks
  149. // to be returned as IPv4 networks. If we are not skipping aliased
  150. // networks, then the user will get IPv4 networks from the ::FFFF:0:0/96
  151. // network as Go automatically converts those.
  152. if n.skipAliasedNetworks && isInIPv4Subtree(ip) {
  153. ip = ip[12:]
  154. prefixLength -= 96
  155. }
  156. return &net.IPNet{
  157. IP: ip,
  158. Mask: net.CIDRMask(prefixLength, len(ip)*8),
  159. }, nil
  160. }
  161. // Err returns an error, if any, that was encountered during iteration.
  162. func (n *Networks) Err() error {
  163. return n.err
  164. }
  165. // isInIPv4Subtree returns true if the IP is an IPv6 address in the database's
  166. // IPv4 subtree.
  167. func isInIPv4Subtree(ip net.IP) bool {
  168. if len(ip) != 16 {
  169. return false
  170. }
  171. for i := 0; i < 12; i++ {
  172. if ip[i] != 0 {
  173. return false
  174. }
  175. }
  176. return true
  177. }