Skip to content

Commit

Permalink
Convert ipv4 address to ipv6 when searching on an ipv6 db
Browse files Browse the repository at this point in the history
  • Loading branch information
oalders committed Jan 10, 2020
1 parent d1c282d commit 7abc676
Show file tree
Hide file tree
Showing 2 changed files with 215 additions and 19 deletions.
15 changes: 12 additions & 3 deletions traverse.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package maxminddb

import "net"
import (
"net"
)

// Internal structure used to keep track of nodes we still need to visit.
type netNode struct {
Expand Down Expand Up @@ -38,13 +40,20 @@ func (r *Reader) Networks() *Networks {
}

func (r *Reader) NetworksWithin(network *net.IPNet) *Networks {
ip := network.IP
prefixLength, _ := network.Mask.Size()
pointer, bit := r.traverseTree(network.IP, 0, uint(prefixLength))

if r.Metadata.IPVersion == 6 && len(ip) == net.IPv4len {
ip = net.IP.To16(ip)
prefixLength += 96
}

pointer, bit := r.traverseTree(ip, 0, uint(prefixLength))
return &Networks{
reader: r,
nodes: []netNode{
{
ip: network.IP,
ip: ip,
bit: uint(bit),
pointer: pointer,
},
Expand Down
219 changes: 203 additions & 16 deletions traverse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,9 @@ func TestNetworksWithInvalidSearchTree(t *testing.T) {
assert.NotNil(t, n.Err(), "no error received when traversing an broken search tree")
assert.Equal(t, n.Err().Error(), "invalid search tree at 128.128.128.128/32")
}
func TestNetworksWithin(t *testing.T) {
_, network, error := net.ParseCIDR("1.1.1.0/24")

assert.Nil(t, error)
func TestNetworksWithinV4SearchInV4Db(t *testing.T) {
var network = &net.IPNet{IP: make(net.IP, 4), Mask: net.CIDRMask(0, 32)}

for _, recordSize := range []uint{24, 28, 32} {
fileName := testFile(fmt.Sprintf("MaxMind-DB-test-ipv4-%d.mmdb", recordSize))
Expand All @@ -70,27 +69,26 @@ func TestNetworksWithin(t *testing.T) {
assert.Equal(t, record.IP, network.IP.String(),
"expected %s got %s", record.IP, network.IP.String(),
)
innerIPs = append(innerIPs, record.IP)
innerIPs = append(innerIPs, network.String())
}

expectedIPs := []string{
"1.1.1.1",
"1.1.1.2",
"1.1.1.4",
"1.1.1.8",
"1.1.1.16",
"1.1.1.32",
"1.1.1.1/32",
"1.1.1.2/31",
"1.1.1.4/30",
"1.1.1.8/29",
"1.1.1.16/28",
"1.1.1.32/32",
}

assert.Equal(t, expectedIPs, innerIPs)
assert.Nil(t, n.Err())
}
}

func TestNetworksWithinSlash32(t *testing.T) {
_, network, error := net.ParseCIDR("1.1.1.32/32")

assert.Nil(t, error)
func TestNetworksWithinSlash32V4SearchInV4Db(t *testing.T) {
_, network, err := net.ParseCIDR("1.1.1.1/32")
assert.Nil(t, err)

for _, recordSize := range []uint{24, 28, 32} {
fileName := testFile(fmt.Sprintf("MaxMind-DB-test-ipv4-%d.mmdb", recordSize))
Expand All @@ -110,12 +108,201 @@ func TestNetworksWithinSlash32(t *testing.T) {
assert.Equal(t, record.IP, network.IP.String(),
"expected %s got %s", record.IP, network.IP.String(),
)
innerIPs = append(innerIPs, record.IP)
innerIPs = append(innerIPs, network.String())
}

expectedIPs := []string{
"1.1.1.1/32",
}

assert.Equal(t, expectedIPs, innerIPs)
assert.Nil(t, n.Err())
}
}

func TestNetworksWithinSlash32V4SearchInV6Db(t *testing.T) {
_, network, err := net.ParseCIDR("1.1.1.1/32")
assert.Nil(t, err)

for _, recordSize := range []uint{24, 28, 32} {
fileName := testFile(fmt.Sprintf("MaxMind-DB-test-mixed-%d.mmdb", recordSize))
reader, err := Open(fileName)
require.Nil(t, err, "unexpected error while opening database: %v", err)
defer reader.Close()

n := reader.NetworksWithin(network)
var innerIPs []string

for n.Next() {
record := struct {
IP string `maxminddb:"ip"`
}{}
network, err := n.Network(&record)
assert.Nil(t, err)
innerIPs = append(innerIPs, network.String())
}

expectedIPs := []string{
"1.1.1.1/32",
}

assert.Equal(t, expectedIPs, innerIPs)
assert.Nil(t, n.Err())
}

}
func TestNetworksWithinSlash128V6SearchInV6Db(t *testing.T) {
_, network, err := net.ParseCIDR("::1:ffff:ffff/128")
assert.Nil(t, err)

for _, recordSize := range []uint{24, 28, 32} {
fileName := testFile(fmt.Sprintf("MaxMind-DB-test-ipv6-%d.mmdb", recordSize))
reader, err := Open(fileName)
require.Nil(t, err, "unexpected error while opening database: %v", err)
defer reader.Close()

n := reader.NetworksWithin(network)
var innerIPs []string

for n.Next() {
record := struct {
IP string `maxminddb:"ip"`
}{}
network, err := n.Network(&record)
assert.Nil(t, err)
assert.Equal(t, record.IP, network.IP.String(),
"expected %s got %s", record.IP, network.IP.String(),
)
innerIPs = append(innerIPs, network.String())
}

expectedIPs := []string([]string{"1.1.1.32"})
expectedIPs := []string{
"::1:ffff:ffff/128",
}

assert.Equal(t, expectedIPs, innerIPs)
assert.Nil(t, n.Err())
}
}

func TestNetworksWithinV6SearchInV6Db(t *testing.T) {
var network = &net.IPNet{IP: make(net.IP, 16), Mask: net.CIDRMask(0, 128)}

for _, recordSize := range []uint{24, 28, 32} {
fileName := testFile(fmt.Sprintf("MaxMind-DB-test-ipv6-%d.mmdb", recordSize))
reader, err := Open(fileName)
require.Nil(t, err, "unexpected error while opening database: %v", err)
defer reader.Close()

n := reader.NetworksWithin(network)
var innerIPs []string

for n.Next() {
record := struct {
IP string `maxminddb:"ip"`
}{}
network, err := n.Network(&record)
assert.Nil(t, err)
assert.Equal(t, record.IP, network.IP.String(),
"expected %s got %s", record.IP, network.IP.String(),
)
innerIPs = append(innerIPs, network.String())
}

expectedIPs := []string{
"::1:ffff:ffff/128",
"::2:0:0/122",
"::2:0:40/124",
"::2:0:50/125",
"::2:0:58/127",
}

assert.Equal(
t,
expectedIPs,
innerIPs,
fmt.Sprintf("inner IPs for %v", fileName),
)
assert.Nil(t, n.Err())
}
}

func TestNetworksWithinV4SearchInV6Db(t *testing.T) {
var network = &net.IPNet{IP: make(net.IP, 4), Mask: net.CIDRMask(0, 32)}

for _, recordSize := range []uint{24, 28, 32} {
fileName := testFile(fmt.Sprintf("MaxMind-DB-test-mixed-%d.mmdb", recordSize))
reader, err := Open(fileName)
require.Nil(t, err, "unexpected error while opening database: %v", err)
defer reader.Close()

n := reader.NetworksWithin(network)
var innerIPs []string

for n.Next() {
record := struct {
IP string `maxminddb:"ip"`
}{}
network, err := n.Network(&record)
assert.Nil(t, err)
innerIPs = append(innerIPs, network.String())
}

expectedIPs := []string{
"1.1.1.1/32",
"1.1.1.2/31",
"1.1.1.4/30",
"1.1.1.8/29",
"1.1.1.16/28",
"1.1.1.32/32",
}

assert.Equal(
t,
expectedIPs,
innerIPs,
fmt.Sprintf("inner IPs for %v", fileName),
)
assert.Nil(t, n.Err())
}
}

func TestNetworksWithinV6SearchInV4Db(t *testing.T) {
var network = &net.IPNet{IP: make(net.IP, 16), Mask: net.CIDRMask(0, 128)}

for _, recordSize := range []uint{24, 28, 32} {
fileName := testFile(fmt.Sprintf("MaxMind-DB-test-ipv4-%d.mmdb", recordSize))
reader, err := Open(fileName)
require.Nil(t, err, "unexpected error while opening database: %v", err)
defer reader.Close()

n := reader.NetworksWithin(network)
var innerIPs []string

for n.Next() {
record := struct {
IP string `maxminddb:"ip"`
}{}
network, err := n.Network(&record)
assert.Nil(t, err)
innerIPs = append(innerIPs, network.String())
}

expectedIPs := []string{
"101:101::/32",
"101:102::/31",
"101:104::/30",
"101:108::/29",
"101:110::/28",
"101:120::/32",
}

assert.Equal(
t,
expectedIPs,
innerIPs,
fmt.Sprintf("inner IPs for %v", fileName),
)
assert.Nil(t, n.Err())
}
}

0 comments on commit 7abc676

Please sign in to comment.