@@ -16,6 +16,7 @@ type netNode struct {
1616
1717type networkOptions struct {
1818 includeAliasedNetworks bool
19+ includeEmptyNetworks bool
1920}
2021
2122var (
@@ -33,21 +34,30 @@ 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
4249// [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
@@ -57,6 +67,9 @@ func (r *Reader) Networks(options ...NetworksOption) iter.Seq[Result] {
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,25 @@ 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+ ip := node .ip
126+ if isInIPv4Subtree (ip ) {
127+ ip = v6ToV4 (ip )
128+ }
129+
130+ ok := yield (Result {
131+ ip : ip ,
132+ offset : notFound ,
133+ prefixLen : uint8 (node .bit ),
134+ })
135+ if ! ok {
136+ return
137+ }
138+ }
139+ break
140+ }
110141 // This skips IPv4 aliases without hardcoding the networks that the writer
111142 // currently aliases.
112143 if ! n .includeAliasedNetworks && r .ipv4Start != 0 &&
0 commit comments