You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
2.6 KiB
108 lines
2.6 KiB
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 |
|
}
|
|
|