Merge branch 'master' of github.com:miekg/dns

This commit is contained in:
Miek Gieben 2013-09-11 08:22:23 +01:00
commit ee8ace0477
14 changed files with 156 additions and 181 deletions

View File

@ -1,10 +1,6 @@
# TODO # TODO
* Support for on-the-fly-signing or check how to do it * Support for on-the-fly-signing or check how to do it
* Test all rdata packing with zero rdata -- allowed for dynamic updates
* Actually mimic net/ ? Dial. Read/Write ?
- if I want this i need to work on something else than \*Client, because a single client
can have multiple oustanding qeuries
* Ratelimiting? server side (rrl) * Ratelimiting? server side (rrl)
* Ratelimiting? client side * Ratelimiting? client side

View File

@ -31,16 +31,16 @@ type reply struct {
// A Client defines parameter for a DNS client. A nil // A Client defines parameter for a DNS client. A nil
// Client is usable for sending queries. // Client is usable for sending queries.
type Client struct { type Client struct {
Net string // if "tcp" a TCP query will be initiated, otherwise an UDP one (default is "" for UDP) Net string // if "tcp" a TCP query will be initiated, otherwise an UDP one (default is "" for UDP)
ReadTimeout time.Duration // the net.Conn.SetReadTimeout value for new connections (ns), defaults to 2 * 1e9 ReadTimeout time.Duration // the net.Conn.SetReadTimeout value for new connections (ns), defaults to 2 * 1e9
WriteTimeout time.Duration // the net.Conn.SetWriteTimeout value for new connections (ns), defaults to 2 * 1e9 WriteTimeout time.Duration // the net.Conn.SetWriteTimeout value for new connections (ns), defaults to 2 * 1e9
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
Inflight bool // if true suppress multiple outstanding queries for the same Qname, Qtype and Qclass SingleInflight bool // if true suppress multiple outstanding queries for the same Qname, Qtype and Qclass
group singleflight group singleflight
} }
func (c *Client) exchangeMerge(m *Msg, a string, s net.Conn) (r *Msg, rtt time.Duration, err error) { func (c *Client) exchangeMerge(m *Msg, a string, s net.Conn) (r *Msg, rtt time.Duration, err error) {
if !c.Inflight { if !c.SingleInflight {
if s == nil { if s == nil {
return c.exchange(m, a) return c.exchange(m, a)
} }

View File

@ -41,12 +41,12 @@ func TestClientEDNS0(t *testing.T) {
} }
} }
func TestInflight(t *testing.T) { func TestSingleSingleInflight(t *testing.T) {
m := new(Msg) m := new(Msg)
m.SetQuestion("miek.nl.", TypeDNSKEY) m.SetQuestion("miek.nl.", TypeDNSKEY)
c := new(Client) c := new(Client)
c.Inflight = true c.SingleInflight = true
nr := 10 nr := 10
ch := make(chan time.Duration) ch := make(chan time.Duration)
for i := 0; i < nr; i++ { for i := 0; i < nr; i++ {

View File

@ -156,76 +156,13 @@ func (dns *Msg) IsEdns0() *OPT {
} }
// IsDomainName checks if s is a valid domainname, it returns // IsDomainName checks if s is a valid domainname, it returns
// the number of labels, total length and true, when a domain name is valid. // the number of labels and true, when a domain name is valid.
// Note that unfully qualified domain name is considered valid, in this case the // Note that non fully qualified domain name is considered valid, in this case the
// last label is counted in the number of labels. // last label is counted in the number of labels.
// When false is returned the labelcount and length are not defined. // When false is returned the number of labels is not defined.
func IsDomainName(s string) (uint8, uint8, bool) { // copied from net package. func IsDomainName(s string) (labels int, ok bool) {
// See RFC 1035, RFC 3696. _, labels, err := packDomainName(s, nil, 0, nil, false)
l := len(s) return labels, err == nil
if l == 0 || l > 255 {
return 0, 0, false
}
// Preloop check for root label
if s == "." {
return 0, 1, true
}
last := byte('.')
ok := false // Ok once we've seen a letter or digit.
partlen := 0
labels := uint8(0)
var c byte
for i := 0; i < l; i++ {
c = s[i]
switch {
default:
// anything escaped is legal
if last != '\\' {
return 0, uint8(l), false
}
partlen++
case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_' || c == '*' || c == '/':
ok = true
partlen++
case c == '\\': // OK.
case c == '@':
if last != '\\' {
return 0, uint8(l), false
}
partlen++
case '0' <= c && c <= '9':
ok = true
partlen++
case c == '-':
if last == '.' {
return 0, uint8(l), false
}
partlen++
case c == '.':
// byte before dot cannot be dot
if last == '.' {
return 0, uint8(l), false
}
if last == '\\' { // Ok, escaped dot.
partlen++
c = 'A' // Make current value not scary.
break
}
if partlen > 63 || partlen == 0 {
return 0, uint8(l), false
}
partlen = 0
labels++
}
last = c
}
// If last isn't a dot, the name was unqualified, but we still want to count
// the last label.
if last == '.' {
return labels, uint8(l), ok
}
return labels + 1, uint8(l), ok
} }
// IsSubDomain checks if child is indeed a child of the parent. Both child and // IsSubDomain checks if child is indeed a child of the parent. Both child and
@ -253,7 +190,7 @@ func Fqdn(s string) string {
return s + "." return s + "."
} }
// Copied from the official Go code // Copied from the official Go code.
// ReverseAddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP // ReverseAddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
// address addr suitable for rDNS (PTR) record lookup or an error if it fails // address addr suitable for rDNS (PTR) record lookup or an error if it fails

5
dns.go
View File

@ -61,7 +61,10 @@
// c := new(Client) // c := new(Client)
// in, rtt, err := c.Exchange(m1, "127.0.0.1:53") // in, rtt, err := c.Exchange(m1, "127.0.0.1:53")
// //
// For asynchronous queries it is easy to wrap Exchange() in a goroutine. // For asynchronous queries it is easy to wrap Exchange() in a goroutine. Suppressing
// multiple outstanding queries (with the same question, type and class) is as easy as setting:
//
// c.SingleInflight = true
// //
// A dns message consists out of four sections. // A dns message consists out of four sections.
// The question section: in.Question, the answer section: in.Answer, // The question section: in.Question, the answer section: in.Answer,

View File

@ -220,7 +220,7 @@ func (rr *RRSIG) Sign(k PrivateKey, rrset []RR) error {
rr.OrigTtl = rrset[0].Header().Ttl rr.OrigTtl = rrset[0].Header().Ttl
rr.TypeCovered = rrset[0].Header().Rrtype rr.TypeCovered = rrset[0].Header().Rrtype
rr.TypeCovered = rrset[0].Header().Rrtype rr.TypeCovered = rrset[0].Header().Rrtype
rr.Labels, _, _ = IsDomainName(rrset[0].Header().Name) rr.Labels = uint8(CountLabel(rrset[0].Header().Name))
if strings.HasPrefix(rrset[0].Header().Name, "*") { if strings.HasPrefix(rrset[0].Header().Name, "*") {
rr.Labels-- // wildcard, remove from label count rr.Labels-- // wildcard, remove from label count

View File

@ -174,7 +174,7 @@ func TestSignVerify(t *testing.T) {
sig := new(RRSIG) sig := new(RRSIG)
sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0} sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0}
sig.TypeCovered = soa.Hdr.Rrtype sig.TypeCovered = soa.Hdr.Rrtype
sig.Labels, _, _ = IsDomainName(soa.Hdr.Name) sig.Labels = uint8(CountLabel(soa.Hdr.Name))
sig.OrigTtl = soa.Hdr.Ttl sig.OrigTtl = soa.Hdr.Ttl
sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05" sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05" sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05"

View File

@ -95,20 +95,21 @@ domainLoop:
func TestIsDomainName(t *testing.T) { func TestIsDomainName(t *testing.T) {
type ret struct { type ret struct {
ok bool ok bool
lab uint8 lab int
l uint8
} }
names := map[string]*ret{ names := map[string]*ret{
"www.example.com": &ret{true, 3, 15}, "..": &ret{false, 1},
"www.example.com.": &ret{true, 3, 16}, "@.": &ret{true, 1},
"mi\\k.nl.": &ret{true, 2, 8}, "www.example.com": &ret{true, 3},
"mi\\k.nl": &ret{true, 2, 7}, "www.example.com.": &ret{true, 3},
"mi\\k.nl.": &ret{true, 2},
"mi\\k.nl": &ret{true, 2},
} }
for d, ok := range names { for d, ok := range names {
l1, l2, k := IsDomainName(d) l, k := IsDomainName(d)
if ok.ok != k || ok.lab != l1 || ok.l != l2 { if ok.ok != k || ok.lab != l {
t.Logf("Got %v %d %d for %s ", k, l1, l2, d) t.Logf(" got %v %d for %s ", k, l, d)
t.Logf(" %v %d %d for %s ", ok.ok, ok.lab, ok.l, d) t.Logf("have %v %d for %s ", ok.ok, ok.lab, d)
t.Fail() t.Fail()
} }
} }

57
msg.go
View File

@ -212,14 +212,31 @@ var RcodeToString = map[int]string{
// map needs to hold a mapping between domain names and offsets // map needs to hold a mapping between domain names and offsets
// pointing into msg[]. // pointing into msg[].
func PackDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) { func PackDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
lenmsg := len(msg) off1, _, err = packDomainName(s, msg, off, compression, compress)
return
}
func packDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, labels int, err error) {
// special case if msg == nil
lenmsg := 256
if msg != nil {
lenmsg = len(msg)
}
ls := len(s) ls := len(s)
if ls == 0 { // Ok, for instance when dealing with update RR without any rdata. if ls == 0 { // Ok, for instance when dealing with update RR without any rdata.
return off, nil return off, 0, nil
} }
// If not fully qualified, error out // If not fully qualified, error out, but only if msg == nil #ugly
if s[ls-1] != '.' { switch {
return lenmsg, ErrFqdn case msg == nil:
if s[ls-1] != '.' {
s += "."
ls++
}
case msg != nil:
if s[ls-1] != '.' {
return lenmsg, 0, ErrFqdn
}
} }
// Each dot ends a segment of the name. // Each dot ends a segment of the name.
// We trade each dot byte for a length byte. // We trade each dot byte for a length byte.
@ -239,7 +256,7 @@ func PackDomainName(s string, msg []byte, off int, compression map[string]int, c
} }
ls-- ls--
if off+1 > lenmsg { if off+1 > lenmsg {
return lenmsg, ErrBuf return lenmsg, labels, ErrBuf
} }
// check for \DDD // check for \DDD
if i+2 < ls && bs[i] >= '0' && bs[i] <= '9' && if i+2 < ls && bs[i] >= '0' && bs[i] <= '9' &&
@ -255,22 +272,30 @@ func PackDomainName(s string, msg []byte, off int, compression map[string]int, c
} }
if bs[i] == '.' { if bs[i] == '.' {
if i > 0 && bs[i-1] == '.' {
// two dots back to back is not legal
return lenmsg, labels, ErrRdata
}
if i-begin >= 1<<6 { // top two bits of length must be clear if i-begin >= 1<<6 { // top two bits of length must be clear
return lenmsg, ErrRdata return lenmsg, labels, ErrRdata
} }
// off can already (we're in a loop) be bigger than len(msg) // off can already (we're in a loop) be bigger than len(msg)
// this happens when a name isn't fully qualified // this happens when a name isn't fully qualified
if off+1 > lenmsg { if off+1 > lenmsg {
return lenmsg, ErrBuf return lenmsg, labels, ErrBuf
}
if msg != nil {
msg[off] = byte(i - begin)
} }
msg[off] = byte(i - begin)
offset := off offset := off
off++ off++
for j := begin; j < i; j++ { for j := begin; j < i; j++ {
if off+1 > lenmsg { if off+1 > lenmsg {
return lenmsg, ErrBuf return lenmsg, labels, ErrBuf
}
if msg != nil {
msg[off] = bs[j]
} }
msg[off] = bs[j]
off++ off++
} }
// Dont try to compress '.' // Dont try to compress '.'
@ -294,24 +319,28 @@ func PackDomainName(s string, msg []byte, off int, compression map[string]int, c
} }
} }
} }
labels++
begin = i + 1 begin = i + 1
} }
} }
// Root label is special // Root label is special
if len(bs) == 1 && bs[0] == '.' { if len(bs) == 1 && bs[0] == '.' {
return off, nil return off, labels, nil
} }
// If we did compression and we find something add the pointer here // If we did compression and we find something add the pointer here
if pointer != -1 { if pointer != -1 {
// We have two bytes (14 bits) to put the pointer in // We have two bytes (14 bits) to put the pointer in
// if msg == nil, we will never do compression
msg[nameoffset], msg[nameoffset+1] = packUint16(uint16(pointer ^ 0xC000)) msg[nameoffset], msg[nameoffset+1] = packUint16(uint16(pointer ^ 0xC000))
off = nameoffset + 1 off = nameoffset + 1
goto End goto End
} }
msg[off] = 0 if msg != nil {
msg[off] = 0
}
End: End:
off++ off++
return off, nil return off, labels, nil
} }
// Unpack a domain name. // Unpack a domain name.

