dns/labels.go

146 lines
3.0 KiB
Go
Raw Normal View History

2013-05-13 00:15:52 +10:00
// Copyright 2011 Miek Gieben. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
2012-01-11 01:55:52 +11:00
package dns
// Holds a bunch of helper functions for dealing with labels.
// SplitLabels splits a domainname string into its labels.
// www.miek.nl. returns []string{"www", "miek", "nl"}
2012-02-15 08:43:04 +11:00
// The root label (.) returns nil.
2012-01-11 01:55:52 +11:00
func SplitLabels(s string) []string {
2013-06-21 06:36:13 +10:00
// TODO(miek): make this use Split
2012-02-24 05:37:08 +11:00
if s == "." {
return nil
}
2012-02-15 08:26:18 +11:00
2012-01-11 01:55:52 +11:00
k := 0
labels := make([]string, 0)
2012-01-28 10:35:37 +11:00
last := byte('.')
lastlast := byte('.')
s = Fqdn(s) // Make fully qualified
2012-01-11 01:55:52 +11:00
for i := 0; i < len(s); i++ {
if s[i] == '.' {
2012-01-28 10:35:37 +11:00
if last == '\\' {
if lastlast != '\\' {
// do nothing
continue
}
2012-01-11 01:55:52 +11:00
}
labels = append(labels, s[k:i])
2012-01-11 01:55:52 +11:00
k = i + 1 // + dot
}
2012-01-28 10:35:37 +11:00
lastlast = last
last = s[i]
2012-01-11 01:55:52 +11:00
}
return labels
}
2013-06-21 06:36:13 +10:00
// CompareLabels compares the names s1 and s2 and
2012-01-11 02:04:32 +11:00
// returns how many labels they have in common starting from the right.
2012-09-05 04:08:55 +10:00
// The comparison stops at the first inequality. The labels are not downcased
// before the comparison.
2012-01-11 02:04:32 +11:00
//
// www.miek.nl. and miek.nl. have two labels in common: miek and nl
// www.miek.nl. and www.bla.nl. have one label in common: nl
2012-01-11 01:55:52 +11:00
func CompareLabels(s1, s2 string) (n int) {
2013-06-21 06:36:13 +10:00
s1 = Fqdn(s1)
s2 = Fqdn(s2)
l1 := Split(s1)
l2 := Split(s2)
2012-01-11 01:55:52 +11:00
2013-06-21 06:36:13 +10:00
// the first check
if l1 == nil || l2 == nil {
return
}
j1 := len(l1) - 1 // end
i1 := len(l1) - 2 // start
j2 := len(l2) - 1
i2 := len(l2) - 2
// the second check can be done here, before we fall through into the for-loop below
if s1[l1[j1]:] == s2[l2[j2]:] {
n++
} else {
return
}
2012-01-11 01:55:52 +11:00
for {
2013-06-21 06:36:13 +10:00
if i1 < 0 || i2 < 0 {
break
}
2013-06-21 06:36:13 +10:00
if s1[l1[i1]:l1[j1]] == s2[l2[i2]:l2[j2]] {
n++
} else {
break
}
2013-06-21 06:36:13 +10:00
j1--
i1--
j2--
i2--
}
return
}
2013-06-21 06:36:13 +10:00
// LenLabels returns the number of labels in the string s
func LenLabels(s string) (labels int) {
if s == "." {
return
}
2013-06-21 06:36:13 +10:00
s = Fqdn(s) // TODO(miek): annoyed I need this
off := 0
end := false
for {
off, end = nextLabel(s, off)
labels++
if end {
return
}
}
2013-06-21 06:36:13 +10:00
}
2013-06-21 06:36:13 +10:00
// Split splits a name s into its label indexes.
// www.miek.nl. returns []int{0, 4, 9}. The root name (.) returns nil.
func Split(s string) []int {
if s == "." {
2013-06-21 06:36:13 +10:00
return nil
}
2013-06-21 06:36:13 +10:00
s = Fqdn(s) // Grrr!
idx := []int{0} // TODO(miek): could allocate more (10) and then extend when needed
off := 0
end := false
2013-06-21 06:36:13 +10:00
for {
2013-06-21 06:36:13 +10:00
off, end = nextLabel(s, off)
if end {
2013-06-21 06:36:13 +10:00
return idx
}
2013-06-21 06:36:13 +10:00
idx = append(idx, off)
}
}
2013-06-21 06:36:13 +10:00
// nextLabel returns the index of the start of the next label in the
// string s. The bool end is true when the end of the string has been
// reached.
func nextLabel(s string, offset int) (i int, end bool) {
2013-06-21 06:36:13 +10:00
// The other label function are quite generous with memory,
// this one does not allocate.
quote := false
2013-06-21 06:36:13 +10:00
for i = offset; i < len(s)-1; i++ {
switch s[i] {
case '\\':
quote = !quote
default:
quote = false
case '.':
if quote {
quote = !quote
continue
}
2013-06-21 06:36:13 +10:00
return i + 1, false
}
}
2013-06-21 06:36:13 +10:00
return i + 1, true
}