Skip to content

Commit 23fc4df

Browse files
committed
Handle IPv6 tree without IPv4 subtree
when calculating LookupNetwork. Arguably, it might be cleaner to not set ipv4Start when there is no IPv4 subtree, although that would also introduce additional complications and it would make those lookups slower.
1 parent e957830 commit 23fc4df

File tree

2 files changed

+52
-14
lines changed

2 files changed

+52
-14
lines changed

reader.go

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@ var metadataStartMarker = []byte("\xAB\xCD\xEFMaxMind.com")
2121
// Reader holds the data corresponding to the MaxMind DB file. Its only public
2222
// field is Metadata, which contains the metadata from the MaxMind DB file.
2323
type Reader struct {
24-
hasMappedFile bool
25-
buffer []byte
26-
decoder decoder
27-
Metadata Metadata
28-
ipv4Start uint
24+
hasMappedFile bool
25+
buffer []byte
26+
decoder decoder
27+
Metadata Metadata
28+
ipv4Start uint
29+
ipv4StartBitDepth int
2930
}
3031

3132
// Metadata holds the metadata decoded from the MaxMind DB file. In particular
@@ -81,27 +82,30 @@ func FromBytes(buffer []byte) (*Reader, error) {
8182
ipv4Start: 0,
8283
}
8384

84-
reader.ipv4Start, err = reader.startNode()
85+
err = reader.setIPv4Start()
8586

8687
return reader, err
8788
}
8889

89-
func (r *Reader) startNode() (uint, error) {
90+
func (r *Reader) setIPv4Start() error {
9091
if r.Metadata.IPVersion != 6 {
91-
return 0, nil
92+
return nil
9293
}
9394

9495
nodeCount := r.Metadata.NodeCount
9596

9697
node := uint(0)
9798
var err error
98-
for i := 0; i < 96 && node < nodeCount; i++ {
99+
i := 0
100+
for ; i < 96 && node < nodeCount; i++ {
99101
node, err = r.readNode(node, 0)
100102
if err != nil {
101-
return 0, err
103+
return err
102104
}
103105
}
104-
return node, err
106+
r.ipv4Start = node
107+
r.ipv4StartBitDepth = i
108+
return err
105109
}
106110

107111
// Lookup retrieves the database record for ip and stores it in the value
@@ -161,9 +165,16 @@ func (r *Reader) LookupOffset(ip net.IP) (uintptr, error) {
161165
}
162166

163167
func (r *Reader) cidr(ip net.IP, prefixLength int) *net.IPNet {
164-
ipBitLength := len(ip) * 8
165-
mask := net.CIDRMask(prefixLength, ipBitLength)
168+
// This is necessary as the node that the IPv4 start is at may
169+
// be at a bit depth that is less that 96, i.e., ipv4Start points
170+
// to a leaf node.
171+
if r.Metadata.IPVersion == 6 &&
172+
len(ip) == net.IPv4len &&
173+
r.ipv4StartBitDepth != 96 {
174+
return &net.IPNet{IP: net.ParseIP("::"), Mask: net.CIDRMask(r.ipv4StartBitDepth, 128)}
175+
}
166176

177+
mask := net.CIDRMask(prefixLength, len(ip)*8)
167178
return &net.IPNet{IP: ip.Mask(mask), Mask: mask}
168179
}
169180

reader_test.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ func TestLookupNetwork(t *testing.T) {
9090
ExpectedRecord interface{}
9191
ExpectedOK bool
9292
}{
93-
// XXX - add test of IPv4 lookup in IPv6 database with no IPv4 subtree
9493
{
9594
IP: net.ParseIP("1.1.1.1"),
9695
DBFile: "MaxMind-DB-test-ipv6-32.mmdb",
@@ -147,6 +146,34 @@ func TestLookupNetwork(t *testing.T) {
147146
ExpectedRecord: decoderRecord,
148147
ExpectedOK: true,
149148
},
149+
{
150+
IP: net.ParseIP("200.0.2.1"),
151+
DBFile: "MaxMind-DB-no-ipv4-search-tree.mmdb",
152+
ExpectedCIDR: "::/64",
153+
ExpectedRecord: "::0/64",
154+
ExpectedOK: true,
155+
},
156+
{
157+
IP: net.ParseIP("::200.0.2.1"),
158+
DBFile: "MaxMind-DB-no-ipv4-search-tree.mmdb",
159+
ExpectedCIDR: "::/64",
160+
ExpectedRecord: "::0/64",
161+
ExpectedOK: true,
162+
},
163+
{
164+
IP: net.ParseIP("0:0:0:0:ffff:ffff:ffff:ffff"),
165+
DBFile: "MaxMind-DB-no-ipv4-search-tree.mmdb",
166+
ExpectedCIDR: "::/64",
167+
ExpectedRecord: "::0/64",
168+
ExpectedOK: true,
169+
},
170+
{
171+
IP: net.ParseIP("ef00::"),
172+
DBFile: "MaxMind-DB-no-ipv4-search-tree.mmdb",
173+
ExpectedCIDR: "8000::/1",
174+
ExpectedRecord: nil,
175+
ExpectedOK: false,
176+
},
150177
}
151178

152179
for _, test := range tests {

0 commit comments

Comments
 (0)