View File

@ -267,7 +267,8 @@ func TestParseFailure(t *testing.T) {
"miek.nl. IN AAAA ::x", "miek.nl. IN AAAA ::x",
"miek.nl. IN MX a0 miek.nl.", "miek.nl. IN MX a0 miek.nl.",
"miek.nl aap IN MX mx.miek.nl.", "miek.nl aap IN MX mx.miek.nl.",
"miek.nl. IN CNAME ", // "miek.nl. IN CNAME ", // actually valid nowadays, zero size rdata
"miek.nl. IN CNAME ..",
"miek.nl. PA MX 10 miek.nl.", "miek.nl. PA MX 10 miek.nl.",
"miek.nl. ) IN MX 10 miek.nl.", "miek.nl. ) IN MX 10 miek.nl.",
} }
@ -275,7 +276,7 @@ func TestParseFailure(t *testing.T) {
for _, s := range tests { for _, s := range tests {
_, err := NewRR(s) _, err := NewRR(s)
if err == nil { if err == nil {
t.Log("Should have triggered an error") t.Logf("Should have triggered an error: \"%s\"", s)
t.Fail() t.Fail()
} }
} }

View File

@ -174,7 +174,7 @@ func (mux *ServeMux) match(q string, t uint16) Handler {
for { for {
l := len(q[off:]) l := len(q[off:])
for i := 0; i < l; i++ { for i := 0; i < l; i++ {
b[i] = q[off+i] | ( 'a' - 'A') b[i] = q[off+i] | ('a' - 'A')
} }
if h, ok := mux.z[string(b[:l])]; ok { // 'causes garbage, might want to change the map key if h, ok := mux.z[string(b[:l])]; ok { // 'causes garbage, might want to change the map key
if t != TypeDS { if t != TypeDS {

2
xfr.go
View File

@ -70,7 +70,7 @@ func (w *reply) axfrIn(q *Msg, c chan *Envelope) {
} }
first = !first first = !first
// only one answer that is SOA, receive more // only one answer that is SOA, receive more
if (len(in.Answer) == 1) { if len(in.Answer) == 1 {
w.tsigTimersOnly = true w.tsigTimersOnly = true
c <- &Envelope{in.Answer, nil} c <- &Envelope{in.Answer, nil}
continue continue

View File

@ -88,6 +88,7 @@ func (e *ParseError) Error() (s string) {
type lex struct { type lex struct {
token string // text of the token token string // text of the token
length int // lenght of the token
err bool // when true, token text has lexer error err bool // when true, token text has lexer error
value uint8 // value: _STRING, _BLANK, etc. value uint8 // value: _STRING, _BLANK, etc.
line int // line in the file line int // line in the file
@ -179,11 +180,11 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
if origin == "" { if origin == "" {
origin = "." origin = "."
} }
if _, _, ok := IsDomainName(origin); !ok { origin = Fqdn(origin)
if _, ok := IsDomainName(origin); !ok {
t <- Token{Error: &ParseError{f, "bad initial origin name", lex{}}} t <- Token{Error: &ParseError{f, "bad initial origin name", lex{}}}
return return
} }
origin = Fqdn(origin)
st := _EXPECT_OWNER_DIR // initial state st := _EXPECT_OWNER_DIR // initial state
var h RR_Header var h RR_Header
@ -212,14 +213,14 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
st = _EXPECT_OWNER_BL st = _EXPECT_OWNER_BL
break break
} }
_, ld, ok := IsDomainName(l.token) if h.Name[l.length-1] != '.' {
h.Name = appendOrigin(h.Name, origin)
}
_, ok := IsDomainName(l.token)
if !ok { if !ok {
t <- Token{Error: &ParseError{f, "bad owner name", l}} t <- Token{Error: &ParseError{f, "bad owner name", l}}
return return
} }
if h.Name[ld-1] != '.' {
h.Name = appendOrigin(h.Name, origin)
}
prevName = h.Name prevName = h.Name
st = _EXPECT_OWNER_BL st = _EXPECT_OWNER_BL
case _DIRTTL: case _DIRTTL:
@ -273,12 +274,12 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
case _BLANK: case _BLANK:
l := <-c l := <-c
if l.value == _STRING { if l.value == _STRING {
if _, _, ok := IsDomainName(l.token); !ok { if _, ok := IsDomainName(l.token); !ok {
t <- Token{Error: &ParseError{f, "bad origin name", l}} t <- Token{Error: &ParseError{f, "bad origin name", l}}
return return
} }
// a new origin is specified. // a new origin is specified.
if !IsFqdn(l.token) { if l.token[l.length-1] != '.' {
if origin != "." { // Prevent .. endings if origin != "." { // Prevent .. endings
neworigin = l.token + "." + origin neworigin = l.token + "." + origin
} else { } else {
@ -342,11 +343,11 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
if e, _ := slurpRemainder(c, f); e != nil { if e, _ := slurpRemainder(c, f); e != nil {
t <- Token{Error: e} t <- Token{Error: e}
} }
if _, _, ok := IsDomainName(l.token); !ok { if _, ok := IsDomainName(l.token); !ok {
t <- Token{Error: &ParseError{f, "bad origin name", l}} t <- Token{Error: &ParseError{f, "bad origin name", l}}
return return
} }
if !IsFqdn(l.token) { if l.token[l.length-1] != '.' {
if origin != "." { // Prevent .. endings if origin != "." { // Prevent .. endings
origin = l.token + "." + origin origin = l.token + "." + origin
} else { } else {
@ -527,6 +528,7 @@ func zlexer(s *scan, c chan lex) {
// If we have a string and its the first, make it an owner // If we have a string and its the first, make it an owner
l.value = _OWNER l.value = _OWNER
l.token = string(str[:stri]) l.token = string(str[:stri])
l.length = stri
// escape $... start with a \ not a $, so this will work // escape $... start with a \ not a $, so this will work
switch l.token { switch l.token {
case "$TTL": case "$TTL":
@ -543,7 +545,7 @@ func zlexer(s *scan, c chan lex) {
} else { } else {
l.value = _STRING l.value = _STRING
l.token = string(str[:stri]) l.token = string(str[:stri])
l.length = stri
if !rrtype { if !rrtype {
if t, ok := StringToType[l.token]; ok { if t, ok := StringToType[l.token]; ok {
l.value = _RRTYPE l.value = _RRTYPE
@ -589,6 +591,7 @@ func zlexer(s *scan, c chan lex) {
if !space && !commt { if !space && !commt {
l.value = _BLANK l.value = _BLANK
l.token = " " l.token = " "
l.length = 1
debug.Printf("[5 %+v]", l.token) debug.Printf("[5 %+v]", l.token)
c <- l c <- l
} }
@ -610,6 +613,7 @@ func zlexer(s *scan, c chan lex) {
if stri > 0 { if stri > 0 {
l.value = _STRING l.value = _STRING
l.token = string(str[:stri]) l.token = string(str[:stri])
l.length = stri
debug.Printf("[4 %+v]", l.token) debug.Printf("[4 %+v]", l.token)
c <- l c <- l
stri = 0 stri = 0
@ -640,6 +644,7 @@ func zlexer(s *scan, c chan lex) {
owner = true owner = true
l.value = _NEWLINE l.value = _NEWLINE
l.token = "\n" l.token = "\n"
l.length = 1
l.comment = string(com[:comi]) l.comment = string(com[:comi])
debug.Printf("[3 %+v %+v]", l.token, l.comment) debug.Printf("[3 %+v %+v]", l.token, l.comment)
c <- l c <- l
@ -657,6 +662,7 @@ func zlexer(s *scan, c chan lex) {
if stri != 0 { if stri != 0 {
l.value = _STRING l.value = _STRING
l.token = string(str[:stri]) l.token = string(str[:stri])
l.length = stri
if !rrtype { if !rrtype {
if t, ok := StringToType[strings.ToUpper(l.token)]; ok { if t, ok := StringToType[strings.ToUpper(l.token)]; ok {
l.value = _RRTYPE l.value = _RRTYPE
@ -669,6 +675,7 @@ func zlexer(s *scan, c chan lex) {
} }
l.value = _NEWLINE l.value = _NEWLINE
l.token = "\n" l.token = "\n"
l.length = 1
debug.Printf("[1 %+v]", l.token) debug.Printf("[1 %+v]", l.token)
c <- l c <- l
stri = 0 stri = 0
@ -710,12 +717,14 @@ func zlexer(s *scan, c chan lex) {
if stri != 0 { if stri != 0 {
l.value = _STRING l.value = _STRING
l.token = string(str[:stri]) l.token = string(str[:stri])
l.length = stri
debug.Printf("[%+v]", l.token) debug.Printf("[%+v]", l.token)
c <- l c <- l
stri = 0 stri = 0
} }
l.value = _QUOTE l.value = _QUOTE
l.token = "\"" l.token = "\""
l.length = 1
c <- l c <- l
quote = !quote quote = !quote
case '(', ')': case '(', ')':
@ -761,10 +770,10 @@ func zlexer(s *scan, c chan lex) {
} }
x, err = s.tokenText() x, err = s.tokenText()
} }
// Hmm.
if stri > 0 { if stri > 0 {
// Send remainder // Send remainder
l.token = string(str[:stri]) l.token = string(str[:stri])
l.length = stri
l.value = _STRING l.value = _STRING
debug.Printf("[%+v]", l.token) debug.Printf("[%+v]", l.token)
c <- l c <- l

View File

@ -271,11 +271,11 @@ func setNS(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Ns = o rr.Ns = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad NS Ns", l} return nil, &ParseError{f, "bad NS Ns", l}
} }
if rr.Ns[ld-1] != '.' { if rr.Ns[l.length-1] != '.' {
rr.Ns = appendOrigin(rr.Ns, o) rr.Ns = appendOrigin(rr.Ns, o)
} }
return rr, nil return rr, nil
@ -291,11 +291,11 @@ func setPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Ptr = o rr.Ptr = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad PTR Ptr", l} return nil, &ParseError{f, "bad PTR Ptr", l}
} }
if rr.Ptr[ld-1] != '.' { if rr.Ptr[l.length-1] != '.' {
rr.Ptr = appendOrigin(rr.Ptr, o) rr.Ptr = appendOrigin(rr.Ptr, o)
} }
return rr, nil return rr, nil
@ -310,11 +310,11 @@ func setRP(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
if l.token == "@" { if l.token == "@" {
rr.Mbox = o rr.Mbox = o
} else { } else {
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad RP Mbox", l} return nil, &ParseError{f, "bad RP Mbox", l}
} }
if rr.Mbox[ld-1] != '.' { if rr.Mbox[l.length-1] != '.' {
rr.Mbox = appendOrigin(rr.Mbox, o) rr.Mbox = appendOrigin(rr.Mbox, o)
} }
} }
@ -325,14 +325,13 @@ func setRP(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Txt = o rr.Txt = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad RP Txt", l} return nil, &ParseError{f, "bad RP Txt", l}
} }
if rr.Txt[ld-1] != '.' { if rr.Txt[l.length-1] != '.' {
rr.Txt = appendOrigin(rr.Txt, o) rr.Txt = appendOrigin(rr.Txt, o)
} }
return rr, nil return rr, nil
} }
@ -346,11 +345,11 @@ func setMR(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Mr = o rr.Mr = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad MR Mr", l} return nil, &ParseError{f, "bad MR Mr", l}
} }
if rr.Mr[ld-1] != '.' { if rr.Mr[l.length-1] != '.' {
rr.Mr = appendOrigin(rr.Mr, o) rr.Mr = appendOrigin(rr.Mr, o)
} }
return rr, nil return rr, nil
@ -366,11 +365,11 @@ func setMB(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Mb = o rr.Mb = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad MB Mb", l} return nil, &ParseError{f, "bad MB Mb", l}
} }
if rr.Mb[ld-1] != '.' { if rr.Mb[l.length-1] != '.' {
rr.Mb = appendOrigin(rr.Mb, o) rr.Mb = appendOrigin(rr.Mb, o)
} }
return rr, nil return rr, nil
@ -386,11 +385,11 @@ func setMG(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Mg = o rr.Mg = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad MG Mg", l} return nil, &ParseError{f, "bad MG Mg", l}
} }
if rr.Mg[ld-1] != '.' { if rr.Mg[l.length-1] != '.' {
rr.Mg = appendOrigin(rr.Mg, o) rr.Mg = appendOrigin(rr.Mg, o)
} }
return rr, nil return rr, nil
@ -418,11 +417,11 @@ func setMINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
if l.token == "@" { if l.token == "@" {
rr.Rmail = o rr.Rmail = o
} else { } else {
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad MINFO Rmail", l} return nil, &ParseError{f, "bad MINFO Rmail", l}
} }
if rr.Rmail[ld-1] != '.' { if rr.Rmail[l.length-1] != '.' {
rr.Rmail = appendOrigin(rr.Rmail, o) rr.Rmail = appendOrigin(rr.Rmail, o)
} }
} }
@ -433,11 +432,11 @@ func setMINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Email = o rr.Email = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad MINFO Email", l} return nil, &ParseError{f, "bad MINFO Email", l}
} }
if rr.Email[ld-1] != '.' { if rr.Email[l.length-1] != '.' {
rr.Email = appendOrigin(rr.Email, o) rr.Email = appendOrigin(rr.Email, o)
} }
return rr, nil return rr, nil
@ -453,11 +452,11 @@ func setMF(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Mf = o rr.Mf = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad MF Mf", l} return nil, &ParseError{f, "bad MF Mf", l}
} }
if rr.Mf[ld-1] != '.' { if rr.Mf[l.length-1] != '.' {
rr.Mf = appendOrigin(rr.Mf, o) rr.Mf = appendOrigin(rr.Mf, o)
} }
return rr, nil return rr, nil
@ -473,11 +472,11 @@ func setMD(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Md = o rr.Md = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad MD Md", l} return nil, &ParseError{f, "bad MD Md", l}
} }
if rr.Md[ld-1] != '.' { if rr.Md[l.length-1] != '.' {
rr.Md = appendOrigin(rr.Md, o) rr.Md = appendOrigin(rr.Md, o)
} }
return rr, nil return rr, nil
@ -500,11 +499,11 @@ func setMX(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Mx = o rr.Mx = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad MX Mx", l} return nil, &ParseError{f, "bad MX Mx", l}
} }
if rr.Mx[ld-1] != '.' { if rr.Mx[l.length-1] != '.' {
rr.Mx = appendOrigin(rr.Mx, o) rr.Mx = appendOrigin(rr.Mx, o)
} }
return rr, nil return rr, nil
@ -527,11 +526,11 @@ func setRT(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Host = o rr.Host = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad RT Host", l} return nil, &ParseError{f, "bad RT Host", l}
} }
if rr.Host[ld-1] != '.' { if rr.Host[l.length-1] != '.' {
rr.Host = appendOrigin(rr.Host, o) rr.Host = appendOrigin(rr.Host, o)
} }
return rr, nil return rr, nil
@ -554,11 +553,11 @@ func setAFSDB(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Hostname = o rr.Hostname = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad AFSDB Hostname", l} return nil, &ParseError{f, "bad AFSDB Hostname", l}
} }
if rr.Hostname[ld-1] != '.' { if rr.Hostname[l.length-1] != '.' {
rr.Hostname = appendOrigin(rr.Hostname, o) rr.Hostname = appendOrigin(rr.Hostname, o)
} }
return rr, nil return rr, nil
@ -590,11 +589,11 @@ func setKX(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Exchanger = o rr.Exchanger = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad KX Exchanger", l} return nil, &ParseError{f, "bad KX Exchanger", l}
} }
if rr.Exchanger[ld-1] != '.' { if rr.Exchanger[l.length-1] != '.' {
rr.Exchanger = appendOrigin(rr.Exchanger, o) rr.Exchanger = appendOrigin(rr.Exchanger, o)
} }
return rr, nil return rr, nil
@ -610,11 +609,11 @@ func setCNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Target = o rr.Target = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad CNAME Target", l} return nil, &ParseError{f, "bad CNAME Target", l}
} }
if rr.Target[ld-1] != '.' { if rr.Target[l.length-1] != '.' {
rr.Target = appendOrigin(rr.Target, o) rr.Target = appendOrigin(rr.Target, o)
} }
return rr, nil return rr, nil
@ -630,11 +629,11 @@ func setDNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Target = o rr.Target = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad CNAME Target", l} return nil, &ParseError{f, "bad CNAME Target", l}
} }
if rr.Target[ld-1] != '.' { if rr.Target[l.length-1] != '.' {
rr.Target = appendOrigin(rr.Target, o) rr.Target = appendOrigin(rr.Target, o)
} }
return rr, nil return rr, nil
@ -650,11 +649,11 @@ func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
if l.token == "@" { if l.token == "@" {
rr.Ns = o rr.Ns = o
} else { } else {
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad SOA Ns", l} return nil, &ParseError{f, "bad SOA Ns", l}
} }
if rr.Ns[ld-1] != '.' { if rr.Ns[l.length-1] != '.' {
rr.Ns = appendOrigin(rr.Ns, o) rr.Ns = appendOrigin(rr.Ns, o)
} }
} }
@ -664,11 +663,11 @@ func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
if l.token == "@" { if l.token == "@" {
rr.Mbox = o rr.Mbox = o
} else { } else {
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad SOA Mbox", l} return nil, &ParseError{f, "bad SOA Mbox", l}
} }
if rr.Mbox[ld-1] != '.' { if rr.Mbox[l.length-1] != '.' {
rr.Mbox = appendOrigin(rr.Mbox, o) rr.Mbox = appendOrigin(rr.Mbox, o)
} }
} }
@ -743,11 +742,11 @@ func setSRV(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Target = o rr.Target = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad SRV Target", l} return nil, &ParseError{f, "bad SRV Target", l}
} }
if rr.Target[ld-1] != '.' { if rr.Target[l.length-1] != '.' {
rr.Target = appendOrigin(rr.Target, o) rr.Target = appendOrigin(rr.Target, o)
} }
return rr, nil return rr, nil
@ -834,11 +833,11 @@ func setNAPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Replacement = o rr.Replacement = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad NAPTR Replacement", l} return nil, &ParseError{f, "bad NAPTR Replacement", l}
} }
if rr.Replacement[ld-1] != '.' { if rr.Replacement[l.length-1] != '.' {
rr.Replacement = appendOrigin(rr.Replacement, o) rr.Replacement = appendOrigin(rr.Replacement, o)
} }
return rr, nil return rr, nil
@ -853,11 +852,11 @@ func setTALINK(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
if l.token == "@" { if l.token == "@" {
rr.PreviousName = o rr.PreviousName = o
} else { } else {
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad TALINK PreviousName", l} return nil, &ParseError{f, "bad TALINK PreviousName", l}
} }
if rr.PreviousName[ld-1] != '.' { if rr.PreviousName[l.length-1] != '.' {
rr.PreviousName = appendOrigin(rr.PreviousName, o) rr.PreviousName = appendOrigin(rr.PreviousName, o)
} }
} }
@ -868,11 +867,11 @@ func setTALINK(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.NextName = o rr.NextName = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad TALINK NextName", l} return nil, &ParseError{f, "bad TALINK NextName", l}
} }
if rr.NextName[ld-1] != '.' { if rr.NextName[l.length-1] != '.' {
rr.NextName = appendOrigin(rr.NextName, o) rr.NextName = appendOrigin(rr.NextName, o)
} }
return rr, nil return rr, nil
@ -1036,11 +1035,11 @@ func setHIP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
xs = append(xs, o) xs = append(xs, o)
continue continue
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad HIP RendezvousServers", l}, "" return nil, &ParseError{f, "bad HIP RendezvousServers", l}, ""
} }
if l.token[ld-1] != '.' { if l.token[l.length-1] != '.' {
l.token = appendOrigin(l.token, o) l.token = appendOrigin(l.token, o)
} }
xs = append(xs, l.token) xs = append(xs, l.token)
@ -1144,11 +1143,11 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
if l.token == "@" { if l.token == "@" {
rr.SignerName = o rr.SignerName = o
} else { } else {
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad RRSIG SignerName", l}, "" return nil, &ParseError{f, "bad RRSIG SignerName", l}, ""
} }
if rr.SignerName[ld-1] != '.' { if rr.SignerName[l.length-1] != '.' {
rr.SignerName = appendOrigin(rr.SignerName, o) rr.SignerName = appendOrigin(rr.SignerName, o)
} }
} }
@ -1169,11 +1168,11 @@ func setNSEC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
if l.token == "@" { if l.token == "@" {
rr.NextDomain = o rr.NextDomain = o
} else { } else {
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad NSEC NextDomain", l}, "" return nil, &ParseError{f, "bad NSEC NextDomain", l}, ""
} }
if rr.NextDomain[ld-1] != '.' { if rr.NextDomain[l.length-1] != '.' {
rr.NextDomain = appendOrigin(rr.NextDomain, o) rr.NextDomain = appendOrigin(rr.NextDomain, o)
} }
} }
@ -1861,11 +1860,11 @@ func setLP(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
rr.Fqdn = o rr.Fqdn = o
return rr, nil return rr, nil
} }
_, ld, ok := IsDomainName(l.token) _, ok := IsDomainName(l.token)
if !ok { if !ok {
return nil, &ParseError{f, "bad LP Fqdn", l} return nil, &ParseError{f, "bad LP Fqdn", l}
} }
if rr.Fqdn[ld-1] != '.' { if rr.Fqdn[l.length-1] != '.' {
rr.Fqdn = appendOrigin(rr.Fqdn, o) rr.Fqdn = appendOrigin(rr.Fqdn, o)
} }
return rr, nil return rr, nil