Skip to content

Commit

Permalink
Fixed len computation when size just goes beyond 14 bits (#668)
Browse files Browse the repository at this point in the history
* Fixed len computation when size just goes beyond 14 bits

* Added bouds checks around 14bits

* Len() always right including when around 14bits boudaries

* Avoid splitting into labels when not applicable

* Fixed comments

* Added comments in code

* Added new test cases

* Fixed computation of Len() for SRV and all kind of records

* Fixed Sign that was relying on non-copy for Unit tests

* Removed unused padding

* Fixed typo in PackBuffer() function

* Added comment about packBufferWithCompressionMap() for testing purposes
  • Loading branch information
pierresouchay authored and miekg committed May 16, 2018
1 parent 621df09 commit 0964911
Show file tree
Hide file tree
Showing 4 changed files with 394 additions and 118 deletions.
28 changes: 19 additions & 9 deletions compress_generate.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

199 changes: 198 additions & 1 deletion length_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"encoding/hex"
"fmt"
"net"
"reflect"
"strings"
"testing"
)

Expand Down Expand Up @@ -52,6 +54,7 @@ func TestMsgCompressLength(t *testing.T) {
func TestMsgLength(t *testing.T) {
makeMsg := func(question string, ans, ns, e []RR) *Msg {
msg := new(Msg)
msg.Compress = true
msg.SetQuestion(Fqdn(question), TypeANY)
msg.Answer = append(msg.Answer, ans...)
msg.Ns = append(msg.Ns, ns...)
Expand Down Expand Up @@ -79,6 +82,92 @@ func TestMsgLength(t *testing.T) {
}
}

func TestCompressionLenHelper(t *testing.T) {
c := make(map[string]int)
compressionLenHelper(c, "example.com", 12)
if c["example.com"] != 12 {
t.Errorf("bad %d", c["example.com"])
}
if c["com"] != 20 {
t.Errorf("bad %d", c["com"])
}

// Test boundaries
c = make(map[string]int)
// foo label starts at 16379
// com label starts at 16384
compressionLenHelper(c, "foo.com", 16379)
if c["foo.com"] != 16379 {
t.Errorf("bad %d", c["foo.com"])
}
// com label is accessible
if c["com"] != 16383 {
t.Errorf("bad %d", c["com"])
}

c = make(map[string]int)
// foo label starts at 16379
// com label starts at 16385 => outside range
compressionLenHelper(c, "foo.com", 16380)
if c["foo.com"] != 16380 {
t.Errorf("bad %d", c["foo.com"])
}
// com label is NOT accessible
if c["com"] != 0 {
t.Errorf("bad %d", c["com"])
}

c = make(map[string]int)
compressionLenHelper(c, "example.com", 16375)
if c["example.com"] != 16375 {
t.Errorf("bad %d", c["example.com"])
}
// com starts AFTER 16384
if c["com"] != 16383 {
t.Errorf("bad %d", c["com"])
}

c = make(map[string]int)
compressionLenHelper(c, "example.com", 16376)
if c["example.com"] != 16376 {
t.Errorf("bad %d", c["example.com"])
}
// com starts AFTER 16384
if c["com"] != 0 {
t.Errorf("bad %d", c["com"])
}
}

func TestCompressionLenSearch(t *testing.T) {
c := make(map[string]int)
compressed, ok, fullSize := compressionLenSearch(c, "a.b.org.")
if compressed != 0 || ok || fullSize != 14 {
panic(fmt.Errorf("Failed: compressed:=%d, ok:=%v, fullSize:=%d", compressed, ok, fullSize))
}
c["org."] = 3
compressed, ok, fullSize = compressionLenSearch(c, "a.b.org.")
if compressed != 4 || !ok || fullSize != 8 {
panic(fmt.Errorf("Failed: compressed:=%d, ok:=%v, fullSize:=%d", compressed, ok, fullSize))
}
c["b.org."] = 5
compressed, ok, fullSize = compressionLenSearch(c, "a.b.org.")
if compressed != 6 || !ok || fullSize != 4 {
panic(fmt.Errorf("Failed: compressed:=%d, ok:=%v, fullSize:=%d", compressed, ok, fullSize))
}
// Not found long compression
c["x.b.org."] = 5
compressed, ok, fullSize = compressionLenSearch(c, "a.b.org.")
if compressed != 6 || !ok || fullSize != 4 {
panic(fmt.Errorf("Failed: compressed:=%d, ok:=%v, fullSize:=%d", compressed, ok, fullSize))
}
// Found long compression
c["a.b.org."] = 5
compressed, ok, fullSize = compressionLenSearch(c, "a.b.org.")
if compressed != 8 || !ok || fullSize != 0 {
panic(fmt.Errorf("Failed: compressed:=%d, ok:=%v, fullSize:=%d", compressed, ok, fullSize))
}
}

func TestMsgLength2(t *testing.T) {
// Serialized replies
var testMessages = []string{
Expand Down Expand Up @@ -159,7 +248,7 @@ func TestMsgCompressLengthLargeRecords(t *testing.T) {
msg.SetQuestion("my.service.acme.", TypeSRV)
j := 1
for i := 0; i < 250; i++ {
target := fmt.Sprintf("host-redis-%d-%d.test.acme.com.node.dc1.consul.", j, i)
target := fmt.Sprintf("host-redis-1-%d.test.acme.com.node.dc1.consul.", i)
msg.Answer = append(msg.Answer, &SRV{Hdr: RR_Header{Name: "redis.service.consul.", Class: 1, Rrtype: TypeSRV, Ttl: 0x3c}, Port: 0x4c57, Target: target})
msg.Extra = append(msg.Extra, &CNAME{Hdr: RR_Header{Name: target, Class: 1, Rrtype: TypeCNAME, Ttl: 0x3c}, Target: fmt.Sprintf("fx.168.%d.%d.", j, i)})
}
Expand All @@ -172,3 +261,111 @@ func TestMsgCompressLengthLargeRecords(t *testing.T) {
t.Fatalf("predicted compressed length is wrong: predicted %s (len=%d) %d, actual %d", msg.Question[0].Name, len(msg.Answer), predicted, len(buf))
}
}

func TestCompareCompressionMapsForANY(t *testing.T) {
msg := new(Msg)
msg.Compress = true
msg.SetQuestion("a.service.acme.", TypeANY)
// Be sure to have more than 14bits
for i := 0; i < 2000; i++ {
target := fmt.Sprintf("host.app-%d.x%d.test.acme.", i%250, i)
msg.Answer = append(msg.Answer, &AAAA{Hdr: RR_Header{Name: target, Rrtype: TypeAAAA, Class: ClassINET, Ttl: 0x3c}, AAAA: net.IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, byte(i / 255), byte(i % 255)}})
msg.Answer = append(msg.Answer, &A{Hdr: RR_Header{Name: target, Rrtype: TypeA, Class: ClassINET, Ttl: 0x3c}, A: net.IP{127, 0, byte(i / 255), byte(i % 255)}})
if msg.Len() > 16384 {
break
}
}
for labelSize := 0; labelSize < 63; labelSize++ {
msg.SetQuestion(fmt.Sprintf("a%s.service.acme.", strings.Repeat("x", labelSize)), TypeANY)

compressionFake := make(map[string]int)
lenFake := compressedLenWithCompressionMap(msg, compressionFake)

compressionReal := make(map[string]int)
buf, err := msg.packBufferWithCompressionMap(nil, compressionReal)
if err != nil {
t.Fatal(err)
}
if lenFake != len(buf) {
t.Fatalf("padding= %d ; Predicted len := %d != real:= %d", labelSize, lenFake, len(buf))
}
if !reflect.DeepEqual(compressionFake, compressionReal) {
t.Fatalf("padding= %d ; Fake Compression Map != Real Compression Map\n*** Real:= %v\n\n***Fake:= %v", labelSize, compressionReal, compressionFake)
}
}
}

func TestCompareCompressionMapsForSRV(t *testing.T) {
msg := new(Msg)
msg.Compress = true
msg.SetQuestion("a.service.acme.", TypeSRV)
// Be sure to have more than 14bits
for i := 0; i < 2000; i++ {
target := fmt.Sprintf("host.app-%d.x%d.test.acme.", i%250, i)
msg.Answer = append(msg.Answer, &SRV{Hdr: RR_Header{Name: "redis.service.consul.", Class: ClassINET, Rrtype: TypeSRV, Ttl: 0x3c}, Port: 0x4c57, Target: target})
msg.Extra = append(msg.Extra, &A{Hdr: RR_Header{Name: target, Rrtype: TypeA, Class: ClassINET, Ttl: 0x3c}, A: net.IP{127, 0, byte(i / 255), byte(i % 255)}})
if msg.Len() > 16384 {
break
}
}
for labelSize := 0; labelSize < 63; labelSize++ {
msg.SetQuestion(fmt.Sprintf("a%s.service.acme.", strings.Repeat("x", labelSize)), TypeAAAA)

compressionFake := make(map[string]int)
lenFake := compressedLenWithCompressionMap(msg, compressionFake)

compressionReal := make(map[string]int)
buf, err := msg.packBufferWithCompressionMap(nil, compressionReal)
if err != nil {
t.Fatal(err)
}
if lenFake != len(buf) {
t.Fatalf("padding= %d ; Predicted len := %d != real:= %d", labelSize, lenFake, len(buf))
}
if !reflect.DeepEqual(compressionFake, compressionReal) {
t.Fatalf("padding= %d ; Fake Compression Map != Real Compression Map\n*** Real:= %v\n\n***Fake:= %v", labelSize, compressionReal, compressionFake)
}
}
}

func TestMsgCompressLengthLargeRecordsWithPaddingPermutation(t *testing.T) {
msg := new(Msg)
msg.Compress = true
msg.SetQuestion("my.service.acme.", TypeSRV)

for i := 0; i < 250; i++ {
target := fmt.Sprintf("host-redis-x-%d.test.acme.com.node.dc1.consul.", i)
msg.Answer = append(msg.Answer, &SRV{Hdr: RR_Header{Name: "redis.service.consul.", Class: 1, Rrtype: TypeSRV, Ttl: 0x3c}, Port: 0x4c57, Target: target})
msg.Extra = append(msg.Extra, &CNAME{Hdr: RR_Header{Name: target, Class: ClassINET, Rrtype: TypeCNAME, Ttl: 0x3c}, Target: fmt.Sprintf("fx.168.x.%d.", i)})
}
for labelSize := 1; labelSize < 63; labelSize++ {
msg.SetQuestion(fmt.Sprintf("my.%s.service.acme.", strings.Repeat("x", labelSize)), TypeSRV)
predicted := msg.Len()
buf, err := msg.Pack()
if err != nil {
t.Error(err)
}
if predicted != len(buf) {
t.Fatalf("padding= %d ; predicted compressed length is wrong: predicted %s (len=%d) %d, actual %d", labelSize, msg.Question[0].Name, len(msg.Answer), predicted, len(buf))
}
}
}

func TestMsgCompressLengthLargeRecordsAllValues(t *testing.T) {
msg := new(Msg)
msg.Compress = true
msg.SetQuestion("redis.service.consul.", TypeSRV)
for i := 0; i < 900; i++ {
target := fmt.Sprintf("host-redis-%d-%d.test.acme.com.node.dc1.consul.", i/256, i%256)
msg.Answer = append(msg.Answer, &SRV{Hdr: RR_Header{Name: "redis.service.consul.", Class: 1, Rrtype: TypeSRV, Ttl: 0x3c}, Port: 0x4c57, Target: target})
msg.Extra = append(msg.Extra, &CNAME{Hdr: RR_Header{Name: target, Class: ClassINET, Rrtype: TypeCNAME, Ttl: 0x3c}, Target: fmt.Sprintf("fx.168.%d.%d.", i/256, i%256)})
predicted := msg.Len()
buf, err := msg.Pack()
if err != nil {
t.Error(err)
}
if predicted != len(buf) {
t.Fatalf("predicted compressed length is wrong for %d records: predicted %s (len=%d) %d, actual %d", i, msg.Question[0].Name, len(msg.Answer), predicted, len(buf))
}
}
}
Loading

0 comments on commit 0964911

Please sign in to comment.