Correctly parse omitted TTLs and relative domains (#513)
* Fix $TTL handling * Error when there is no TTL for an RR * Fix relative name handling * Error when a relative name is used without an origin (cf. https://tools.ietf.org/html/rfc1035#section-5.1 ) Fixes #484master
parent
689d334b01
commit
eccf8bbe83
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// AddDomain adds origin to s if s is not already a FQDN.
|
||||
// AddOrigin adds origin to s if s is not already a FQDN.
|
||||
// Note that the result may not be a FQDN. If origin does not end
|
||||
// with a ".", the result won't either.
|
||||
// This implements the zonefile convention (specified in RFC 1035,
|
||||
|
|
4
doc.go
4
doc.go
|
@ -22,9 +22,9 @@ Or directly from a string:
|
|||
|
||||
mx, err := dns.NewRR("miek.nl. 3600 IN MX 10 mx.miek.nl.")
|
||||
|
||||
Or when the default TTL (3600) and class (IN) suit you:
|
||||
Or when the default origin (.) and TTL (3600) and class (IN) suit you:
|
||||
|
||||
mx, err := dns.NewRR("miek.nl. MX 10 mx.miek.nl.")
|
||||
mx, err := dns.NewRR("miek.nl MX 10 mx.miek.nl")
|
||||
|
||||
Or even:
|
||||
|
||||
|
|
188
parse_test.go
188
parse_test.go
|
@ -8,6 +8,7 @@ import (
|
|||
"math/rand"
|
||||
"net"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -571,81 +572,88 @@ test IN CNAME test.a.example.com.
|
|||
t.Logf("%d RRs parsed in %.2f s (%.2f RR/s)", i, float32(delta)/1e9, float32(i)/(float32(delta)/1e9))
|
||||
}
|
||||
|
||||
func ExampleParseZone() {
|
||||
zone := `$ORIGIN .
|
||||
$TTL 3600 ; 1 hour
|
||||
name IN SOA a6.nstld.com. hostmaster.nic.name. (
|
||||
203362132 ; serial
|
||||
300 ; refresh (5 minutes)
|
||||
300 ; retry (5 minutes)
|
||||
1209600 ; expire (2 weeks)
|
||||
300 ; minimum (5 minutes)
|
||||
)
|
||||
$TTL 10800 ; 3 hours
|
||||
name. 10800 IN NS name.
|
||||
IN NS g6.nstld.com.
|
||||
7200 NS h6.nstld.com.
|
||||
3600 IN NS j6.nstld.com.
|
||||
IN 3600 NS k6.nstld.com.
|
||||
NS l6.nstld.com.
|
||||
NS a6.nstld.com.
|
||||
NS c6.nstld.com.
|
||||
NS d6.nstld.com.
|
||||
NS f6.nstld.com.
|
||||
NS m6.nstld.com.
|
||||
(
|
||||
NS m7.nstld.com.
|
||||
)
|
||||
$ORIGIN name.
|
||||
0-0onlus NS ns7.ehiweb.it.
|
||||
NS ns8.ehiweb.it.
|
||||
0-g MX 10 mx01.nic
|
||||
MX 10 mx02.nic
|
||||
MX 10 mx03.nic
|
||||
MX 10 mx04.nic
|
||||
$ORIGIN 0-g.name
|
||||
moutamassey NS ns01.yahoodomains.jp.
|
||||
NS ns02.yahoodomains.jp.
|
||||
func TestOmittedTTL(t *testing.T) {
|
||||
zone := `
|
||||
$ORIGIN example.com.
|
||||
example.com. 42 IN SOA ns1.example.com. hostmaster.example.com. 1 86400 60 86400 3600 ; TTL=42 SOA
|
||||
example.com. NS 2 ; TTL=42 absolute owner name
|
||||
@ MD 3 ; TTL=42 current-origin owner name
|
||||
MF 4 ; TTL=42 leading-space implied owner name
|
||||
43 TYPE65280 \# 1 05 ; TTL=43 implied owner name explicit TTL
|
||||
MB 6 ; TTL=43 leading-tab implied owner name
|
||||
$TTL 1337
|
||||
example.com. 88 MG 7 ; TTL=88 explicit TTL
|
||||
example.com. MR 8 ; TTL=1337 after first $TTL
|
||||
$TTL 314
|
||||
1 TXT 9 ; TTL=1 implied owner name explicit TTL
|
||||
example.com. DNAME 10 ; TTL=314 after second $TTL
|
||||
`
|
||||
to := ParseZone(strings.NewReader(zone), "", "testzone")
|
||||
for x := range to {
|
||||
fmt.Println(x.RR)
|
||||
reCaseFromComment := regexp.MustCompile(`TTL=(\d+)\s+(.*)`)
|
||||
records := ParseZone(strings.NewReader(zone), "", "")
|
||||
var i int
|
||||
for record := range records {
|
||||
i++
|
||||
if record.Error != nil {
|
||||
t.Error(record.Error)
|
||||
continue
|
||||
}
|
||||
expected := reCaseFromComment.FindStringSubmatch(record.Comment)
|
||||
expectedTTL, _ := strconv.ParseUint(expected[1], 10, 32)
|
||||
ttl := record.RR.Header().Ttl
|
||||
if ttl != uint32(expectedTTL) {
|
||||
t.Errorf("%s: expected TTL %d, got %d", expected[2], expectedTTL, ttl)
|
||||
}
|
||||
}
|
||||
if i != 10 {
|
||||
t.Errorf("expected %d records, got %d", 5, i)
|
||||
}
|
||||
// Output:
|
||||
// name. 3600 IN SOA a6.nstld.com. hostmaster.nic.name. 203362132 300 300 1209600 300
|
||||
// name. 10800 IN NS name.
|
||||
// name. 10800 IN NS g6.nstld.com.
|
||||
// name. 7200 IN NS h6.nstld.com.
|
||||
// name. 3600 IN NS j6.nstld.com.
|
||||
// name. 3600 IN NS k6.nstld.com.
|
||||
// name. 10800 IN NS l6.nstld.com.
|
||||
// name. 10800 IN NS a6.nstld.com.
|
||||
// name. 10800 IN NS c6.nstld.com.
|
||||
// name. 10800 IN NS d6.nstld.com.
|
||||
// name. 10800 IN NS f6.nstld.com.
|
||||
// name. 10800 IN NS m6.nstld.com.
|
||||
// name. 10800 IN NS m7.nstld.com.
|
||||
// 0-0onlus.name. 10800 IN NS ns7.ehiweb.it.
|
||||
// 0-0onlus.name. 10800 IN NS ns8.ehiweb.it.
|
||||
// 0-g.name. 10800 IN MX 10 mx01.nic.name.
|
||||
// 0-g.name. 10800 IN MX 10 mx02.nic.name.
|
||||
// 0-g.name. 10800 IN MX 10 mx03.nic.name.
|
||||
// 0-g.name. 10800 IN MX 10 mx04.nic.name.
|
||||
// moutamassey.0-g.name.name. 10800 IN NS ns01.yahoodomains.jp.
|
||||
// moutamassey.0-g.name.name. 10800 IN NS ns02.yahoodomains.jp.
|
||||
}
|
||||
|
||||
func ExampleHIP() {
|
||||
h := `www.example.com IN HIP ( 2 200100107B1A74DF365639CC39F1D578
|
||||
AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p
|
||||
9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQ
|
||||
b1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D
|
||||
rvs.example.com. )`
|
||||
if hip, err := NewRR(h); err == nil {
|
||||
fmt.Println(hip.String())
|
||||
func TestRelativeNameErrors(t *testing.T) {
|
||||
var badZones = []struct {
|
||||
label string
|
||||
zoneContents string
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
"relative owner name without origin",
|
||||
"example.com 3600 IN SOA ns.example.com. hostmaster.example.com. 1 86400 60 86400 3600",
|
||||
"bad owner name",
|
||||
},
|
||||
{
|
||||
"relative owner name in RDATA",
|
||||
"example.com. 3600 IN SOA ns hostmaster 1 86400 60 86400 3600",
|
||||
"bad SOA Ns",
|
||||
},
|
||||
{
|
||||
"origin reference without origin",
|
||||
"@ 3600 IN SOA ns.example.com. hostmaster.example.com. 1 86400 60 86400 3600",
|
||||
"bad owner name",
|
||||
},
|
||||
{
|
||||
"relative owner name in $INCLUDE",
|
||||
"$INCLUDE file.db example.com",
|
||||
"bad origin name",
|
||||
},
|
||||
{
|
||||
"relative owner name in $ORIGIN",
|
||||
"$ORIGIN example.com",
|
||||
"bad origin name",
|
||||
},
|
||||
}
|
||||
for _, errorCase := range badZones {
|
||||
entries := ParseZone(strings.NewReader(errorCase.zoneContents), "", "")
|
||||
for entry := range entries {
|
||||
if entry.Error == nil {
|
||||
t.Errorf("%s: expected error, got nil", errorCase.label)
|
||||
continue
|
||||
}
|
||||
err := entry.Error.err
|
||||
if err != errorCase.expectedErr {
|
||||
t.Errorf("%s: expected error `%s`, got `%s`", errorCase.label, errorCase.expectedErr, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Output:
|
||||
// www.example.com. 3600 IN HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs.example.com.
|
||||
}
|
||||
|
||||
func TestHIP(t *testing.T) {
|
||||
|
@ -686,24 +694,6 @@ b1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D
|
|||
}
|
||||
}
|
||||
|
||||
func ExampleSOA() {
|
||||
s := "example.com. 1000 SOA master.example.com. admin.example.com. 1 4294967294 4294967293 4294967295 100"
|
||||
if soa, err := NewRR(s); err == nil {
|
||||
fmt.Println(soa.String())
|
||||
}
|
||||
// Output:
|
||||
// example.com. 1000 IN SOA master.example.com. admin.example.com. 1 4294967294 4294967293 4294967295 100
|
||||
}
|
||||
|
||||
func TestLineNumberError(t *testing.T) {
|
||||
s := "example.com. 1000 SOA master.example.com. admin.example.com. monkey 4294967294 4294967293 4294967295 100"
|
||||
if _, err := NewRR(s); err != nil {
|
||||
if err.Error() != "dns: bad SOA zone parameter: \"monkey\" at line: 1:68" {
|
||||
t.Error("not expecting this error: ", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test with no known RR on the line
|
||||
func TestLineNumberError2(t *testing.T) {
|
||||
tests := map[string]string{
|
||||
|
@ -801,28 +791,6 @@ func TestLowercaseTokens(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func ExampleParseZone_generate() {
|
||||
// From the manual: http://www.bind9.net/manual/bind/9.3.2/Bv9ARM.ch06.html#id2566761
|
||||
zone := "$GENERATE 1-2 0 NS SERVER$.EXAMPLE.\n$GENERATE 1-8 $ CNAME $.0"
|
||||
to := ParseZone(strings.NewReader(zone), "0.0.192.IN-ADDR.ARPA.", "")
|
||||
for x := range to {
|
||||
if x.Error == nil {
|
||||
fmt.Println(x.RR.String())
|
||||
}
|
||||
}
|
||||
// Output:
|
||||
// 0.0.0.192.IN-ADDR.ARPA. 3600 IN NS SERVER1.EXAMPLE.
|
||||
// 0.0.0.192.IN-ADDR.ARPA. 3600 IN NS SERVER2.EXAMPLE.
|
||||
// 1.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 1.0.0.0.192.IN-ADDR.ARPA.
|
||||
// 2.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 2.0.0.0.192.IN-ADDR.ARPA.
|
||||
// 3.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 3.0.0.0.192.IN-ADDR.ARPA.
|
||||
// 4.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 4.0.0.0.192.IN-ADDR.ARPA.
|
||||
// 5.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 5.0.0.0.192.IN-ADDR.ARPA.
|
||||
// 6.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 6.0.0.0.192.IN-ADDR.ARPA.
|
||||
// 7.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 7.0.0.0.192.IN-ADDR.ARPA.
|
||||
// 8.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 8.0.0.0.192.IN-ADDR.ARPA.
|
||||
}
|
||||
|
||||
func TestSRVPacking(t *testing.T) {
|
||||
msg := Msg{}
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ func (rd *VERSION) Len() int {
|
|||
}
|
||||
|
||||
var smallzone = `$ORIGIN example.org.
|
||||
@ SOA sns.dns.icann.org. noc.dns.icann.org. (
|
||||
@ 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. (
|
||||
2014091518 7200 3600 1209600 3600
|
||||
)
|
||||
A 1.2.3.4
|
||||
|
|
129
scan.go
129
scan.go
|
@ -105,6 +105,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 +126,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, ".", defttl, filename, 1)
|
||||
if r == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -132,10 +139,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,16 +164,16 @@ 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, nil, file, 10000)
|
||||
}
|
||||
|
||||
func parseZoneHelper(r io.Reader, origin, file string, chansize int) chan *Token {
|
||||
func parseZoneHelper(r io.Reader, origin string, defttl *ttlState, file string, chansize int) chan *Token {
|
||||
t := make(chan *Token, chansize)
|
||||
go parseZone(r, origin, file, t, 0)
|
||||
go parseZone(r, origin, defttl, file, t, 0)
|
||||
return t
|
||||
}
|
||||
|
||||
func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
||||
func parseZone(r io.Reader, origin string, defttl *ttlState, f string, t chan *Token, include int) {
|
||||
defer func() {
|
||||
if include == 0 {
|
||||
close(t)
|
||||
|
@ -186,18 +193,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,27 +214,21 @@ 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:
|
||||
|
@ -258,8 +257,9 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
|||
return
|
||||
}
|
||||
h.Ttl = ttl
|
||||
// Don't about the defttl, we should take the $TTL value
|
||||
// defttl = ttl
|
||||
if defttl == nil || !defttl.isByDirective {
|
||||
defttl = &ttlState{ttl, false}
|
||||
}
|
||||
st = zExpectAnyNoTtlBl
|
||||
|
||||
default:
|
||||
|
@ -282,20 +282,12 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
|||
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
|
||||
|
@ -313,7 +305,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
|||
t <- &Token{Error: &ParseError{f, "too deeply nested $INCLUDE", l}}
|
||||
return
|
||||
}
|
||||
parseZone(r1, neworigin, l.token, t, include+1)
|
||||
parseZone(r1, neworigin, defttl, l.token, t, include+1)
|
||||
st = zExpectOwnerDir
|
||||
case zExpectDirTtlBl:
|
||||
if l.value != zBlank {
|
||||
|
@ -335,7 +327,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
|||
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 {
|
||||
|
@ -351,19 +343,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 {
|
||||
|
@ -390,6 +375,10 @@ 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:
|
||||
|
@ -402,7 +391,9 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
|||
return
|
||||
}
|
||||
h.Ttl = ttl
|
||||
// defttl = ttl // don't set the defttl here
|
||||
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}}
|
||||
|
@ -441,7 +432,9 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
|||
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
|
||||
|
@ -918,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
|
||||
|
|
592
scan_rr.go
592
scan_rr.go
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue