mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
Switch from govendor to go modules. (#587)
Thanks to @BenoitKnecht for leading the way on this.
This commit is contained in:
245
vendor/github.com/miekg/dns/msg.go
generated
vendored
245
vendor/github.com/miekg/dns/msg.go
generated
vendored
@ -302,6 +302,12 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
|
||||
}
|
||||
// If we did compression and we find something add the pointer here
|
||||
if pointer != -1 {
|
||||
// Clear the msg buffer after the pointer location, otherwise
|
||||
// packDataNsec writes the wrong data to msg.
|
||||
tainted := msg[nameoffset:off]
|
||||
for i := range tainted {
|
||||
tainted[i] = 0
|
||||
}
|
||||
// We have two bytes (14 bits) to put the pointer in
|
||||
// if msg == nil, we will never do compression
|
||||
binary.BigEndian.PutUint16(msg[nameoffset:], uint16(pointer^0xC000))
|
||||
@ -367,12 +373,10 @@ Loop:
|
||||
var buf [3]byte
|
||||
bufs := strconv.AppendInt(buf[:0], int64(b), 10)
|
||||
s = append(s, '\\')
|
||||
for i := 0; i < 3-len(bufs); i++ {
|
||||
for i := len(bufs); i < 3; i++ {
|
||||
s = append(s, '0')
|
||||
}
|
||||
for _, r := range bufs {
|
||||
s = append(s, r)
|
||||
}
|
||||
s = append(s, bufs...)
|
||||
// presentation-format \DDD escapes add 3 extra bytes
|
||||
maxLen += 3
|
||||
} else {
|
||||
@ -512,7 +516,7 @@ func unpackTxt(msg []byte, off0 int) (ss []string, off int, err error) {
|
||||
off = off0
|
||||
var s string
|
||||
for off < len(msg) && err == nil {
|
||||
s, off, err = unpackTxtString(msg, off)
|
||||
s, off, err = unpackString(msg, off)
|
||||
if err == nil {
|
||||
ss = append(ss, s)
|
||||
}
|
||||
@ -520,39 +524,6 @@ func unpackTxt(msg []byte, off0 int) (ss []string, off int, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func unpackTxtString(msg []byte, offset int) (string, int, error) {
|
||||
if offset+1 > len(msg) {
|
||||
return "", offset, &Error{err: "overflow unpacking txt"}
|
||||
}
|
||||
l := int(msg[offset])
|
||||
if offset+l+1 > len(msg) {
|
||||
return "", offset, &Error{err: "overflow unpacking txt"}
|
||||
}
|
||||
s := make([]byte, 0, l)
|
||||
for _, b := range msg[offset+1 : offset+1+l] {
|
||||
switch b {
|
||||
case '"', '\\':
|
||||
s = append(s, '\\', b)
|
||||
default:
|
||||
if b < 32 || b > 127 { // unprintable
|
||||
var buf [3]byte
|
||||
bufs := strconv.AppendInt(buf[:0], int64(b), 10)
|
||||
s = append(s, '\\')
|
||||
for i := 0; i < 3-len(bufs); i++ {
|
||||
s = append(s, '0')
|
||||
}
|
||||
for _, r := range bufs {
|
||||
s = append(s, r)
|
||||
}
|
||||
} else {
|
||||
s = append(s, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
offset += 1 + l
|
||||
return string(s), offset, nil
|
||||
}
|
||||
|
||||
// Helpers for dealing with escaped bytes
|
||||
func isDigit(b byte) bool { return b >= '0' && b <= '9' }
|
||||
|
||||
@ -560,6 +531,10 @@ func dddToByte(s []byte) byte {
|
||||
return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0'))
|
||||
}
|
||||
|
||||
func dddStringToByte(s string) byte {
|
||||
return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0'))
|
||||
}
|
||||
|
||||
// Helper function for packing and unpacking
|
||||
func intToBytes(i *big.Int, length int) []byte {
|
||||
buf := i.Bytes()
|
||||
@ -595,6 +570,13 @@ func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) {
|
||||
if err != nil {
|
||||
return nil, len(msg), err
|
||||
}
|
||||
|
||||
return UnpackRRWithHeader(h, msg, off)
|
||||
}
|
||||
|
||||
// UnpackRRWithHeader unpacks the record type specific payload given an existing
|
||||
// RR_Header.
|
||||
func UnpackRRWithHeader(h RR_Header, msg []byte, off int) (rr RR, off1 int, err error) {
|
||||
end := off + int(h.Rdlength)
|
||||
|
||||
if fn, known := typeToUnpack[h.Rrtype]; !known {
|
||||
@ -612,8 +594,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)
|
||||
@ -684,18 +666,20 @@ func (dns *Msg) Pack() (msg []byte, err error) {
|
||||
return dns.PackBuffer(nil)
|
||||
}
|
||||
|
||||
// PackBuffer packs a Msg, using the given buffer buf. If buf is too small
|
||||
// a new buffer is allocated.
|
||||
// PackBuffer packs a Msg, using the given buffer buf. If buf is too small a new buffer is allocated.
|
||||
func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) {
|
||||
// We use a similar function in tsig.go's stripTsig.
|
||||
var (
|
||||
dh Header
|
||||
compression map[string]int
|
||||
)
|
||||
|
||||
var compression map[string]int
|
||||
if dns.Compress {
|
||||
compression = make(map[string]int) // Compression pointer mappings
|
||||
compression = make(map[string]int) // Compression pointer mappings.
|
||||
}
|
||||
return dns.packBufferWithCompressionMap(buf, compression)
|
||||
}
|
||||
|
||||
// packBufferWithCompressionMap packs a Msg, using the given buffer buf.
|
||||
func (dns *Msg) packBufferWithCompressionMap(buf []byte, compression map[string]int) (msg []byte, err error) {
|
||||
// We use a similar function in tsig.go's stripTsig.
|
||||
|
||||
var dh Header
|
||||
|
||||
if dns.Rcode < 0 || dns.Rcode > 0xFFF {
|
||||
return nil, ErrRcode
|
||||
@ -707,12 +691,11 @@ func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) {
|
||||
return nil, ErrExtendedRcode
|
||||
}
|
||||
opt.SetExtendedRcode(uint8(dns.Rcode >> 4))
|
||||
dns.Rcode &= 0xF
|
||||
}
|
||||
|
||||
// Convert convenient Msg into wire-like Header.
|
||||
dh.Id = dns.Id
|
||||
dh.Bits = uint16(dns.Opcode)<<11 | uint16(dns.Rcode)
|
||||
dh.Bits = uint16(dns.Opcode)<<11 | uint16(dns.Rcode&0xF)
|
||||
if dns.Response {
|
||||
dh.Bits |= _QR
|
||||
}
|
||||
@ -800,24 +783,30 @@ func (dns *Msg) Unpack(msg []byte) (err error) {
|
||||
}
|
||||
|
||||
dns.Id = dh.Id
|
||||
dns.Response = (dh.Bits & _QR) != 0
|
||||
dns.Response = dh.Bits&_QR != 0
|
||||
dns.Opcode = int(dh.Bits>>11) & 0xF
|
||||
dns.Authoritative = (dh.Bits & _AA) != 0
|
||||
dns.Truncated = (dh.Bits & _TC) != 0
|
||||
dns.RecursionDesired = (dh.Bits & _RD) != 0
|
||||
dns.RecursionAvailable = (dh.Bits & _RA) != 0
|
||||
dns.Zero = (dh.Bits & _Z) != 0
|
||||
dns.AuthenticatedData = (dh.Bits & _AD) != 0
|
||||
dns.CheckingDisabled = (dh.Bits & _CD) != 0
|
||||
dns.Authoritative = dh.Bits&_AA != 0
|
||||
dns.Truncated = dh.Bits&_TC != 0
|
||||
dns.RecursionDesired = dh.Bits&_RD != 0
|
||||
dns.RecursionAvailable = dh.Bits&_RA != 0
|
||||
dns.Zero = dh.Bits&_Z != 0
|
||||
dns.AuthenticatedData = dh.Bits&_AD != 0
|
||||
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
|
||||
@ -909,94 +898,138 @@ func (dns *Msg) String() string {
|
||||
// than packing it, measuring the size and discarding the buffer.
|
||||
func (dns *Msg) Len() int { return compressedLen(dns, dns.Compress) }
|
||||
|
||||
func compressedLenWithCompressionMap(dns *Msg, compression map[string]int) int {
|
||||
l := 12 // Message header is always 12 bytes
|
||||
for _, r := range dns.Question {
|
||||
compressionLenHelper(compression, r.Name, l)
|
||||
l += r.len()
|
||||
}
|
||||
l += compressionLenSlice(l, compression, dns.Answer)
|
||||
l += compressionLenSlice(l, compression, dns.Ns)
|
||||
l += compressionLenSlice(l, compression, dns.Extra)
|
||||
return l
|
||||
}
|
||||
|
||||
// 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
|
||||
if compress {
|
||||
compression := map[string]int{}
|
||||
for _, r := range dns.Question {
|
||||
return compressedLenWithCompressionMap(dns, compression)
|
||||
}
|
||||
l := 12 // Message header is always 12 bytes
|
||||
|
||||
for _, r := range dns.Question {
|
||||
l += r.len()
|
||||
}
|
||||
for _, r := range dns.Answer {
|
||||
if r != nil {
|
||||
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 _, r := range dns.Ns {
|
||||
if r != nil {
|
||||
l += r.len()
|
||||
}
|
||||
}
|
||||
for _, r := range dns.Extra {
|
||||
if r != nil {
|
||||
l += r.len()
|
||||
}
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func compressionLenSlice(c map[string]int, rs []RR) int {
|
||||
var l int
|
||||
func compressionLenSlice(lenp int, c map[string]int, rs []RR) int {
|
||||
initLen := lenp
|
||||
for _, r := range rs {
|
||||
if r == nil {
|
||||
continue
|
||||
}
|
||||
l += r.len()
|
||||
k, ok := compressionLenSearch(c, r.Header().Name)
|
||||
// TmpLen is to track len of record at 14bits boudaries
|
||||
tmpLen := lenp
|
||||
|
||||
x := r.len()
|
||||
// track this length, and the global length in len, while taking compression into account for both.
|
||||
k, ok, _ := compressionLenSearch(c, r.Header().Name)
|
||||
if ok {
|
||||
l += 1 - k
|
||||
// Size of x is reduced by k, but we add 1 since k includes the '.' and label descriptor take 2 bytes
|
||||
// so, basically x:= x - k - 1 + 2
|
||||
x += 1 - k
|
||||
}
|
||||
compressionLenHelper(c, r.Header().Name)
|
||||
k, ok = compressionLenSearchType(c, r)
|
||||
|
||||
tmpLen += compressionLenHelper(c, r.Header().Name, tmpLen)
|
||||
k, ok, _ = compressionLenSearchType(c, r)
|
||||
if ok {
|
||||
l += 1 - k
|
||||
x += 1 - k
|
||||
}
|
||||
compressionLenHelperType(c, r)
|
||||
lenp += x
|
||||
tmpLen = lenp
|
||||
tmpLen += compressionLenHelperType(c, r, tmpLen)
|
||||
|
||||
}
|
||||
return l
|
||||
return lenp - initLen
|
||||
}
|
||||
|
||||
// Put the parts of the name in the compression map.
|
||||
func compressionLenHelper(c map[string]int, s string) {
|
||||
// Put the parts of the name in the compression map, return the size in bytes added in payload
|
||||
func compressionLenHelper(c map[string]int, s string, currentLen int) int {
|
||||
if currentLen > maxCompressionOffset {
|
||||
// We won't be able to add any label that could be re-used later anyway
|
||||
return 0
|
||||
}
|
||||
if _, ok := c[s]; ok {
|
||||
return 0
|
||||
}
|
||||
initLen := currentLen
|
||||
pref := ""
|
||||
prev := s
|
||||
lbs := Split(s)
|
||||
for j := len(lbs) - 1; j >= 0; j-- {
|
||||
for j := 0; j < len(lbs); j++ {
|
||||
pref = s[lbs[j]:]
|
||||
currentLen += len(prev) - len(pref)
|
||||
prev = pref
|
||||
if _, ok := c[pref]; !ok {
|
||||
c[pref] = len(pref)
|
||||
// If first byte label is within the first 14bits, it might be re-used later
|
||||
if currentLen < maxCompressionOffset {
|
||||
c[pref] = currentLen
|
||||
}
|
||||
} else {
|
||||
added := currentLen - initLen
|
||||
if j > 0 {
|
||||
// We added a new PTR
|
||||
added += 2
|
||||
}
|
||||
return added
|
||||
}
|
||||
}
|
||||
return currentLen - initLen
|
||||
}
|
||||
|
||||
// Look for each part in the compression map and returns its length,
|
||||
// keep on searching so we get the longest match.
|
||||
func compressionLenSearch(c map[string]int, s string) (int, bool) {
|
||||
// Will return the size of compression found, whether a match has been
|
||||
// found and the size of record if added in payload
|
||||
func compressionLenSearch(c map[string]int, s string) (int, bool, int) {
|
||||
off := 0
|
||||
end := false
|
||||
if s == "" { // don't bork on bogus data
|
||||
return 0, false
|
||||
return 0, false, 0
|
||||
}
|
||||
fullSize := 0
|
||||
for {
|
||||
if _, ok := c[s[off:]]; ok {
|
||||
return len(s[off:]), true
|
||||
return len(s[off:]), true, fullSize + off
|
||||
}
|
||||
if end {
|
||||
break
|
||||
}
|
||||
// Each label descriptor takes 2 bytes, add it
|
||||
fullSize += 2
|
||||
off, end = NextLabel(s, off)
|
||||
}
|
||||
return 0, false
|
||||
return 0, false, fullSize + len(s)
|
||||
}
|
||||
|
||||
// Copy returns a new RR which is a deep-copy of r.
|
||||
|
Reference in New Issue
Block a user