Fix panic when parsing resolv.conf
This commit is contained in:
parent
f149b56063
commit
9ae808aac4
316 changed files with 37454 additions and 13195 deletions
306
vendor/github.com/miekg/dns/msg.go
generated
vendored
306
vendor/github.com/miekg/dns/msg.go
generated
vendored
|
@ -9,42 +9,36 @@
|
|||
package dns
|
||||
|
||||
//go:generate go run msg_generate.go
|
||||
//go:generate go run compress_generate.go
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Initialize default math/rand source using crypto/rand to provide better
|
||||
// security without the performance trade-off.
|
||||
buf := make([]byte, 8)
|
||||
_, err := crand.Read(buf)
|
||||
if err != nil {
|
||||
// Failed to read from cryptographic source, fallback to default initial
|
||||
// seed (1) by returning early
|
||||
return
|
||||
}
|
||||
seed := binary.BigEndian.Uint64(buf)
|
||||
rand.Seed(int64(seed))
|
||||
}
|
||||
|
||||
const maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer
|
||||
const (
|
||||
maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer
|
||||
maxDomainNameWireOctets = 255 // See RFC 1035 section 2.3.4
|
||||
)
|
||||
|
||||
// Errors defined in this package.
|
||||
var (
|
||||
ErrAlg error = &Error{err: "bad algorithm"} // ErrAlg indicates an error with the (DNSSEC) algorithm.
|
||||
ErrAuth error = &Error{err: "bad authentication"} // ErrAuth indicates an error in the TSIG authentication.
|
||||
ErrBuf error = &Error{err: "buffer size too small"} // ErrBuf indicates that the buffer used it too small for the message.
|
||||
ErrConnEmpty error = &Error{err: "conn has no connection"} // ErrConnEmpty indicates a connection is being uses before it is initialized.
|
||||
ErrBuf error = &Error{err: "buffer size too small"} // ErrBuf indicates that the buffer used is too small for the message.
|
||||
ErrConnEmpty error = &Error{err: "conn has no connection"} // ErrConnEmpty indicates a connection is being used before it is initialized.
|
||||
ErrExtendedRcode error = &Error{err: "bad extended rcode"} // ErrExtendedRcode ...
|
||||
ErrFqdn error = &Error{err: "domain must be fully qualified"} // ErrFqdn indicates that a domain name does not have a closing dot.
|
||||
ErrId error = &Error{err: "id mismatch"} // ErrId indicates there is a mismatch with the message's ID.
|
||||
ErrKeyAlg error = &Error{err: "bad key algorithm"} // ErrKeyAlg indicates that the algorithm in the key is not valid.
|
||||
ErrKey error = &Error{err: "bad key"}
|
||||
ErrKeySize error = &Error{err: "bad key size"}
|
||||
ErrLongDomain error = &Error{err: fmt.Sprintf("domain name exceeded %d wire-format octets", maxDomainNameWireOctets)}
|
||||
ErrNoSig error = &Error{err: "no signature found"}
|
||||
ErrPrivKey error = &Error{err: "bad private key"}
|
||||
ErrRcode error = &Error{err: "bad rcode"}
|
||||
|
@ -64,13 +58,47 @@ var (
|
|||
// For instance, to make it return a static value:
|
||||
//
|
||||
// dns.Id = func() uint16 { return 3 }
|
||||
var Id func() uint16 = id
|
||||
var Id = id
|
||||
|
||||
var (
|
||||
idLock sync.Mutex
|
||||
idRand *rand.Rand
|
||||
)
|
||||
|
||||
// id returns a 16 bits random number to be used as a
|
||||
// message id. The random provided should be good enough.
|
||||
func id() uint16 {
|
||||
id32 := rand.Uint32()
|
||||
return uint16(id32)
|
||||
idLock.Lock()
|
||||
|
||||
if idRand == nil {
|
||||
// This (partially) works around
|
||||
// https://github.com/golang/go/issues/11833 by only
|
||||
// seeding idRand upon the first call to id.
|
||||
|
||||
var seed int64
|
||||
var buf [8]byte
|
||||
|
||||
if _, err := crand.Read(buf[:]); err == nil {
|
||||
seed = int64(binary.LittleEndian.Uint64(buf[:]))
|
||||
} else {
|
||||
seed = rand.Int63()
|
||||
}
|
||||
|
||||
idRand = rand.New(rand.NewSource(seed))
|
||||
}
|
||||
|
||||
// The call to idRand.Uint32 must be within the
|
||||
// mutex lock because *rand.Rand is not safe for
|
||||
// concurrent use.
|
||||
//
|
||||
// There is no added performance overhead to calling
|
||||
// idRand.Uint32 inside a mutex lock over just
|
||||
// calling rand.Uint32 as the global math/rand rng
|
||||
// is internally protected by a sync.Mutex.
|
||||
id := uint16(idRand.Uint32())
|
||||
|
||||
idLock.Unlock()
|
||||
return id
|
||||
}
|
||||
|
||||
// MsgHdr is a a manually-unpacked version of (id, bits).
|
||||
|
@ -241,7 +269,9 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
|
|||
bsFresh = true
|
||||
}
|
||||
// Don't try to compress '.'
|
||||
if compress && roBs[begin:] != "." {
|
||||
// We should only compress when compress it true, but we should also still pick
|
||||
// up names that can be used for *future* compression(s).
|
||||
if compression != nil && roBs[begin:] != "." {
|
||||
if p, ok := compression[roBs[begin:]]; !ok {
|
||||
// Only offsets smaller than this can be used.
|
||||
if offset < maxCompressionOffset {
|
||||
|
@ -305,6 +335,7 @@ func UnpackDomainName(msg []byte, off int) (string, int, error) {
|
|||
s := make([]byte, 0, 64)
|
||||
off1 := 0
|
||||
lenmsg := len(msg)
|
||||
maxLen := maxDomainNameWireOctets
|
||||
ptr := 0 // number of pointers followed
|
||||
Loop:
|
||||
for {
|
||||
|
@ -329,8 +360,10 @@ Loop:
|
|||
fallthrough
|
||||
case '"', '\\':
|
||||
s = append(s, '\\', b)
|
||||
// presentation-format \X escapes add an extra byte
|
||||
maxLen++
|
||||
default:
|
||||
if b < 32 || b >= 127 { // unprintable use \DDD
|
||||
if b < 32 || b >= 127 { // unprintable, use \DDD
|
||||
var buf [3]byte
|
||||
bufs := strconv.AppendInt(buf[:0], int64(b), 10)
|
||||
s = append(s, '\\')
|
||||
|
@ -340,6 +373,8 @@ Loop:
|
|||
for _, r := range bufs {
|
||||
s = append(s, r)
|
||||
}
|
||||
// presentation-format \DDD escapes add 3 extra bytes
|
||||
maxLen += 3
|
||||
} else {
|
||||
s = append(s, b)
|
||||
}
|
||||
|
@ -364,6 +399,9 @@ Loop:
|
|||
if ptr++; ptr > 10 {
|
||||
return "", lenmsg, &Error{err: "too many compression pointers"}
|
||||
}
|
||||
// pointer should guarantee that it advances and points forwards at least
|
||||
// but the condition on previous three lines guarantees that it's
|
||||
// at least loop-free
|
||||
off = (c^0xC0)<<8 | int(c1)
|
||||
default:
|
||||
// 0x80 and 0x40 are reserved
|
||||
|
@ -375,6 +413,9 @@ Loop:
|
|||
}
|
||||
if len(s) == 0 {
|
||||
s = []byte(".")
|
||||
} else if len(s) >= maxLen {
|
||||
// error if the name is too long, but don't throw it away
|
||||
return string(s), lenmsg, ErrLongDomain
|
||||
}
|
||||
return string(s), off1, nil
|
||||
}
|
||||
|
@ -571,8 +612,8 @@ func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) {
|
|||
// If we cannot unpack the whole array, then it will return nil
|
||||
func unpackRRslice(l int, msg []byte, off int) (dst1 []RR, off1 int, err error) {
|
||||
var r RR
|
||||
// Optimistically make dst be the length that was sent
|
||||
dst := make([]RR, 0, l)
|
||||
// Don't pre-allocate, l may be under attacker control
|
||||
var dst []RR
|
||||
for i := 0; i < l; i++ {
|
||||
off1 := off
|
||||
r, off, err = UnpackRR(msg, off)
|
||||
|
@ -710,12 +751,10 @@ func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) {
|
|||
|
||||
// We need the uncompressed length here, because we first pack it and then compress it.
|
||||
msg = buf
|
||||
compress := dns.Compress
|
||||
dns.Compress = false
|
||||
if packLen := dns.Len() + 1; len(msg) < packLen {
|
||||
uncompressedLen := compressedLen(dns, false)
|
||||
if packLen := uncompressedLen + 1; len(msg) < packLen {
|
||||
msg = make([]byte, packLen)
|
||||
}
|
||||
dns.Compress = compress
|
||||
|
||||
// Pack it in: header and then the pieces.
|
||||
off := 0
|
||||
|
@ -772,13 +811,19 @@ func (dns *Msg) Unpack(msg []byte) (err error) {
|
|||
dns.CheckingDisabled = (dh.Bits & _CD) != 0
|
||||
dns.Rcode = int(dh.Bits & 0xF)
|
||||
|
||||
// If we are at the end of the message we should return *just* the
|
||||
// header. This can still be useful to the caller. 9.9.9.9 sends these
|
||||
// when responding with REFUSED for instance.
|
||||
if off == len(msg) {
|
||||
return ErrTruncated
|
||||
// reset sections before returning
|
||||
dns.Question, dns.Answer, dns.Ns, dns.Extra = nil, nil, nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Optimistically use the count given to us in the header
|
||||
dns.Question = make([]Question, 0, int(dh.Qdcount))
|
||||
|
||||
// Qdcount, Ancount, Nscount, Arcount can't be trusted, as they are
|
||||
// attacker controlled. This means we can't use them to pre-allocate
|
||||
// slices.
|
||||
dns.Question = nil
|
||||
for i := 0; i < int(dh.Qdcount); i++ {
|
||||
off1 := off
|
||||
var q Question
|
||||
|
@ -868,72 +913,62 @@ func (dns *Msg) String() string {
|
|||
// If dns.Compress is true compression it is taken into account. Len()
|
||||
// is provided to be a faster way to get the size of the resulting packet,
|
||||
// than packing it, measuring the size and discarding the buffer.
|
||||
func (dns *Msg) Len() int {
|
||||
func (dns *Msg) Len() int { return compressedLen(dns, dns.Compress) }
|
||||
|
||||
// compressedLen returns the message length when in compressed wire format
|
||||
// when compress is true, otherwise the uncompressed length is returned.
|
||||
func compressedLen(dns *Msg, compress bool) int {
|
||||
// We always return one more than needed.
|
||||
l := 12 // Message header is always 12 bytes
|
||||
var compression map[string]int
|
||||
if dns.Compress {
|
||||
compression = make(map[string]int)
|
||||
}
|
||||
for i := 0; i < len(dns.Question); i++ {
|
||||
l += dns.Question[i].len()
|
||||
if dns.Compress {
|
||||
compressionLenHelper(compression, dns.Question[i].Name)
|
||||
if compress {
|
||||
compression := map[string]int{}
|
||||
for _, r := range dns.Question {
|
||||
l += r.len()
|
||||
compressionLenHelper(compression, r.Name)
|
||||
}
|
||||
l += compressionLenSlice(compression, dns.Answer)
|
||||
l += compressionLenSlice(compression, dns.Ns)
|
||||
l += compressionLenSlice(compression, dns.Extra)
|
||||
} else {
|
||||
for _, r := range dns.Question {
|
||||
l += r.len()
|
||||
}
|
||||
for _, r := range dns.Answer {
|
||||
if r != nil {
|
||||
l += r.len()
|
||||
}
|
||||
}
|
||||
for _, r := range dns.Ns {
|
||||
if r != nil {
|
||||
l += r.len()
|
||||
}
|
||||
}
|
||||
for _, r := range dns.Extra {
|
||||
if r != nil {
|
||||
l += r.len()
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(dns.Answer); i++ {
|
||||
if dns.Answer[i] == nil {
|
||||
return l
|
||||
}
|
||||
|
||||
func compressionLenSlice(c map[string]int, rs []RR) int {
|
||||
var l int
|
||||
for _, r := range rs {
|
||||
if r == nil {
|
||||
continue
|
||||
}
|
||||
l += dns.Answer[i].len()
|
||||
if dns.Compress {
|
||||
k, ok := compressionLenSearch(compression, dns.Answer[i].Header().Name)
|
||||
if ok {
|
||||
l += 1 - k
|
||||
}
|
||||
compressionLenHelper(compression, dns.Answer[i].Header().Name)
|
||||
k, ok = compressionLenSearchType(compression, dns.Answer[i])
|
||||
if ok {
|
||||
l += 1 - k
|
||||
}
|
||||
compressionLenHelperType(compression, dns.Answer[i])
|
||||
l += r.len()
|
||||
k, ok := compressionLenSearch(c, r.Header().Name)
|
||||
if ok {
|
||||
l += 1 - k
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(dns.Ns); i++ {
|
||||
if dns.Ns[i] == nil {
|
||||
continue
|
||||
}
|
||||
l += dns.Ns[i].len()
|
||||
if dns.Compress {
|
||||
k, ok := compressionLenSearch(compression, dns.Ns[i].Header().Name)
|
||||
if ok {
|
||||
l += 1 - k
|
||||
}
|
||||
compressionLenHelper(compression, dns.Ns[i].Header().Name)
|
||||
k, ok = compressionLenSearchType(compression, dns.Ns[i])
|
||||
if ok {
|
||||
l += 1 - k
|
||||
}
|
||||
compressionLenHelperType(compression, dns.Ns[i])
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(dns.Extra); i++ {
|
||||
if dns.Extra[i] == nil {
|
||||
continue
|
||||
}
|
||||
l += dns.Extra[i].len()
|
||||
if dns.Compress {
|
||||
k, ok := compressionLenSearch(compression, dns.Extra[i].Header().Name)
|
||||
if ok {
|
||||
l += 1 - k
|
||||
}
|
||||
compressionLenHelper(compression, dns.Extra[i].Header().Name)
|
||||
k, ok = compressionLenSearchType(compression, dns.Extra[i])
|
||||
if ok {
|
||||
l += 1 - k
|
||||
}
|
||||
compressionLenHelperType(compression, dns.Extra[i])
|
||||
compressionLenHelper(c, r.Header().Name)
|
||||
k, ok = compressionLenSearchType(c, r)
|
||||
if ok {
|
||||
l += 1 - k
|
||||
}
|
||||
compressionLenHelperType(c, r)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
@ -970,97 +1005,6 @@ func compressionLenSearch(c map[string]int, s string) (int, bool) {
|
|||
return 0, false
|
||||
}
|
||||
|
||||
// TODO(miek): should add all types, because the all can be *used* for compression. Autogenerate from msg_generate and put in zmsg.go
|
||||
func compressionLenHelperType(c map[string]int, r RR) {
|
||||
switch x := r.(type) {
|
||||
case *NS:
|
||||
compressionLenHelper(c, x.Ns)
|
||||
case *MX:
|
||||
compressionLenHelper(c, x.Mx)
|
||||
case *CNAME:
|
||||
compressionLenHelper(c, x.Target)
|
||||
case *PTR:
|
||||
compressionLenHelper(c, x.Ptr)
|
||||
case *SOA:
|
||||
compressionLenHelper(c, x.Ns)
|
||||
compressionLenHelper(c, x.Mbox)
|
||||
case *MB:
|
||||
compressionLenHelper(c, x.Mb)
|
||||
case *MG:
|
||||
compressionLenHelper(c, x.Mg)
|
||||
case *MR:
|
||||
compressionLenHelper(c, x.Mr)
|
||||
case *MF:
|
||||
compressionLenHelper(c, x.Mf)
|
||||
case *MD:
|
||||
compressionLenHelper(c, x.Md)
|
||||
case *RT:
|
||||
compressionLenHelper(c, x.Host)
|
||||
case *RP:
|
||||
compressionLenHelper(c, x.Mbox)
|
||||
compressionLenHelper(c, x.Txt)
|
||||
case *MINFO:
|
||||
compressionLenHelper(c, x.Rmail)
|
||||
compressionLenHelper(c, x.Email)
|
||||
case *AFSDB:
|
||||
compressionLenHelper(c, x.Hostname)
|
||||
case *SRV:
|
||||
compressionLenHelper(c, x.Target)
|
||||
case *NAPTR:
|
||||
compressionLenHelper(c, x.Replacement)
|
||||
case *RRSIG:
|
||||
compressionLenHelper(c, x.SignerName)
|
||||
case *NSEC:
|
||||
compressionLenHelper(c, x.NextDomain)
|
||||
// HIP?
|
||||
}
|
||||
}
|
||||
|
||||
// Only search on compressing these types.
|
||||
func compressionLenSearchType(c map[string]int, r RR) (int, bool) {
|
||||
switch x := r.(type) {
|
||||
case *NS:
|
||||
return compressionLenSearch(c, x.Ns)
|
||||
case *MX:
|
||||
return compressionLenSearch(c, x.Mx)
|
||||
case *CNAME:
|
||||
return compressionLenSearch(c, x.Target)
|
||||
case *DNAME:
|
||||
return compressionLenSearch(c, x.Target)
|
||||
case *PTR:
|
||||
return compressionLenSearch(c, x.Ptr)
|
||||
case *SOA:
|
||||
k, ok := compressionLenSearch(c, x.Ns)
|
||||
k1, ok1 := compressionLenSearch(c, x.Mbox)
|
||||
if !ok && !ok1 {
|
||||
return 0, false
|
||||
}
|
||||
return k + k1, true
|
||||
case *MB:
|
||||
return compressionLenSearch(c, x.Mb)
|
||||
case *MG:
|
||||
return compressionLenSearch(c, x.Mg)
|
||||
case *MR:
|
||||
return compressionLenSearch(c, x.Mr)
|
||||
case *MF:
|
||||
return compressionLenSearch(c, x.Mf)
|
||||
case *MD:
|
||||
return compressionLenSearch(c, x.Md)
|
||||
case *RT:
|
||||
return compressionLenSearch(c, x.Host)
|
||||
case *MINFO:
|
||||
k, ok := compressionLenSearch(c, x.Rmail)
|
||||
k1, ok1 := compressionLenSearch(c, x.Email)
|
||||
if !ok && !ok1 {
|
||||
return 0, false
|
||||
}
|
||||
return k + k1, true
|
||||
case *AFSDB:
|
||||
return compressionLenSearch(c, x.Hostname)
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Copy returns a new RR which is a deep-copy of r.
|
||||
func Copy(r RR) RR { r1 := r.copy(); return r1 }
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue