k-sone / critbitgo

crit-bit for golang and its applications (sorted map, IP routing table)
MIT License
45 stars 14 forks source link

MatchIP produces incorrect result #16

Closed gaissmai closed 10 months ago

gaissmai commented 10 months ago

I work with the full Internet routing table, over a million IPv4/IPv6 routes. If I then add an IPv6 default route to the crit-bit trie, this route is not found reliably but nil is returned, which should not be the case. I have now reduced it to the simplest test case for me. I was able to determine that I definitely need IPv4 and IPv6 routes to produce the error case:

package main_test

import (
  "net"
  "testing"

  "github.com/k-sone/critbitgo"
)

func checkerr(err error) {
  if err != nil {
    panic(err)
  }  
}

func TestMatchIP(t *testing.T) {
  // loopback
  _, lo4, err := net.ParseCIDR("127.0.0.1/8")
  checkerr(err)

  _, lo6, err := net.ParseCIDR("::1/128")
  checkerr(err)

  // default routes
  _, dg4, err := net.ParseCIDR("0.0.0.0/0")
  checkerr(err)

  _, dg6, err := net.ParseCIDR("::/0")
  checkerr(err)

  // make new crit-bit trie
  trie := critbitgo.NewNet()

  // add some CIDRs, mixed IP version needed to reproduce the error
  for _, r := range []*net.IPNet{lo4, lo6, dg4, dg6} {
    err := trie.Add(r, nil)
    checkerr(err)
  }  

  // test IPv6 addr
  ip := net.ParseIP("fe80::1")

  // longest-prefix-match for test IPv6 addr, expect "::/0"
  cidr, _, err := trie.MatchIP(ip)
  checkerr(err)

  if cidr == nil {
    t.Fatalf("MatchIP(%q), expect %q, got %v", ip, dg6, cidr)
  }  
}

see the test result, the IPv6 default route isn't found:

$ go test
--- FAIL: TestMatchIP (0.00s)
    main_test.go:48: MatchIP("fe80::1"), expect "::/0", got <nil>
gaissmai commented 10 months ago

you have to build an own trie for IPv4 and for IPv6,it's not possible to handle both IP versions in one trie