diff options
Diffstat (limited to 'vendor/github.com/oschwald/maxminddb-golang/traverse.go')
-rw-r--r-- | vendor/github.com/oschwald/maxminddb-golang/traverse.go | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/vendor/github.com/oschwald/maxminddb-golang/traverse.go b/vendor/github.com/oschwald/maxminddb-golang/traverse.go new file mode 100644 index 0000000..f9b443c --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/traverse.go @@ -0,0 +1,108 @@ +package maxminddb + +import "net" + +// Internal structure used to keep track of nodes we still need to visit. +type netNode struct { + ip net.IP + bit uint + pointer uint +} + +// Networks represents a set of subnets that we are iterating over. +type Networks struct { + reader *Reader + nodes []netNode // Nodes we still have to visit. + lastNode netNode + err error +} + +// Networks returns an iterator that can be used to traverse all networks in +// the database. +// +// Please note that a MaxMind DB may map IPv4 networks into several locations +// in in an IPv6 database. This iterator will iterate over all of these +// locations separately. +func (r *Reader) Networks() *Networks { + s := 4 + if r.Metadata.IPVersion == 6 { + s = 16 + } + return &Networks{ + reader: r, + nodes: []netNode{ + { + ip: make(net.IP, s), + }, + }, + } +} + +// Next prepares the next network for reading with the Network method. It +// returns true if there is another network to be processed and false if there +// are no more networks or if there is an error. +func (n *Networks) Next() bool { + for len(n.nodes) > 0 { + node := n.nodes[len(n.nodes)-1] + n.nodes = n.nodes[:len(n.nodes)-1] + + for { + if node.pointer < n.reader.Metadata.NodeCount { + ipRight := make(net.IP, len(node.ip)) + copy(ipRight, node.ip) + if len(ipRight) <= int(node.bit>>3) { + n.err = newInvalidDatabaseError( + "invalid search tree at %v/%v", ipRight, node.bit) + return false + } + ipRight[node.bit>>3] |= 1 << (7 - (node.bit % 8)) + + rightPointer, err := n.reader.readNode(node.pointer, 1) + if err != nil { + n.err = err + return false + } + + node.bit++ + n.nodes = append(n.nodes, netNode{ + pointer: rightPointer, + ip: ipRight, + bit: node.bit, + }) + + node.pointer, err = n.reader.readNode(node.pointer, 0) + if err != nil { + n.err = err + return false + } + + } else if node.pointer > n.reader.Metadata.NodeCount { + n.lastNode = node + return true + } else { + break + } + } + } + + return false +} + +// Network returns the current network or an error if there is a problem +// decoding the data for the network. It takes a pointer to a result value to +// decode the network's data into. +func (n *Networks) Network(result interface{}) (*net.IPNet, error) { + if err := n.reader.retrieveData(n.lastNode.pointer, result); err != nil { + return nil, err + } + + return &net.IPNet{ + IP: n.lastNode.ip, + Mask: net.CIDRMask(int(n.lastNode.bit), len(n.lastNode.ip)*8), + }, nil +} + +// Err returns an error, if any, that was encountered during iteration. +func (n *Networks) Err() error { + return n.err +} |