aboutsummaryrefslogtreecommitdiff
path: root/middleware/file/tree
diff options
context:
space:
mode:
authorGravatar Miek Gieben <miek@miek.nl> 2016-11-05 14:39:49 +0000
committerGravatar GitHub <noreply@github.com> 2016-11-05 14:39:49 +0000
commit2cca527d9f17fd1595366545c47630bf35591873 (patch)
treed9cda7808a085db5705bdbbffc7bc8e36824356e /middleware/file/tree
parentd6902cd7a1e70149268925453289681536b88195 (diff)
downloadcoredns-2cca527d9f17fd1595366545c47630bf35591873.tar.gz
coredns-2cca527d9f17fd1595366545c47630bf35591873.tar.zst
coredns-2cca527d9f17fd1595366545c47630bf35591873.zip
middleware/file: fix delegations (#376)
Fix the delegation handling in the *file* and *dnssec* middleware. Refactor tests a bit and show that they are failling. Add a Tree printer, cleanups and tests. Fix wildcard test - should get no answer from empty-non-terminal
Diffstat (limited to 'middleware/file/tree')
-rw-r--r--middleware/file/tree/elem.go11
-rw-r--r--middleware/file/tree/less.go3
-rw-r--r--middleware/file/tree/less_test.go2
-rw-r--r--middleware/file/tree/print.go58
-rw-r--r--middleware/file/tree/tree.go103
5 files changed, 88 insertions, 89 deletions
diff --git a/middleware/file/tree/elem.go b/middleware/file/tree/elem.go
index 234e2c848..6317cc912 100644
--- a/middleware/file/tree/elem.go
+++ b/middleware/file/tree/elem.go
@@ -52,13 +52,10 @@ func (e *Elem) Name() string {
return ""
}
-// IsWildcard returns true if this name starts with a wildcard label (*.)
-func (e *Elem) IsWildcard() bool {
- n := e.Name()
- if len(n) < 2 {
- return false
- }
- return n[0] == '*' && n[1] == '.'
+// Empty returns true is e does not contain any RRs, i.e. is an
+// empty-non-terminal.
+func (e *Elem) Empty() bool {
+ return len(e.m) == 0
}
// Insert inserts rr into e. If rr is equal to existing rrs this is a noop.
diff --git a/middleware/file/tree/less.go b/middleware/file/tree/less.go
index 595dc9213..3b8340088 100644
--- a/middleware/file/tree/less.go
+++ b/middleware/file/tree/less.go
@@ -11,7 +11,7 @@ import (
// The function orders names in DNSSEC canonical order: RFC 4034s section-6.1
//
// See http://bert-hubert.blogspot.co.uk/2015/10/how-to-do-fast-canonical-ordering-of.html
-// for a blog article on this implementation.
+// for a blog article on this implementation, although here we still go label by label.
//
// The values of a and b are *not* lowercased before the comparison!
func less(a, b string) int {
@@ -24,6 +24,7 @@ func less(a, b string) int {
if oka && okb {
return 0
}
+
// sadly this []byte will allocate... TODO(miek): check if this is needed
// for a name, otherwise compare the strings.
ab := []byte(a[ai:aj])
diff --git a/middleware/file/tree/less_test.go b/middleware/file/tree/less_test.go
index 419b75c55..ed021b66f 100644
--- a/middleware/file/tree/less_test.go
+++ b/middleware/file/tree/less_test.go
@@ -65,7 +65,7 @@ Tests:
sort.Sort(set(test.in))
for i := 0; i < len(test.in); i++ {
if test.in[i] != test.out[i] {
- t.Errorf("test %d: expected %s, got %s\n", j, test.out[i], test.in[i])
+ t.Errorf("Test %d: expected %s, got %s\n", j, test.out[i], test.in[i])
n := ""
for k, in := range test.in {
if k+1 == len(test.in) {
diff --git a/middleware/file/tree/print.go b/middleware/file/tree/print.go
new file mode 100644
index 000000000..f098e56c7
--- /dev/null
+++ b/middleware/file/tree/print.go
@@ -0,0 +1,58 @@
+package tree
+
+import "fmt"
+
+// Print prints a Tree. Main use is to aid in debugging.
+func (t *Tree) Print() {
+ if t.Root == nil {
+ fmt.Println("<nil>")
+ }
+ t.Root.print()
+}
+
+func (n *Node) print() {
+ q := NewQueue()
+ q.Push(n)
+
+ nodesInCurrentLevel := 1
+ nodesInNextLevel := 0
+
+ for !q.Empty() {
+ do := q.Pop()
+ nodesInCurrentLevel--
+
+ if do != nil {
+ fmt.Print(do.Elem.Name(), " ")
+ q.Push(do.Left)
+ q.Push(do.Right)
+ nodesInNextLevel += 2
+ }
+ if nodesInCurrentLevel == 0 {
+ fmt.Println()
+ }
+ nodesInCurrentLevel = nodesInNextLevel
+ nodesInNextLevel = 0
+ }
+ fmt.Println()
+}
+
+type queue []*Node
+
+func NewQueue() queue {
+ q := queue([]*Node{})
+ return q
+}
+
+func (q *queue) Push(n *Node) {
+ *q = append(*q, n)
+}
+
+func (q *queue) Pop() *Node {
+ n := (*q)[0]
+ *q = (*q)[1:]
+ return n
+}
+
+func (q *queue) Empty() bool {
+ return len(*q) == 0
+}
diff --git a/middleware/file/tree/tree.go b/middleware/file/tree/tree.go
index 668c19734..ed33c09a4 100644
--- a/middleware/file/tree/tree.go
+++ b/middleware/file/tree/tree.go
@@ -13,9 +13,6 @@
// Heavily modified by Miek Gieben for use in DNS zones.
package tree
-// TODO(miek): locking? lockfree would be nice. Will probably go for fine grained locking on the name level.
-// TODO(miek): fix docs
-
import "github.com/miekg/dns"
const (
@@ -23,17 +20,6 @@ const (
bu23
)
-// Result is a result of a Search.
-type Result int
-
-// Various constants that indicated the type a resource returned.
-const (
- Found Result = iota
- NameError
- EmptyNonTerminal
- Delegation
-)
-
// Operation mode of the LLRB tree.
const mode = bu23
@@ -151,77 +137,32 @@ func (t *Tree) Len() int {
return t.Count
}
-// Search returns the first match of qname/qtype in the Tree.
-func (t *Tree) Search(qname string, qtype uint16) (*Elem, Result) {
- if t.Root == nil {
- return nil, NameError
- }
- n, res := t.Root.search(qname, qtype, false)
- if n == nil {
- return nil, res
- }
- return n.Elem, res
-}
-
-// SearchGlue returns the first match of qname/(A/AAAA) in the Tree.
-func (t *Tree) SearchGlue(qname string) (*Elem, Result) {
- // TODO(miek): shouldn't need this, because when we *find* the delegation, we
- // know for sure that any glue is under it. Should change the return values
- // to return the node, so we can resume from those.
+// Search returns the first match of qname in the Tree.
+func (t *Tree) Search(qname string) (*Elem, bool) {
if t.Root == nil {
- return nil, NameError
+ return nil, false
}
- n, res := t.Root.search(qname, dns.TypeA, true)
+ n, res := t.Root.search(qname)
if n == nil {
return nil, res
}
return n.Elem, res
}
-// search searches the tree for qname and type. If glue is true the search *does* not
-// stop when hitting NS records, but descends in search of glue. The qtype for this
-// kind of search can only be AAAA or A.
-func (n *Node) search(qname string, qtype uint16, glue bool) (*Node, Result) {
- old := n
-
- var wild *Node
-
+// search searches the tree for qname and type.
+func (n *Node) search(qname string) (*Node, bool) {
for n != nil {
-
- // Is this a wildcard that applies to us
- if n.Elem.IsWildcard() {
- if dns.IsSubDomain(n.Elem.Name()[2:], qname) {
- wild = n
- }
- }
-
switch c := Less(n.Elem, qname); {
case c == 0:
- return n, Found
+ return n, true
case c < 0:
- old = n
n = n.Left
default:
- if !glue && n.Elem.Types(dns.TypeNS) != nil {
- return n, Delegation
-
- }
- old = n
n = n.Right
}
}
- // If we have seen a wildcard "on-the-way-to-here", we should return this wildcard
- // instead. This is to be able to have a more specific RR defined *under* the wildcard.
- if wild != nil {
- return wild, Found
- }
-
- if dns.CountLabel(qname) < dns.CountLabel(old.Elem.Name()) {
- return n, EmptyNonTerminal
- }
-
- return n, NameError
+ return n, false
}
// Insert inserts rr into the Tree at the first match found
@@ -233,6 +174,7 @@ func (t *Tree) Insert(rr dns.RR) {
t.Root.Color = black
}
+// insert inserts rr in to the tree.
func (n *Node) insert(rr dns.RR) (root *Node, d int) {
if n == nil {
return &Node{Elem: newElem(rr)}, 1
@@ -339,21 +281,21 @@ func (t *Tree) Delete(rr dns.RR) {
return
}
- el, _ := t.Search(rr.Header().Name, rr.Header().Rrtype)
+ el, _ := t.Search(rr.Header().Name)
if el == nil {
- t.DeleteNode(rr)
+ t.deleteNode(rr)
return
}
// Delete from this element.
empty := el.Delete(rr)
if empty {
- t.DeleteNode(rr)
+ t.deleteNode(rr)
return
}
}
// DeleteNode deletes the node that matches rr according to Less().
-func (t *Tree) DeleteNode(rr dns.RR) {
+func (t *Tree) deleteNode(rr dns.RR) {
if t.Root == nil {
return
}
@@ -427,15 +369,16 @@ func (n *Node) max() *Node {
}
// Prev returns the greatest value equal to or less than the qname according to Less().
-func (t *Tree) Prev(qname string) *Elem {
+func (t *Tree) Prev(qname string) (*Elem, bool) {
if t.Root == nil {
- return nil
+ return nil, false
}
+
n := t.Root.floor(qname)
if n == nil {
- return nil
+ return nil, false
}
- return n.Elem
+ return n.Elem, true
}
func (n *Node) floor(qname string) *Node {
@@ -445,7 +388,7 @@ func (n *Node) floor(qname string) *Node {
switch c := Less(n.Elem, qname); {
case c == 0:
return n
- case c < 0:
+ case c <= 0:
return n.Left.floor(qname)
default:
if r := n.Right.floor(qname); r != nil {
@@ -456,15 +399,15 @@ func (n *Node) floor(qname string) *Node {
}
// Next returns the smallest value equal to or greater than the qname according to Less().
-func (t *Tree) Next(qname string) *Elem {
+func (t *Tree) Next(qname string) (*Elem, bool) {
if t.Root == nil {
- return nil
+ return nil, false
}
n := t.Root.ceil(qname)
if n == nil {
- return nil
+ return nil, false
}
- return n.Elem
+ return n.Elem, true
}
func (n *Node) ceil(qname string) *Node {