Skip to content

When Compress is enable AND size if large, msg.Len() != len(msg.Pack()) #657

@pierresouchay

Description

@pierresouchay

While working on a patch for Consul hashicorp/consul#3948 I found a bug in this library because when compression is activated, msg.Len() is not the same as len(msg.Pack())

Since Consul was using a very old version of the library, I thought it had been fixed, so Consul upgraded its version to 1.0.4 after this issue hashicorp/consul#3977

But still, the issue still exists with version 1.0.4.

I created a test case that shows it into action: (to paste into dns_test.go ):

func TestMsgCompressLengthLargeRecords(t *testing.T) {
	msg := new(Msg)
	msg.Compress = true
	msg.SetQuestion(Fqdn("my.service.acme."), TypeSRV)
	numEntries := 0
	for j := 0; j < 10; j++ {
		for i := 0; i < 255; i++ {
			numEntries++
			target := fmt.Sprintf("host-redis-%d-%d.test.acme.com.node.dc1.consul.", j, i)
			msg.Answer = append(msg.Answer, &SRV{Hdr: RR_Header{Name: "redis.service.consul.", Rrtype: 0x21, Class: 0x1, Ttl: 0x3c}, Port: 0x4c57, Target: target})
			msg.Extra = append(msg.Extra, &CNAME{Hdr: RR_Header{Name: target, Rrtype: 0x1, Class: 0x1, Ttl: 0x3c}, Target: fmt.Sprintf("fx.168.%d.%d.", j, i)})
			predicted := msg.Len()
			buf, err := msg.Pack()
			if err != nil {
				t.Error(err)
			}
			if predicted != len(buf) {
				t.Errorf("predicted compressed length is wrong: predicted %s (len=%d) %d, actual %d with %d entries",
					msg.Question[0].Name, len(msg.Answer), predicted, len(buf), numEntries)
			}
		}
	}
}

This test fails this way:

go test github.com/miekg/dns -run ^TestMsgCompressLengthLargeRecords$
--- FAIL: TestMsgCompressLengthLargeRecords (9.82s)
	dns_test.go:309: predicted compressed length is wrong: predicted my.service.acme. (len=250) 22833, actual 22850 with 250 entries
	dns_test.go:309: predicted compressed length is wrong: predicted my.service.acme. (len=251) 22925, actual 22959 with 251 entries
	dns_test.go:309: predicted compressed length is wrong: predicted my.service.acme. (len=252) 23017, actual 23068 with 252 entries
	dns_test.go:309: predicted compressed length is wrong: predicted my.service.acme. (len=253) 23109, actual 23177 with 253 entries
	dns_test.go:309: predicted compressed length is wrong: predicted my.service.acme. (len=254) 23201, actual 23286 with 254 entries
	dns_test.go:309: predicted compressed length is wrong: predicted my.service.acme. (len=255) 23293, actual 23395 with 255 entries

Which is exactly what I did see while patching Consul.

In the patch I am working on, since Consul might create very large SRV records (several thousands), in order to have a good response, we are trying to fill DNS at its maximum, so we compute the size compressed, see if it is more than 64K, if not send the response, otherwise, remove records and retry.

So, basically, the size uncompressed is supposed to be far bigger than 64k while I am trying to improve the patch to send 64k MAX compressed.

Note that this test passes without any issue with compression disabled.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions