@@ -16,6 +16,7 @@ type netNode struct {
1616
1717type networkOptions struct {
1818 includeAliasedNetworks bool
19+ includeEmptyNetworks bool
1920}
2021
2122var (
@@ -33,30 +34,42 @@ func IncludeAliasedNetworks(networks *networkOptions) {
3334 networks .includeAliasedNetworks = true
3435}
3536
36- // Networks returns an iterator that can be used to traverse all networks in
37+ // IncludeEmptyNetworks is an option for Networks and NetworksWithin
38+ // that makes them include networks without any data in the iteration.
39+ func IncludeEmptyNetworks (networks * networkOptions ) {
40+ networks .includeEmptyNetworks = true
41+ }
42+
43+ // Networks returns an iterator that can be used to traverse the networks in
3744// the database.
3845//
3946// Please note that a MaxMind DB may map IPv4 networks into several locations
4047// in an IPv6 database. This iterator will only iterate over these once by
4148// default. To iterate over all the IPv4 network locations, use the
42- // IncludeAliasedNetworks option.
49+ // [IncludeAliasedNetworks] option.
50+ //
51+ // Networks without data are excluded by default. To include them, use
52+ // [IncludeEmptyNetworks].
4353func (r * Reader ) Networks (options ... NetworksOption ) iter.Seq [Result ] {
4454 if r .Metadata .IPVersion == 6 {
4555 return r .NetworksWithin (allIPv6 , options ... )
4656 }
4757 return r .NetworksWithin (allIPv4 , options ... )
4858}
4959
50- // NetworksWithin returns an iterator that can be used to traverse all networks
60+ // NetworksWithin returns an iterator that can be used to traverse the networks
5161// in the database which are contained in a given prefix.
5262//
5363// Please note that a MaxMind DB may map IPv4 networks into several locations
54- // in an IPv6 database. This iterator will iterate over all of these locations
55- // separately . To only iterate over the IPv4 networks once , use the
56- // SkipAliasedNetworks option.
64+ // in an IPv6 database. This iterator will only iterate over these once by
65+ // default . To iterate over all the IPv4 network locations , use the
66+ // [IncludeAliasedNetworks] option.
5767//
5868// If the provided prefix is contained within a network in the database, the
5969// iterator will iterate over exactly one network, the containing network.
70+ //
71+ // Networks without data are excluded by default. To include them, use
72+ // [IncludeEmptyNetworks].
6073func (r * Reader ) NetworksWithin (prefix netip.Prefix , options ... NetworksOption ) iter.Seq [Result ] {
6174 return func (yield func (Result ) bool ) {
6275 if r .Metadata .IPVersion == 4 && prefix .Addr ().Is6 () {
@@ -106,7 +119,20 @@ func (r *Reader) NetworksWithin(prefix netip.Prefix, options ...NetworksOption)
106119 node := nodes [len (nodes )- 1 ]
107120 nodes = nodes [:len (nodes )- 1 ]
108121
109- for node .pointer != r .Metadata .NodeCount {
122+ for {
123+ if node .pointer == r .Metadata .NodeCount {
124+ if n .includeEmptyNetworks {
125+ ok := yield (Result {
126+ ip : mappedIP (node .ip ),
127+ offset : notFound ,
128+ prefixLen : uint8 (node .bit ),
129+ })
130+ if ! ok {
131+ return
132+ }
133+ }
134+ break
135+ }
110136 // This skips IPv4 aliases without hardcoding the networks that the writer
111137 // currently aliases.
112138 if ! n .includeAliasedNetworks && r .ipv4Start != 0 &&
@@ -115,15 +141,10 @@ func (r *Reader) NetworksWithin(prefix netip.Prefix, options ...NetworksOption)
115141 }
116142
117143 if node .pointer > r .Metadata .NodeCount {
118- ip := node .ip
119- if isInIPv4Subtree (ip ) {
120- ip = v6ToV4 (ip )
121- }
122-
123144 offset , err := r .resolveDataPointer (node .pointer )
124145 ok := yield (Result {
125146 decoder : r .decoder ,
126- ip : ip ,
147+ ip : mappedIP ( node . ip ) ,
127148 offset : uint (offset ),
128149 prefixLen : uint8 (node .bit ),
129150 err : err ,
@@ -171,6 +192,13 @@ func (r *Reader) NetworksWithin(prefix netip.Prefix, options ...NetworksOption)
171192
172193var ipv4SubtreeBoundary = netip .MustParseAddr ("::255.255.255.255" ).Next ()
173194
195+ func mappedIP (ip netip.Addr ) netip.Addr {
196+ if isInIPv4Subtree (ip ) {
197+ return v6ToV4 (ip )
198+ }
199+ return ip
200+ }
201+
174202// isInIPv4Subtree returns true if the IP is in the database's IPv4 subtree.
175203func isInIPv4Subtree (ip netip.Addr ) bool {
176204 return ip .Is4 () || ip .Less (ipv4SubtreeBoundary )
0 commit comments