Updated code to handle escapes in TXT RDATA

Added test demonstrating error in TXT parsing.
Fixed lexing process and slightly updated conversion
back to strings.

See #126 for details.
This commit is contained in:
Alex Sergeyev 2014-09-10 15:56:23 -04:00
parent b6da65c4b0
commit ae7d973e40
3 changed files with 70 additions and 27 deletions

View File

@ -137,6 +137,39 @@ func TestDomainNameAndTXTEscapes(t *testing.T) {
} }
} }
func TestTXTEscapeParsing(t *testing.T) {
test := [][]string{
{`";"`, `";"`},
{`\;`, `";"`},
{`"\t"`, `"\t"`},
{`"\r"`, `"\r"`},
{`"\ "`, `" "`},
{`"\;"`, `";"`},
{`"\;\""`, `";\""`},
{`"\(a\)"`, `"(a)"`},
{`"\(a)"`, `"(a)"`},
{`"(a\)"`, `"(a)"`},
{`"(a)"`, `"(a)"`},
{`"\048"`, `"0"`},
{`"\` + "\n" + `"`, `"\n"`},
{`"\` + "\r" + `"`, `"\r"`},
{`"\` + "\x11" + `"`, `"\017"`},
{`"\'"`, `"'"`},
}
for _, s := range test {
rr, err := NewRR(fmt.Sprintf("example.com. IN TXT %v", s[0]))
if err != nil {
t.Errorf("Could not parse %v TXT: %s", s[0], err)
continue
}
txt := sprintTxt(rr.(*TXT).Txt)
if txt != s[1] {
t.Errorf("Mismatch after parsing `%v` TXT record: `%v` != `%v`", s[0], txt, s[1])
}
}
}
func GenerateDomain(r *rand.Rand, size int) []byte { func GenerateDomain(r *rand.Rand, size int) []byte {
dnLen := size % 70 // artificially limit size so there's less to intrepret if a failure occurs dnLen := size % 70 // artificially limit size so there's less to intrepret if a failure occurs
var dn []byte var dn []byte

View File

@ -482,24 +482,25 @@ func sprintTxt(txt []string) string {
} }
func appendDomainNameByte(s []byte, b byte) []byte { func appendDomainNameByte(s []byte, b byte) []byte {
if b == '.' || b == '(' || b == ')' || b == ';' || b == ' ' || b == '\'' || b == '@' { switch b {
case '.', ' ', '\'', '@', ';', '(', ')': // additional chars to escape
return append(s, '\\', b) return append(s, '\\', b)
} }
return appendTXTStringByte(s, b) return appendTXTStringByte(s, b)
} }
func appendTXTStringByte(s []byte, b byte) []byte { func appendTXTStringByte(s []byte, b byte) []byte {
if b == '"' { switch b {
return append(s, `\"`...) case '\t':
} else if b == '\\' { return append(s, '\\', 't')
return append(s, `\\`...) case '\r':
} else if b == '\t' { return append(s, '\\', 'r')
return append(s, `\t`...) case '\n':
} else if b == '\r' { return append(s, '\\', 'n')
return append(s, `\r`...) case '"', '\\':
} else if b == '\n' { return append(s, '\\', b)
return append(s, `\n`...) }
} else if b < ' ' || b > '~' { if b < ' ' || b > '~' {
return append(s, fmt.Sprintf("\\%03d", b)...) return append(s, fmt.Sprintf("\\%03d", b)...)
} }
return append(s, b) return append(s, b)

View File

@ -525,7 +525,6 @@ func zlexer(s *scan, c chan lex) {
stri++ stri++
break break
} }
escape = false
if commt { if commt {
com[comi] = x com[comi] = x
comi++ comi++
@ -607,14 +606,14 @@ func zlexer(s *scan, c chan lex) {
owner = false owner = false
space = true space = true
case ';': case ';':
if quote { if escape {
// Inside quotes this is legal escape = false
str[stri] = x str[stri] = x
stri++ stri++
break break
} }
if escape { if quote {
escape = false // Inside quotes this is legal
str[stri] = x str[stri] = x
stri++ stri++
break break
@ -631,9 +630,15 @@ func zlexer(s *scan, c chan lex) {
com[comi] = ';' com[comi] = ';'
comi++ comi++
case '\r': case '\r':
// discard escape = false
// this means it can also not be used as rdata if quote {
str[stri] = x
stri++
break
}
// discard if outside of quotes
case '\n': case '\n':
escape = false
// Escaped newline // Escaped newline
if quote { if quote {
str[stri] = x str[stri] = x
@ -641,7 +646,6 @@ func zlexer(s *scan, c chan lex) {
break break
} }
// inside quotes this is legal // inside quotes this is legal
escape = false
if commt { if commt {
// Reset a comment // Reset a comment
commt = false commt = false
@ -696,18 +700,20 @@ func zlexer(s *scan, c chan lex) {
comi = 0 comi = 0
} }
case '\\': case '\\':
// quote? // comments do not get escaped chars, everything is copied
if commt { if commt {
com[comi] = x com[comi] = x
comi++ comi++
break break
} }
// something already escaped must be in string
if escape { if escape {
str[stri] = x str[stri] = x
stri++ stri++
escape = false escape = false
break break
} }
// something escaped outside of string gets added to string
str[stri] = x str[stri] = x
stri++ stri++
escape = true escape = true
@ -729,21 +735,19 @@ func zlexer(s *scan, c chan lex) {
l.value = _STRING l.value = _STRING
l.token = string(str[:stri]) l.token = string(str[:stri])
l.length = stri l.length = stri
debug.Printf("[%+v]", l.token) debug.Printf("[%+v]", l.token)
c <- l c <- l
stri = 0 stri = 0
} }
// send quote itself as separate token
l.value = _QUOTE l.value = _QUOTE
l.token = "\"" l.token = "\""
l.length = 1 l.length = 1
c <- l c <- l
quote = !quote quote = !quote
case '(', ')': case '(', ')':
if quote {
str[stri] = x
stri++
break
}
if commt { if commt {
com[comi] = x com[comi] = x
comi++ comi++
@ -755,6 +759,11 @@ func zlexer(s *scan, c chan lex) {
escape = false escape = false
break break
} }
if quote {
str[stri] = x
stri++
break
}
switch x { switch x {
case ')': case ')':
brace-- brace--
@ -769,12 +778,12 @@ func zlexer(s *scan, c chan lex) {
brace++ brace++
} }
default: default:
escape = false
if commt { if commt {
com[comi] = x com[comi] = x
comi++ comi++
break break
} }
escape = false
str[stri] = x str[stri] = x
stri++ stri++
space = false space = false