summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/miekg/dns/msg.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/miekg/dns/msg.go')
-rw-r--r--vendor/github.com/miekg/dns/msg.go127
1 files changed, 78 insertions, 49 deletions
diff --git a/vendor/github.com/miekg/dns/msg.go b/vendor/github.com/miekg/dns/msg.go
index 276e6b027..dcd3b6a5e 100644
--- a/vendor/github.com/miekg/dns/msg.go
+++ b/vendor/github.com/miekg/dns/msg.go
@@ -691,18 +691,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
@@ -714,12 +716,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
}
@@ -922,23 +923,27 @@ 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 {
- l += r.len()
- compressionLenHelper(compression, r.Name)
- }
- l += compressionLenSlice(l, compression, dns.Answer)
- l += compressionLenSlice(l, compression, dns.Ns)
- l += compressionLenSlice(l, compression, dns.Extra)
-
- return l
+ return compressedLenWithCompressionMap(dns, compression)
}
+ l := 12 // Message header is always 12 bytes
for _, r := range dns.Question {
l += r.len()
@@ -962,70 +967,94 @@ func compressedLen(dns *Msg, compress bool) int {
return l
}
-func compressionLenSlice(len int, 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
}
- // track this length, and the global length in len, while taking compression into account for both.
- x := r.len()
- l += x
- len += x
+ // TmpLen is to track len of record at 14bits boudaries
+ tmpLen := lenp
- k, ok := compressionLenSearch(c, r.Header().Name)
+ 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
- len += 1 - k
- }
-
- if len < maxCompressionOffset {
- compressionLenHelper(c, r.Header().Name)
+ // 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
}
- k, ok = compressionLenSearchType(c, r)
+ tmpLen += compressionLenHelper(c, r.Header().Name, tmpLen)
+ k, ok, _ = compressionLenSearchType(c, r)
if ok {
- l += 1 - k
- len += 1 - k
+ x += 1 - k
}
+ lenp += x
+ tmpLen = lenp
+ tmpLen += compressionLenHelperType(c, r, tmpLen)
- if len < maxCompressionOffset {
- compressionLenHelperType(c, r)
- }
}
- 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.