aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Miek Gieben <miek@miek.nl> 2016-03-30 14:16:50 +0100
committerGravatar Miek Gieben <miek@miek.nl> 2016-03-30 14:16:50 +0100
commit4a313d67ff6031fec3743ba01e81f4961027ffe8 (patch)
tree71d3ccabe93f09b0ee5a51eea2f91c059a32fcc1
parent1a455f7bc4c24f472e6fd441b2b145047d1325b2 (diff)
parent162dca6eebc2fb95efa9f45490cb083c5713d4ca (diff)
downloadcoredns-4a313d67ff6031fec3743ba01e81f4961027ffe8.tar.gz
coredns-4a313d67ff6031fec3743ba01e81f4961027ffe8.tar.zst
coredns-4a313d67ff6031fec3743ba01e81f4961027ffe8.zip
Merge pull request #61 from miekg/canonical-sorting
Add canonical sorting
-rw-r--r--middleware/canonical.go57
-rw-r--r--middleware/canonical_test.go72
2 files changed, 129 insertions, 0 deletions
diff --git a/middleware/canonical.go b/middleware/canonical.go
new file mode 100644
index 000000000..5d51231c2
--- /dev/null
+++ b/middleware/canonical.go
@@ -0,0 +1,57 @@
+package middleware
+
+import (
+ "bytes"
+
+ "github.com/miekg/dns"
+)
+
+// Less returns <0 when a is less than b, 0 when they are equal and
+// >0 when a is larger than b.
+// The function order names in DNSSEC canonical order.
+//
+// See http://bert-hubert.blogspot.co.uk/2015/10/how-to-do-fast-canonical-ordering-of.html
+// for a blog article on how we do this. And https://tools.ietf.org/html/rfc4034#section-6.1 .
+func Less(a, b string) int {
+ i := 1
+ aj := len(a)
+ bj := len(b)
+ for {
+ ai, _ := dns.PrevLabel(a, i)
+ bi, _ := dns.PrevLabel(b, i)
+ // sadly this []byte will allocate...
+ ab := []byte(a[ai:aj])
+ toLowerAndDDD(ab)
+ bb := []byte(b[bi:bj])
+ toLowerAndDDD(bb)
+
+ res := bytes.Compare(ab, bb)
+ if res != 0 {
+ return res
+ }
+
+ i++
+ aj, bj = ai, bi
+ }
+ return 0
+}
+
+func toLowerAndDDD(b []byte) {
+ lb := len(b)
+ for i := 0; i < lb; i++ {
+ if b[i] >= 'A' && b[i] <= 'Z' {
+ b[i] += 32
+ continue
+ }
+ if i+3 < lb && b[i] == '\\' && isDigit(b[i+1]) && isDigit(b[i+2]) && isDigit(b[i+3]) {
+ b[i] = dddToByte(b[i:])
+ for j := i + 1; j < lb-3; j++ {
+ b[j] = b[j+3]
+ }
+ lb -= 3
+ }
+ }
+}
+
+func isDigit(b byte) bool { return b >= '0' && b <= '9' }
+func dddToByte(s []byte) byte { return byte((s[1]-'0')*100 + (s[2]-'0')*10 + (s[3] - '0')) }
diff --git a/middleware/canonical_test.go b/middleware/canonical_test.go
new file mode 100644
index 000000000..390878a67
--- /dev/null
+++ b/middleware/canonical_test.go
@@ -0,0 +1,72 @@
+package middleware
+
+import (
+ "sort"
+ "testing"
+)
+
+type set []string
+
+func (p set) Len() int { return len(p) }
+func (p set) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+func (p set) Less(i, j int) bool { d := Less(p[i], p[j]); return d <= 0 }
+
+func TestLess(t *testing.T) {
+ tests := []struct {
+ in []string
+ out []string
+ }{
+ {
+ []string{"aaa.powerdns.de", "bbb.powerdns.net.", "xxx.powerdns.com."},
+ []string{"xxx.powerdns.com.", "aaa.powerdns.de", "bbb.powerdns.net."},
+ },
+ {
+ []string{"aaa.POWERDNS.de", "bbb.PoweRdnS.net.", "xxx.powerdns.com."},
+ []string{"xxx.powerdns.com.", "aaa.POWERDNS.de", "bbb.PoweRdnS.net."},
+ },
+ {
+ []string{"aaa.aaaa.aa.", "aa.aaa.a.", "bbb.bbbb.bb."},
+ []string{"aa.aaa.a.", "aaa.aaaa.aa.", "bbb.bbbb.bb."},
+ },
+ {
+ []string{"aaaaa.", "aaa.", "bbb."},
+ []string{"aaa.", "aaaaa.", "bbb."},
+ },
+ {
+ []string{"a.a.a.a.", "a.a.", "a.a.a."},
+ []string{"a.a.", "a.a.a.", "a.a.a.a."},
+ },
+ {
+ []string{"example.", "z.example.", "a.example."},
+ []string{"example.", "a.example.", "z.example."},
+ },
+ {
+ []string{"a.example.", "Z.a.example.", "z.example.", "yljkjljk.a.example.", "\\001.z.example.", "example.", "*.z.example.", "\\200.z.example.", "zABC.a.EXAMPLE."},
+ []string{"example.", "a.example.", "yljkjljk.a.example.", "Z.a.example.", "zABC.a.EXAMPLE.", "z.example.", "\\001.z.example.", "*.z.example.", "\\200.z.example."},
+ },
+ {
+ // RFC3034 example.
+ []string{"a.example.", "Z.a.example.", "z.example.", "yljkjljk.a.example.", "example.", "*.z.example.", "zABC.a.EXAMPLE."},
+ []string{"example.", "a.example.", "yljkjljk.a.example.", "Z.a.example.", "zABC.a.EXAMPLE.", "z.example.", "*.z.example."},
+ },
+ }
+
+Tests:
+ for j, test := range 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])
+ n := ""
+ for k, in := range test.in {
+ if k+1 == len(test.in) {
+ n = "\n"
+ }
+ t.Logf("%s <-> %s\n%s", in, test.out[k], n)
+ }
+ continue Tests
+ }
+
+ }
+ }
+}
Gravatar pre-commit-ci[bot] 1-1/+1 2022-11-14Abort when using Vay Deposition with FDTD (#3515)Gravatar Revathi Jambunathan 3-0/+8 2022-11-14Centralize the multi fab allocation (#3484)Gravatar David Grote 6-262/+326 2022-11-14CI: unbreak macOS (#3521)Gravatar Edoardo Zoni 1-1/+1 2022-11-14Flux injection: move particle only after performing checks (#3519)Gravatar Remi Lehe 2-38/+34 2022-11-12Fix warnings with ceil in BTD code (#3518)Gravatar David Grote 1-2/+2 2022-11-12CI: unbreak macOS (2to3) (#3520)Gravatar Axel Huebl 1-1/+1 2022-11-10Use makeParser function for laser field parsing option (#3517)Gravatar Neïl Zaim 6-33/+4 2022-11-10Vay Deposition: Filter D, Exchange Guard Cells of J (#3388)Gravatar Edoardo Zoni 2-2/+14 2022-11-092D/RZ Embedded Boundaries Bug Fix (#3510)Gravatar Edoardo Zoni 1-1/+12 2022-11-09BTD: remove old/legacy back-transformed diagnostics (#3485)Gravatar Remi Lehe 29-2671/+85 2022-11-08Docs: Improve MPI Threading User FAQ (#3501)Gravatar Axel Huebl 1-5/+16 2022-11-07Allow `None` for Maxwell solver (#3504)Gravatar Roelof Groenewald 39-195/+199 2022-11-07Load balancing bug fix: remake MultiFabs for Vay deposition, current centerin...Gravatar Revathi Jambunathan 1-2/+15 2022-11-07AMReX: Weekly Update (#3509)Gravatar Axel Huebl 5-5/+5 2022-11-04Clean Species Physical Properties (#3505)Gravatar Neïl Zaim 2-5/+7