1
0
Fork 0

Fix panic when parsing resolv.conf

This commit is contained in:
Ludovic Fernandez 2018-03-02 10:46:04 +01:00 committed by Traefiker Bot
parent f149b56063
commit 9ae808aac4
316 changed files with 37454 additions and 13195 deletions

244
vendor/github.com/miekg/dns/scan.go generated vendored
View file

@ -1,23 +1,14 @@
package dns
import (
"fmt"
"io"
"log"
"os"
"path/filepath"
"strconv"
"strings"
)
type debugging bool
const debug debugging = false
func (d debugging) Printf(format string, args ...interface{}) {
if d {
log.Printf(format, args...)
}
}
const maxTok = 2048 // Largest token we can return.
const maxUint16 = 1<<16 - 1
@ -38,7 +29,7 @@ const (
zOwner
zClass
zDirOrigin // $ORIGIN
zDirTtl // $TTL
zDirTTL // $TTL
zDirInclude // $INCLUDE
zDirGenerate // $GENERATE
@ -51,13 +42,13 @@ const (
zExpectAny // Expect rrtype, ttl or class
zExpectAnyNoClass // Expect rrtype or ttl
zExpectAnyNoClassBl // The whitespace after _EXPECT_ANY_NOCLASS
zExpectAnyNoTtl // Expect rrtype or class
zExpectAnyNoTtlBl // Whitespace after _EXPECT_ANY_NOTTL
zExpectAnyNoTTL // Expect rrtype or class
zExpectAnyNoTTLBl // Whitespace after _EXPECT_ANY_NOTTL
zExpectRrtype // Expect rrtype
zExpectRrtypeBl // Whitespace BEFORE rrtype
zExpectRdata // The first element of the rdata
zExpectDirTtlBl // Space after directive $TTL
zExpectDirTtl // Directive $TTL
zExpectDirTTLBl // Space after directive $TTL
zExpectDirTTL // Directive $TTL
zExpectDirOriginBl // Space after directive $ORIGIN
zExpectDirOrigin // Directive $ORIGIN
zExpectDirIncludeBl // Space after directive $INCLUDE
@ -105,6 +96,12 @@ type Token struct {
Comment string
}
// ttlState describes the state necessary to fill in an omitted RR TTL
type ttlState struct {
ttl uint32 // ttl is the current default TTL
isByDirective bool // isByDirective indicates whether ttl was set by a $TTL directive
}
// NewRR reads the RR contained in the string s. Only the first RR is
// returned. If s contains no RR, return nil with no error. The class
// defaults to IN and TTL defaults to 3600. The full zone file syntax
@ -120,7 +117,8 @@ func NewRR(s string) (RR, error) {
// ReadRR reads the RR contained in q.
// See NewRR for more documentation.
func ReadRR(q io.Reader, filename string) (RR, error) {
r := <-parseZoneHelper(q, ".", filename, 1)
defttl := &ttlState{defaultTtl, false}
r := <-parseZoneHelper(q, ".", filename, defttl, 1)
if r == nil {
return nil, nil
}
@ -132,10 +130,10 @@ func ReadRR(q io.Reader, filename string) (RR, error) {
}
// ParseZone reads a RFC 1035 style zonefile from r. It returns *Tokens on the
// returned channel, which consist out the parsed RR, a potential comment or an error.
// If there is an error the RR is nil. The string file is only used
// returned channel, each consisting of either a parsed RR and optional comment
// or a nil RR and an error. The string file is only used
// in error reporting. The string origin is used as the initial origin, as
// if the file would start with: $ORIGIN origin .
// if the file would start with an $ORIGIN directive.
// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are supported.
// The channel t is closed by ParseZone when the end of r is reached.
//
@ -157,25 +155,37 @@ func ReadRR(q io.Reader, filename string) (RR, error) {
// The text "; this is comment" is returned in Token.Comment. Comments inside the
// RR are discarded. Comments on a line by themselves are discarded too.
func ParseZone(r io.Reader, origin, file string) chan *Token {
return parseZoneHelper(r, origin, file, 10000)
return parseZoneHelper(r, origin, file, nil, 10000)
}
func parseZoneHelper(r io.Reader, origin, file string, chansize int) chan *Token {
func parseZoneHelper(r io.Reader, origin, file string, defttl *ttlState, chansize int) chan *Token {
t := make(chan *Token, chansize)
go parseZone(r, origin, file, t, 0)
go parseZone(r, origin, file, defttl, t, 0)
return t
}
func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
func parseZone(r io.Reader, origin, f string, defttl *ttlState, t chan *Token, include int) {
defer func() {
if include == 0 {
close(t)
}
}()
s := scanInit(r)
s, cancel := scanInit(r)
c := make(chan lex)
// Start the lexer
go zlexer(s, c)
defer func() {
cancel()
// zlexer can send up to three tokens, the next one and possibly 2 remainders.
// Do a non-blocking read.
_, ok := <-c
_, ok = <-c
_, ok = <-c
if !ok {
// too bad
}
}()
// 6 possible beginnings of a line, _ is a space
// 0. zRRTYPE -> all omitted until the rrtype
// 1. zOwner _ zRrtype -> class/ttl omitted
@ -186,18 +196,16 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
// After detecting these, we know the zRrtype so we can jump to functions
// handling the rdata for each of these types.
if origin == "" {
origin = "."
}
origin = Fqdn(origin)
if _, ok := IsDomainName(origin); !ok {
t <- &Token{Error: &ParseError{f, "bad initial origin name", lex{}}}
return
if origin != "" {
origin = Fqdn(origin)
if _, ok := IsDomainName(origin); !ok {
t <- &Token{Error: &ParseError{f, "bad initial origin name", lex{}}}
return
}
}
st := zExpectOwnerDir // initial state
var h RR_Header
var defttl uint32 = defaultTtl
var prevName string
for l := range c {
// Lexer spotted an error already
@ -209,31 +217,25 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
switch st {
case zExpectOwnerDir:
// We can also expect a directive, like $TTL or $ORIGIN
h.Ttl = defttl
if defttl != nil {
h.Ttl = defttl.ttl
}
h.Class = ClassINET
switch l.value {
case zNewline:
st = zExpectOwnerDir
case zOwner:
h.Name = l.token
if l.token[0] == '@' {
h.Name = origin
prevName = h.Name
st = zExpectOwnerBl
break
}
if h.Name[l.length-1] != '.' {
h.Name = appendOrigin(h.Name, origin)
}
_, ok := IsDomainName(l.token)
name, ok := toAbsoluteName(l.token, origin)
if !ok {
t <- &Token{Error: &ParseError{f, "bad owner name", l}}
return
}
h.Name = name
prevName = h.Name
st = zExpectOwnerBl
case zDirTtl:
st = zExpectDirTtlBl
case zDirTTL:
st = zExpectDirTTLBl
case zDirOrigin:
st = zExpectDirOriginBl
case zDirInclude:
@ -252,15 +254,16 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
// Discard, can happen when there is nothing on the
// line except the RR type
case zString:
ttl, ok := stringToTtl(l.token)
ttl, ok := stringToTTL(l.token)
if !ok {
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
return
}
h.Ttl = ttl
// Don't about the defttl, we should take the $TTL value
// defttl = ttl
st = zExpectAnyNoTtlBl
if defttl == nil || !defttl.isByDirective {
defttl = &ttlState{ttl, false}
}
st = zExpectAnyNoTTLBl
default:
t <- &Token{Error: &ParseError{f, "syntax error at beginning", l}}
@ -278,25 +281,16 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
return
}
neworigin := origin // There may be optionally a new origin set after the filename, if not use current one
l := <-c
switch l.value {
switch l := <-c; l.value {
case zBlank:
l := <-c
if l.value == zString {
if _, ok := IsDomainName(l.token); !ok || l.length == 0 || l.err {
name, ok := toAbsoluteName(l.token, origin)
if !ok {
t <- &Token{Error: &ParseError{f, "bad origin name", l}}
return
}
// a new origin is specified.
if l.token[l.length-1] != '.' {
if origin != "." { // Prevent .. endings
neworigin = l.token + "." + origin
} else {
neworigin = l.token + origin
}
} else {
neworigin = l.token
}
neworigin = name
}
case zNewline, zEOF:
// Ok
@ -305,24 +299,32 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
return
}
// Start with the new file
r1, e1 := os.Open(l.token)
includePath := l.token
if !filepath.IsAbs(includePath) {
includePath = filepath.Join(filepath.Dir(f), includePath)
}
r1, e1 := os.Open(includePath)
if e1 != nil {
t <- &Token{Error: &ParseError{f, "failed to open `" + l.token + "'", l}}
msg := fmt.Sprintf("failed to open `%s'", l.token)
if !filepath.IsAbs(l.token) {
msg += fmt.Sprintf(" as `%s'", includePath)
}
t <- &Token{Error: &ParseError{f, msg, l}}
return
}
if include+1 > 7 {
t <- &Token{Error: &ParseError{f, "too deeply nested $INCLUDE", l}}
return
}
parseZone(r1, l.token, neworigin, t, include+1)
parseZone(r1, neworigin, includePath, defttl, t, include+1)
st = zExpectOwnerDir
case zExpectDirTtlBl:
case zExpectDirTTLBl:
if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank after $TTL-directive", l}}
return
}
st = zExpectDirTtl
case zExpectDirTtl:
st = zExpectDirTTL
case zExpectDirTTL:
if l.value != zString {
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
return
@ -331,12 +333,12 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
t <- &Token{Error: e}
return
}
ttl, ok := stringToTtl(l.token)
ttl, ok := stringToTTL(l.token)
if !ok {
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
return
}
defttl = ttl
defttl = &ttlState{ttl, true}
st = zExpectOwnerDir
case zExpectDirOriginBl:
if l.value != zBlank {
@ -352,19 +354,12 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
if e, _ := slurpRemainder(c, f); e != nil {
t <- &Token{Error: e}
}
if _, ok := IsDomainName(l.token); !ok {
name, ok := toAbsoluteName(l.token, origin)
if !ok {
t <- &Token{Error: &ParseError{f, "bad origin name", l}}
return
}
if l.token[l.length-1] != '.' {
if origin != "." { // Prevent .. endings
origin = l.token + "." + origin
} else {
origin = l.token + origin
}
} else {
origin = l.token
}
origin = name
st = zExpectOwnerDir
case zExpectDirGenerateBl:
if l.value != zBlank {
@ -391,20 +386,26 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
case zExpectAny:
switch l.value {
case zRrtpe:
if defttl == nil {
t <- &Token{Error: &ParseError{f, "missing TTL with no previous value", l}}
return
}
h.Rrtype = l.torc
st = zExpectRdata
case zClass:
h.Class = l.torc
st = zExpectAnyNoClassBl
case zString:
ttl, ok := stringToTtl(l.token)
ttl, ok := stringToTTL(l.token)
if !ok {
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
return
}
h.Ttl = ttl
// defttl = ttl // don't set the defttl here
st = zExpectAnyNoTtlBl
if defttl == nil || !defttl.isByDirective {
defttl = &ttlState{ttl, false}
}
st = zExpectAnyNoTTLBl
default:
t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}}
return
@ -415,13 +416,13 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
return
}
st = zExpectAnyNoClass
case zExpectAnyNoTtlBl:
case zExpectAnyNoTTLBl:
if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank before TTL", l}}
return
}
st = zExpectAnyNoTtl
case zExpectAnyNoTtl:
st = zExpectAnyNoTTL
case zExpectAnyNoTTL:
switch l.value {
case zClass:
h.Class = l.torc
@ -436,13 +437,15 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
case zExpectAnyNoClass:
switch l.value {
case zString:
ttl, ok := stringToTtl(l.token)
ttl, ok := stringToTTL(l.token)
if !ok {
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
return
}
h.Ttl = ttl
// defttl = ttl // don't set the def ttl anymore
if defttl == nil || !defttl.isByDirective {
defttl = &ttlState{ttl, false}
}
st = zExpectRrtypeBl
case zRrtpe:
h.Rrtype = l.torc
@ -505,14 +508,12 @@ func zlexer(s *scan, c chan lex) {
if stri >= maxTok {
l.token = "token length insufficient for parsing"
l.err = true
debug.Printf("[%+v]", l.token)
c <- l
return
}
if comi >= maxTok {
l.token = "comment length insufficient for parsing"
l.err = true
debug.Printf("[%+v]", l.token)
c <- l
return
}
@ -547,7 +548,7 @@ func zlexer(s *scan, c chan lex) {
// escape $... start with a \ not a $, so this will work
switch l.tokenUpper {
case "$TTL":
l.value = zDirTtl
l.value = zDirTTL
case "$ORIGIN":
l.value = zDirOrigin
case "$INCLUDE":
@ -555,7 +556,6 @@ func zlexer(s *scan, c chan lex) {
case "$GENERATE":
l.value = zDirGenerate
}
debug.Printf("[7 %+v]", l.token)
c <- l
} else {
l.value = zString
@ -577,6 +577,7 @@ func zlexer(s *scan, c chan lex) {
return
}
l.value = zRrtpe
rrtype = true
l.torc = t
}
}
@ -597,16 +598,14 @@ func zlexer(s *scan, c chan lex) {
}
}
}
debug.Printf("[6 %+v]", l.token)
c <- l
}
stri = 0
// I reverse space stuff here
if !space && !commt {
l.value = zBlank
l.token = " "
l.length = 1
debug.Printf("[5 %+v]", l.token)
c <- l
}
owner = false
@ -629,7 +628,6 @@ func zlexer(s *scan, c chan lex) {
l.token = string(str[:stri])
l.tokenUpper = strings.ToUpper(l.token)
l.length = stri
debug.Printf("[4 %+v]", l.token)
c <- l
stri = 0
}
@ -667,7 +665,6 @@ func zlexer(s *scan, c chan lex) {
l.tokenUpper = l.token
l.length = 1
l.comment = string(com[:comi])
debug.Printf("[3 %+v %+v]", l.token, l.comment)
c <- l
l.comment = ""
comi = 0
@ -693,14 +690,12 @@ func zlexer(s *scan, c chan lex) {
rrtype = true
}
}
debug.Printf("[2 %+v]", l.token)
c <- l
}
l.value = zNewline
l.token = "\n"
l.tokenUpper = l.token
l.length = 1
debug.Printf("[1 %+v]", l.token)
c <- l
stri = 0
commt = false
@ -746,7 +741,6 @@ func zlexer(s *scan, c chan lex) {
l.tokenUpper = strings.ToUpper(l.token)
l.length = stri
debug.Printf("[%+v]", l.token)
c <- l
stri = 0
}
@ -782,7 +776,6 @@ func zlexer(s *scan, c chan lex) {
l.token = "extra closing brace"
l.tokenUpper = l.token
l.err = true
debug.Printf("[%+v]", l.token)
c <- l
return
}
@ -808,7 +801,12 @@ func zlexer(s *scan, c chan lex) {
l.tokenUpper = strings.ToUpper(l.token)
l.length = stri
l.value = zString
debug.Printf("[%+v]", l.token)
c <- l
}
if brace != 0 {
l.token = "unbalanced brace"
l.tokenUpper = l.token
l.err = true
c <- l
}
}
@ -819,8 +817,8 @@ func classToInt(token string) (uint16, bool) {
if len(token) < offset+1 {
return 0, false
}
class, ok := strconv.Atoi(token[offset:])
if ok != nil || class > maxUint16 {
class, err := strconv.ParseUint(token[offset:], 10, 16)
if err != nil {
return 0, false
}
return uint16(class), true
@ -832,15 +830,15 @@ func typeToInt(token string) (uint16, bool) {
if len(token) < offset+1 {
return 0, false
}
typ, ok := strconv.Atoi(token[offset:])
if ok != nil || typ > maxUint16 {
typ, err := strconv.ParseUint(token[offset:], 10, 16)
if err != nil {
return 0, false
}
return uint16(typ), true
}
// Parse things like 2w, 2m, etc, Return the time in seconds.
func stringToTtl(token string) (uint32, bool) {
// stringToTTL parses things like 2w, 2m, etc, and returns the time in seconds.
func stringToTTL(token string) (uint32, bool) {
s := uint32(0)
i := uint32(0)
for _, c := range token {
@ -913,6 +911,34 @@ func stringToCm(token string) (e, m uint8, ok bool) {
return
}
func toAbsoluteName(name, origin string) (absolute string, ok bool) {
// check for an explicit origin reference
if name == "@" {
// require a nonempty origin
if origin == "" {
return "", false
}
return origin, true
}
// require a valid domain name
_, ok = IsDomainName(name)
if !ok || name == "" {
return "", false
}
// check if name is already absolute
if name[len(name)-1] == '.' {
return name, true
}
// require a nonempty origin
if origin == "" {
return "", false
}
return appendOrigin(name, origin), true
}
func appendOrigin(name, origin string) string {
if origin == "." {
return name + origin