diff options
Diffstat (limited to 'libgo/go/net/dnsmsg.go')
-rw-r--r-- | libgo/go/net/dnsmsg.go | 164 |
1 files changed, 71 insertions, 93 deletions
diff --git a/libgo/go/net/dnsmsg.go b/libgo/go/net/dnsmsg.go index 93078fe..afdb44c 100644 --- a/libgo/go/net/dnsmsg.go +++ b/libgo/go/net/dnsmsg.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// DNS packet assembly. See RFC 1035. +// DNS packet assembly. See RFC 1035. // // This is intended to support name resolution during Dial. // It doesn't have to be blazing fast. @@ -18,7 +18,7 @@ // generic pack/unpack routines. // // TODO(rsc): There are enough names defined in this file that they're all -// prefixed with dns. Perhaps put this in its own package later. +// prefixed with dns. Perhaps put this in its own package later. package net @@ -109,7 +109,7 @@ const ( // DNS queries. type dnsQuestion struct { - Name string `net:"domain-name"` // `net:"domain-name"` specifies encoding; see packers below + Name string Qtype uint16 Qclass uint16 } @@ -124,7 +124,7 @@ func (q *dnsQuestion) Walk(f func(v interface{}, name, tag string) bool) bool { // There are many types of messages, // but they all share the same header. type dnsRR_Header struct { - Name string `net:"domain-name"` + Name string Rrtype uint16 Class uint16 Ttl uint32 @@ -152,7 +152,7 @@ type dnsRR interface { type dnsRR_CNAME struct { Hdr dnsRR_Header - Cname string `net:"domain-name"` + Cname string } func (rr *dnsRR_CNAME) Header() *dnsRR_Header { @@ -163,77 +163,10 @@ func (rr *dnsRR_CNAME) Walk(f func(v interface{}, name, tag string) bool) bool { return rr.Hdr.Walk(f) && f(&rr.Cname, "Cname", "domain") } -type dnsRR_HINFO struct { - Hdr dnsRR_Header - Cpu string - Os string -} - -func (rr *dnsRR_HINFO) Header() *dnsRR_Header { - return &rr.Hdr -} - -func (rr *dnsRR_HINFO) Walk(f func(v interface{}, name, tag string) bool) bool { - return rr.Hdr.Walk(f) && f(&rr.Cpu, "Cpu", "") && f(&rr.Os, "Os", "") -} - -type dnsRR_MB struct { - Hdr dnsRR_Header - Mb string `net:"domain-name"` -} - -func (rr *dnsRR_MB) Header() *dnsRR_Header { - return &rr.Hdr -} - -func (rr *dnsRR_MB) Walk(f func(v interface{}, name, tag string) bool) bool { - return rr.Hdr.Walk(f) && f(&rr.Mb, "Mb", "domain") -} - -type dnsRR_MG struct { - Hdr dnsRR_Header - Mg string `net:"domain-name"` -} - -func (rr *dnsRR_MG) Header() *dnsRR_Header { - return &rr.Hdr -} - -func (rr *dnsRR_MG) Walk(f func(v interface{}, name, tag string) bool) bool { - return rr.Hdr.Walk(f) && f(&rr.Mg, "Mg", "domain") -} - -type dnsRR_MINFO struct { - Hdr dnsRR_Header - Rmail string `net:"domain-name"` - Email string `net:"domain-name"` -} - -func (rr *dnsRR_MINFO) Header() *dnsRR_Header { - return &rr.Hdr -} - -func (rr *dnsRR_MINFO) Walk(f func(v interface{}, name, tag string) bool) bool { - return rr.Hdr.Walk(f) && f(&rr.Rmail, "Rmail", "domain") && f(&rr.Email, "Email", "domain") -} - -type dnsRR_MR struct { - Hdr dnsRR_Header - Mr string `net:"domain-name"` -} - -func (rr *dnsRR_MR) Header() *dnsRR_Header { - return &rr.Hdr -} - -func (rr *dnsRR_MR) Walk(f func(v interface{}, name, tag string) bool) bool { - return rr.Hdr.Walk(f) && f(&rr.Mr, "Mr", "domain") -} - type dnsRR_MX struct { Hdr dnsRR_Header Pref uint16 - Mx string `net:"domain-name"` + Mx string } func (rr *dnsRR_MX) Header() *dnsRR_Header { @@ -246,7 +179,7 @@ func (rr *dnsRR_MX) Walk(f func(v interface{}, name, tag string) bool) bool { type dnsRR_NS struct { Hdr dnsRR_Header - Ns string `net:"domain-name"` + Ns string } func (rr *dnsRR_NS) Header() *dnsRR_Header { @@ -259,7 +192,7 @@ func (rr *dnsRR_NS) Walk(f func(v interface{}, name, tag string) bool) bool { type dnsRR_PTR struct { Hdr dnsRR_Header - Ptr string `net:"domain-name"` + Ptr string } func (rr *dnsRR_PTR) Header() *dnsRR_Header { @@ -272,8 +205,8 @@ func (rr *dnsRR_PTR) Walk(f func(v interface{}, name, tag string) bool) bool { type dnsRR_SOA struct { Hdr dnsRR_Header - Ns string `net:"domain-name"` - Mbox string `net:"domain-name"` + Ns string + Mbox string Serial uint32 Refresh uint32 Retry uint32 @@ -315,7 +248,7 @@ func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool { if !f(&txt, "Txt", "") { return false } - // more bytes than rr.Hdr.Rdlength said there woudld be + // more bytes than rr.Hdr.Rdlength said there would be if rr.Hdr.Rdlength-n < uint16(len(txt))+1 { return false } @@ -330,7 +263,7 @@ type dnsRR_SRV struct { Priority uint16 Weight uint16 Port uint16 - Target string `net:"domain-name"` + Target string } func (rr *dnsRR_SRV) Header() *dnsRR_Header { @@ -347,7 +280,7 @@ func (rr *dnsRR_SRV) Walk(f func(v interface{}, name, tag string) bool) bool { type dnsRR_A struct { Hdr dnsRR_Header - A uint32 `net:"ipv4"` + A uint32 } func (rr *dnsRR_A) Header() *dnsRR_Header { @@ -360,7 +293,7 @@ func (rr *dnsRR_A) Walk(f func(v interface{}, name, tag string) bool) bool { type dnsRR_AAAA struct { Hdr dnsRR_Header - AAAA [16]byte `net:"ipv6"` + AAAA [16]byte } func (rr *dnsRR_AAAA) Header() *dnsRR_Header { @@ -376,17 +309,12 @@ func (rr *dnsRR_AAAA) Walk(f func(v interface{}, name, tag string) bool) bool { // All the packers and unpackers take a (msg []byte, off int) // and return (off1 int, ok bool). If they return ok==false, they // also return off1==len(msg), so that the next unpacker will -// also fail. This lets us avoid checks of ok until the end of a +// also fail. This lets us avoid checks of ok until the end of a // packing sequence. // Map of constructors for each RR wire type. var rr_mk = map[int]func() dnsRR{ dnsTypeCNAME: func() dnsRR { return new(dnsRR_CNAME) }, - dnsTypeHINFO: func() dnsRR { return new(dnsRR_HINFO) }, - dnsTypeMB: func() dnsRR { return new(dnsRR_MB) }, - dnsTypeMG: func() dnsRR { return new(dnsRR_MG) }, - dnsTypeMINFO: func() dnsRR { return new(dnsRR_MINFO) }, - dnsTypeMR: func() dnsRR { return new(dnsRR_MR) }, dnsTypeMX: func() dnsRR { return new(dnsRR_MX) }, dnsTypeNS: func() dnsRR { return new(dnsRR_NS) }, dnsTypePTR: func() dnsRR { return new(dnsRR_PTR) }, @@ -399,13 +327,20 @@ var rr_mk = map[int]func() dnsRR{ // Pack a domain name s into msg[off:]. // Domain names are a sequence of counted strings -// split at the dots. They end with a zero-length string. +// split at the dots. They end with a zero-length string. func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) { // Add trailing dot to canonicalize name. if n := len(s); n == 0 || s[n-1] != '.' { s += "." } + // Allow root domain. + if s == "." { + msg[off] = 0 + off++ + return off, true + } + // Each dot ends a segment of the name. // We trade each dot byte for a length byte. // There is also a trailing zero. @@ -422,8 +357,13 @@ func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) { if i-begin >= 1<<6 { // top two bits of length must be clear return len(msg), false } + if i-begin == 0 { + return len(msg), false + } + msg[off] = byte(i - begin) off++ + for j := begin; j < i; j++ { msg[off] = s[j] off++ @@ -440,8 +380,8 @@ func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) { // In addition to the simple sequences of counted strings above, // domain names are allowed to refer to strings elsewhere in the // packet, to avoid repeating common suffixes when returning -// many entries in a single domain. The pointers are marked -// by a length byte with the top two bits set. Ignoring those +// many entries in a single domain. The pointers are marked +// by a length byte with the top two bits set. Ignoring those // two bits, that byte and the next give a 14 bit offset from msg[0] // where we should pick up the trail. // Note that if we jump elsewhere in the packet, @@ -494,6 +434,9 @@ Loop: return "", len(msg), false } } + if len(s) == 0 { + s = "." + } if ptr == 0 { off1 = off } @@ -803,20 +746,32 @@ func (dns *dnsMsg) Pack() (msg []byte, ok bool) { // Pack it in: header and then the pieces. off := 0 off, ok = packStruct(&dh, msg, off) + if !ok { + return nil, false + } for i := 0; i < len(question); i++ { off, ok = packStruct(&question[i], msg, off) + if !ok { + return nil, false + } } for i := 0; i < len(answer); i++ { off, ok = packRR(answer[i], msg, off) + if !ok { + return nil, false + } } for i := 0; i < len(ns); i++ { off, ok = packRR(ns[i], msg, off) + if !ok { + return nil, false + } } for i := 0; i < len(extra); i++ { off, ok = packRR(extra[i], msg, off) - } - if !ok { - return nil, false + if !ok { + return nil, false + } } return msg[0:off], true } @@ -848,6 +803,9 @@ func (dns *dnsMsg) Unpack(msg []byte) bool { for i := 0; i < len(dns.question); i++ { off, ok = unpackStruct(&dns.question[i], msg, off) + if !ok { + return false + } } for i := 0; i < int(dh.Ancount); i++ { rec, off, ok = unpackRR(msg, off) @@ -904,3 +862,23 @@ func (dns *dnsMsg) String() string { } return s } + +// IsResponseTo reports whether m is an acceptable response to query. +func (m *dnsMsg) IsResponseTo(query *dnsMsg) bool { + if !m.response { + return false + } + if m.id != query.id { + return false + } + if len(m.question) != len(query.question) { + return false + } + for i, q := range m.question { + q2 := query.question[i] + if !equalASCIILabel(q.Name, q2.Name) || q.Qtype != q2.Qtype || q.Qclass != q2.Qclass { + return false + } + } + return true +} |