1package dns 2 3import ( 4 "encoding/hex" 5 "fmt" 6 "net" 7 "strings" 8 "testing" 9) 10 11func TestCompressLength(t *testing.T) { 12 m := new(Msg) 13 m.SetQuestion("miek.nl.", TypeMX) 14 ul := m.Len() 15 m.Compress = true 16 if ul != m.Len() { 17 t.Fatalf("should be equal") 18 } 19} 20 21// Does the predicted length match final packed length? 22func TestMsgCompressLength(t *testing.T) { 23 makeMsg := func(question string, ans, ns, e []RR) *Msg { 24 msg := new(Msg) 25 msg.SetQuestion(Fqdn(question), TypeANY) 26 msg.Answer = append(msg.Answer, ans...) 27 msg.Ns = append(msg.Ns, ns...) 28 msg.Extra = append(msg.Extra, e...) 29 msg.Compress = true 30 return msg 31 } 32 33 name1 := "12345678901234567890123456789012345.12345678.123." 34 rrA := testRR(name1 + " 3600 IN A 192.0.2.1") 35 rrMx := testRR(name1 + " 3600 IN MX 10 " + name1) 36 tests := []*Msg{ 37 makeMsg(name1, []RR{rrA}, nil, nil), 38 makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)} 39 40 for _, msg := range tests { 41 predicted := msg.Len() 42 buf, err := msg.Pack() 43 if err != nil { 44 t.Error(err) 45 } 46 if predicted < len(buf) { 47 t.Errorf("predicted compressed length is wrong: predicted %s (len=%d) %d, actual %d", 48 msg.Question[0].Name, len(msg.Answer), predicted, len(buf)) 49 } 50 } 51} 52 53func TestMsgLength(t *testing.T) { 54 makeMsg := func(question string, ans, ns, e []RR) *Msg { 55 msg := new(Msg) 56 msg.Compress = true 57 msg.SetQuestion(Fqdn(question), TypeANY) 58 msg.Answer = append(msg.Answer, ans...) 59 msg.Ns = append(msg.Ns, ns...) 60 msg.Extra = append(msg.Extra, e...) 61 return msg 62 } 63 64 name1 := "12345678901234567890123456789012345.12345678.123." 65 rrA := testRR(name1 + " 3600 IN A 192.0.2.1") 66 rrMx := testRR(name1 + " 3600 IN MX 10 " + name1) 67 tests := []*Msg{ 68 makeMsg(name1, []RR{rrA}, nil, nil), 69 makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)} 70 71 for _, msg := range tests { 72 predicted := msg.Len() 73 buf, err := msg.Pack() 74 if err != nil { 75 t.Error(err) 76 } 77 if predicted < len(buf) { 78 t.Errorf("predicted length is wrong: predicted %s (len=%d), actual %d", 79 msg.Question[0].Name, predicted, len(buf)) 80 } 81 } 82} 83 84func TestCompressionLenSearchInsert(t *testing.T) { 85 c := make(map[string]struct{}) 86 compressionLenSearch(c, "example.com", 12) 87 if _, ok := c["example.com"]; !ok { 88 t.Errorf("bad example.com") 89 } 90 if _, ok := c["com"]; !ok { 91 t.Errorf("bad com") 92 } 93 94 // Test boundaries 95 c = make(map[string]struct{}) 96 // foo label starts at 16379 97 // com label starts at 16384 98 compressionLenSearch(c, "foo.com", 16379) 99 if _, ok := c["foo.com"]; !ok { 100 t.Errorf("bad foo.com") 101 } 102 // com label is accessible 103 if _, ok := c["com"]; !ok { 104 t.Errorf("bad com") 105 } 106 107 c = make(map[string]struct{}) 108 // foo label starts at 16379 109 // com label starts at 16385 => outside range 110 compressionLenSearch(c, "foo.com", 16380) 111 if _, ok := c["foo.com"]; !ok { 112 t.Errorf("bad foo.com") 113 } 114 // com label is NOT accessible 115 if _, ok := c["com"]; ok { 116 t.Errorf("bad com") 117 } 118 119 c = make(map[string]struct{}) 120 compressionLenSearch(c, "example.com", 16375) 121 if _, ok := c["example.com"]; !ok { 122 t.Errorf("bad example.com") 123 } 124 // com starts AFTER 16384 125 if _, ok := c["com"]; !ok { 126 t.Errorf("bad com") 127 } 128 129 c = make(map[string]struct{}) 130 compressionLenSearch(c, "example.com", 16376) 131 if _, ok := c["example.com"]; !ok { 132 t.Errorf("bad example.com") 133 } 134 // com starts AFTER 16384 135 if _, ok := c["com"]; ok { 136 t.Errorf("bad com") 137 } 138} 139 140func TestCompressionLenSearch(t *testing.T) { 141 c := make(map[string]struct{}) 142 compressed, ok := compressionLenSearch(c, "a.b.org.", maxCompressionOffset) 143 if compressed != 0 || ok { 144 t.Errorf("Failed: compressed:=%d, ok:=%v", compressed, ok) 145 } 146 c["org."] = struct{}{} 147 compressed, ok = compressionLenSearch(c, "a.b.org.", maxCompressionOffset) 148 if compressed != 4 || !ok { 149 t.Errorf("Failed: compressed:=%d, ok:=%v", compressed, ok) 150 } 151 c["b.org."] = struct{}{} 152 compressed, ok = compressionLenSearch(c, "a.b.org.", maxCompressionOffset) 153 if compressed != 2 || !ok { 154 t.Errorf("Failed: compressed:=%d, ok:=%v", compressed, ok) 155 } 156 // Not found long compression 157 c["x.b.org."] = struct{}{} 158 compressed, ok = compressionLenSearch(c, "a.b.org.", maxCompressionOffset) 159 if compressed != 2 || !ok { 160 t.Errorf("Failed: compressed:=%d, ok:=%v", compressed, ok) 161 } 162 // Found long compression 163 c["a.b.org."] = struct{}{} 164 compressed, ok = compressionLenSearch(c, "a.b.org.", maxCompressionOffset) 165 if compressed != 0 || !ok { 166 t.Errorf("Failed: compressed:=%d, ok:=%v", compressed, ok) 167 } 168} 169 170func TestMsgLength2(t *testing.T) { 171 // Serialized replies 172 var testMessages = []string{ 173 // google.com. IN A? 174 "064e81800001000b0004000506676f6f676c6503636f6d0000010001c00c00010001000000050004adc22986c00c00010001000000050004adc22987c00c00010001000000050004adc22988c00c00010001000000050004adc22989c00c00010001000000050004adc2298ec00c00010001000000050004adc22980c00c00010001000000050004adc22981c00c00010001000000050004adc22982c00c00010001000000050004adc22983c00c00010001000000050004adc22984c00c00010001000000050004adc22985c00c00020001000000050006036e7331c00cc00c00020001000000050006036e7332c00cc00c00020001000000050006036e7333c00cc00c00020001000000050006036e7334c00cc0d800010001000000050004d8ef200ac0ea00010001000000050004d8ef220ac0fc00010001000000050004d8ef240ac10e00010001000000050004d8ef260a0000290500000000050000", 175 // amazon.com. IN A? (reply has no EDNS0 record) 176 "6de1818000010004000a000806616d617a6f6e03636f6d0000010001c00c000100010000000500044815c2d4c00c000100010000000500044815d7e8c00c00010001000000050004b02062a6c00c00010001000000050004cdfbf236c00c000200010000000500140570646e733408756c747261646e73036f726700c00c000200010000000500150570646e733508756c747261646e7304696e666f00c00c000200010000000500160570646e733608756c747261646e7302636f02756b00c00c00020001000000050014036e7331037033310664796e656374036e657400c00c00020001000000050006036e7332c0cfc00c00020001000000050006036e7333c0cfc00c00020001000000050006036e7334c0cfc00c000200010000000500110570646e733108756c747261646e73c0dac00c000200010000000500080570646e7332c127c00c000200010000000500080570646e7333c06ec0cb00010001000000050004d04e461fc0eb00010001000000050004cc0dfa1fc0fd00010001000000050004d04e471fc10f00010001000000050004cc0dfb1fc12100010001000000050004cc4a6c01c121001c000100000005001020010502f3ff00000000000000000001c13e00010001000000050004cc4a6d01c13e001c0001000000050010261000a1101400000000000000000001", 177 // yahoo.com. IN A? 178 "fc2d81800001000300070008057961686f6f03636f6d0000010001c00c00010001000000050004628afd6dc00c00010001000000050004628bb718c00c00010001000000050004cebe242dc00c00020001000000050006036e7336c00cc00c00020001000000050006036e7338c00cc00c00020001000000050006036e7331c00cc00c00020001000000050006036e7332c00cc00c00020001000000050006036e7333c00cc00c00020001000000050006036e7334c00cc00c00020001000000050006036e7335c00cc07b0001000100000005000444b48310c08d00010001000000050004448eff10c09f00010001000000050004cb54dd35c0b100010001000000050004628a0b9dc0c30001000100000005000477a0f77cc05700010001000000050004ca2bdfaac06900010001000000050004caa568160000290500000000050000", 179 // microsoft.com. IN A? 180 "f4368180000100020005000b096d6963726f736f667403636f6d0000010001c00c0001000100000005000440040b25c00c0001000100000005000441373ac9c00c0002000100000005000e036e7331046d736674036e657400c00c00020001000000050006036e7332c04fc00c00020001000000050006036e7333c04fc00c00020001000000050006036e7334c04fc00c00020001000000050006036e7335c04fc04b000100010000000500044137253ec04b001c00010000000500102a010111200500000000000000010001c0650001000100000005000440043badc065001c00010000000500102a010111200600060000000000010001c07700010001000000050004d5c7b435c077001c00010000000500102a010111202000000000000000010001c08900010001000000050004cf2e4bfec089001c00010000000500102404f800200300000000000000010001c09b000100010000000500044137e28cc09b001c00010000000500102a010111200f000100000000000100010000290500000000050000", 181 // google.com. IN MX? 182 "724b8180000100050004000b06676f6f676c6503636f6d00000f0001c00c000f000100000005000c000a056173706d78016cc00cc00c000f0001000000050009001404616c7431c02ac00c000f0001000000050009001e04616c7432c02ac00c000f0001000000050009002804616c7433c02ac00c000f0001000000050009003204616c7434c02ac00c00020001000000050006036e7332c00cc00c00020001000000050006036e7333c00cc00c00020001000000050006036e7334c00cc00c00020001000000050006036e7331c00cc02a00010001000000050004adc2421bc02a001c00010000000500102a00145040080c01000000000000001bc04200010001000000050004adc2461bc05700010001000000050004adc2451bc06c000100010000000500044a7d8f1bc081000100010000000500044a7d191bc0ca00010001000000050004d8ef200ac09400010001000000050004d8ef220ac0a600010001000000050004d8ef240ac0b800010001000000050004d8ef260a0000290500000000050000", 183 // reddit.com. IN A? 184 "12b98180000100080000000c0672656464697403636f6d0000020001c00c0002000100000005000f046175733204616b616d036e657400c00c000200010000000500070475736534c02dc00c000200010000000500070475737733c02dc00c000200010000000500070475737735c02dc00c00020001000000050008056173696131c02dc00c00020001000000050008056173696139c02dc00c00020001000000050008056e73312d31c02dc00c0002000100000005000a076e73312d313935c02dc02800010001000000050004c30a242ec04300010001000000050004451f1d39c05600010001000000050004451f3bc7c0690001000100000005000460073240c07c000100010000000500046007fb81c090000100010000000500047c283484c090001c00010000000500102a0226f0006700000000000000000064c0a400010001000000050004c16c5b01c0a4001c000100000005001026001401000200000000000000000001c0b800010001000000050004c16c5bc3c0b8001c0001000000050010260014010002000000000000000000c30000290500000000050000", 185 } 186 187 for i, hexData := range testMessages { 188 // we won't fail the decoding of the hex 189 input, _ := hex.DecodeString(hexData) 190 191 m := new(Msg) 192 m.Unpack(input) 193 m.Compress = true 194 lenComp := m.Len() 195 b, _ := m.Pack() 196 pacComp := len(b) 197 m.Compress = false 198 lenUnComp := m.Len() 199 b, _ = m.Pack() 200 pacUnComp := len(b) 201 if pacComp != lenComp { 202 t.Errorf("msg.Len(compressed)=%d actual=%d for test %d", lenComp, pacComp, i) 203 } 204 if pacUnComp != lenUnComp { 205 t.Errorf("msg.Len(uncompressed)=%d actual=%d for test %d", lenUnComp, pacUnComp, i) 206 } 207 } 208} 209 210func TestMsgLengthCompressionMalformed(t *testing.T) { 211 // SOA with empty hostmaster, which is illegal 212 soa := &SOA{Hdr: RR_Header{Name: ".", Rrtype: TypeSOA, Class: ClassINET, Ttl: 12345}, 213 Ns: ".", 214 Mbox: "", 215 Serial: 0, 216 Refresh: 28800, 217 Retry: 7200, 218 Expire: 604800, 219 Minttl: 60} 220 m := new(Msg) 221 m.Compress = true 222 m.Ns = []RR{soa} 223 m.Len() // Should not crash. 224} 225 226func TestMsgCompressLength2(t *testing.T) { 227 msg := new(Msg) 228 msg.Compress = true 229 msg.SetQuestion(Fqdn("bliep."), TypeANY) 230 msg.Answer = append(msg.Answer, &SRV{Hdr: RR_Header{Name: "blaat.", Rrtype: 0x21, Class: 0x1, Ttl: 0x3c}, Port: 0x4c57, Target: "foo.bar."}) 231 msg.Extra = append(msg.Extra, &A{Hdr: RR_Header{Name: "foo.bar.", Rrtype: 0x1, Class: 0x1, Ttl: 0x3c}, A: net.IP{0xac, 0x11, 0x0, 0x3}}) 232 predicted := msg.Len() 233 buf, err := msg.Pack() 234 if err != nil { 235 t.Error(err) 236 } 237 if predicted != len(buf) { 238 t.Errorf("predicted compressed length is wrong: predicted %s (len=%d) %d, actual %d", 239 msg.Question[0].Name, len(msg.Answer), predicted, len(buf)) 240 } 241} 242 243func TestMsgCompressLengthLargeRecords(t *testing.T) { 244 msg := new(Msg) 245 msg.Compress = true 246 msg.SetQuestion("my.service.acme.", TypeSRV) 247 j := 1 248 for i := 0; i < 250; i++ { 249 target := fmt.Sprintf("host-redis-1-%d.test.acme.com.node.dc1.consul.", i) 250 msg.Answer = append(msg.Answer, &SRV{Hdr: RR_Header{Name: "redis.service.consul.", Class: 1, Rrtype: TypeSRV, Ttl: 0x3c}, Port: 0x4c57, Target: target}) 251 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)}) 252 } 253 predicted := msg.Len() 254 buf, err := msg.Pack() 255 if err != nil { 256 t.Error(err) 257 } 258 if predicted != len(buf) { 259 t.Fatalf("predicted compressed length is wrong: predicted %s (len=%d) %d, actual %d", msg.Question[0].Name, len(msg.Answer), predicted, len(buf)) 260 } 261} 262 263func compressionMapsEqual(a map[string]struct{}, b map[string]int) bool { 264 if len(a) != len(b) { 265 return false 266 } 267 268 for k := range a { 269 if _, ok := b[k]; !ok { 270 return false 271 } 272 } 273 274 return true 275} 276 277func compressionMapsDifference(a map[string]struct{}, b map[string]int) string { 278 var s strings.Builder 279 280 var c int 281 fmt.Fprintf(&s, "length compression map (%d):", len(a)) 282 for k := range b { 283 if _, ok := a[k]; !ok { 284 if c > 0 { 285 s.WriteString(",") 286 } 287 288 fmt.Fprintf(&s, " missing %q", k) 289 c++ 290 } 291 } 292 293 c = 0 294 fmt.Fprintf(&s, "\npack compression map (%d):", len(b)) 295 for k := range a { 296 if _, ok := b[k]; !ok { 297 if c > 0 { 298 s.WriteString(",") 299 } 300 301 fmt.Fprintf(&s, " missing %q", k) 302 c++ 303 } 304 } 305 306 return s.String() 307} 308 309func TestCompareCompressionMapsForANY(t *testing.T) { 310 msg := new(Msg) 311 msg.Compress = true 312 msg.SetQuestion("a.service.acme.", TypeANY) 313 // Be sure to have more than 14bits 314 for i := 0; i < 2000; i++ { 315 target := fmt.Sprintf("host.app-%d.x%d.test.acme.", i%250, i) 316 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)}}) 317 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)}}) 318 if msg.Len() > 16384 { 319 break 320 } 321 } 322 for labelSize := 0; labelSize < 63; labelSize++ { 323 msg.SetQuestion(fmt.Sprintf("a%s.service.acme.", strings.Repeat("x", labelSize)), TypeANY) 324 325 compressionFake := make(map[string]struct{}) 326 lenFake := msgLenWithCompressionMap(msg, compressionFake) 327 328 compressionReal := make(map[string]int) 329 buf, err := msg.packBufferWithCompressionMap(nil, compressionMap{ext: compressionReal}, true) 330 if err != nil { 331 t.Fatal(err) 332 } 333 if lenFake != len(buf) { 334 t.Fatalf("padding= %d ; Predicted len := %d != real:= %d", labelSize, lenFake, len(buf)) 335 } 336 if !compressionMapsEqual(compressionFake, compressionReal) { 337 t.Fatalf("padding= %d ; Fake Compression Map != Real Compression Map\n%s", labelSize, compressionMapsDifference(compressionFake, compressionReal)) 338 } 339 } 340} 341 342func TestCompareCompressionMapsForSRV(t *testing.T) { 343 msg := new(Msg) 344 msg.Compress = true 345 msg.SetQuestion("a.service.acme.", TypeSRV) 346 // Be sure to have more than 14bits 347 for i := 0; i < 2000; i++ { 348 target := fmt.Sprintf("host.app-%d.x%d.test.acme.", i%250, i) 349 msg.Answer = append(msg.Answer, &SRV{Hdr: RR_Header{Name: "redis.service.consul.", Class: ClassINET, Rrtype: TypeSRV, Ttl: 0x3c}, Port: 0x4c57, Target: target}) 350 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)}}) 351 if msg.Len() > 16384 { 352 break 353 } 354 } 355 for labelSize := 0; labelSize < 63; labelSize++ { 356 msg.SetQuestion(fmt.Sprintf("a%s.service.acme.", strings.Repeat("x", labelSize)), TypeAAAA) 357 358 compressionFake := make(map[string]struct{}) 359 lenFake := msgLenWithCompressionMap(msg, compressionFake) 360 361 compressionReal := make(map[string]int) 362 buf, err := msg.packBufferWithCompressionMap(nil, compressionMap{ext: compressionReal}, true) 363 if err != nil { 364 t.Fatal(err) 365 } 366 if lenFake != len(buf) { 367 t.Fatalf("padding= %d ; Predicted len := %d != real:= %d", labelSize, lenFake, len(buf)) 368 } 369 if !compressionMapsEqual(compressionFake, compressionReal) { 370 t.Fatalf("padding= %d ; Fake Compression Map != Real Compression Map\n%s", labelSize, compressionMapsDifference(compressionFake, compressionReal)) 371 } 372 } 373} 374 375func TestMsgCompressLengthLargeRecordsWithPaddingPermutation(t *testing.T) { 376 msg := new(Msg) 377 msg.Compress = true 378 msg.SetQuestion("my.service.acme.", TypeSRV) 379 380 for i := 0; i < 250; i++ { 381 target := fmt.Sprintf("host-redis-x-%d.test.acme.com.node.dc1.consul.", i) 382 msg.Answer = append(msg.Answer, &SRV{Hdr: RR_Header{Name: "redis.service.consul.", Class: 1, Rrtype: TypeSRV, Ttl: 0x3c}, Port: 0x4c57, Target: target}) 383 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)}) 384 } 385 for labelSize := 1; labelSize < 63; labelSize++ { 386 msg.SetQuestion(fmt.Sprintf("my.%s.service.acme.", strings.Repeat("x", labelSize)), TypeSRV) 387 predicted := msg.Len() 388 buf, err := msg.Pack() 389 if err != nil { 390 t.Error(err) 391 } 392 if predicted != len(buf) { 393 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)) 394 } 395 } 396} 397 398func TestMsgCompressLengthLargeRecordsAllValues(t *testing.T) { 399 // we want to cross the 14 (16384) bit boundary here, so we build it up to just below and go slightly over. 400 msg := new(Msg) 401 msg.Compress = true 402 msg.SetQuestion("redis.service.consul.", TypeSRV) 403 for i := 0; i < 170; i++ { 404 target := fmt.Sprintf("host-redis-%d-%d.test.acme.com.node.dc1.consul.", i/256, i%256) 405 msg.Answer = append(msg.Answer, &SRV{Hdr: RR_Header{Name: "redis.service.consul.", Class: 1, Rrtype: TypeSRV, Ttl: 0x3c}, Port: 0x4c57, Target: target}) 406 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)}) 407 } 408 // msg.Len() == 15458 409 // msg.Len() == 16470 at 180 410 411 for i := 170; i < 181; i++ { 412 target := fmt.Sprintf("host-redis-%d-%d.test.acme.com.node.dc1.consul.", i/256, i%256) 413 msg.Answer = append(msg.Answer, &SRV{Hdr: RR_Header{Name: "redis.service.consul.", Class: 1, Rrtype: TypeSRV, Ttl: 0x3c}, Port: 0x4c57, Target: target}) 414 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)}) 415 predicted := msg.Len() 416 buf, err := msg.Pack() 417 if err != nil { 418 t.Error(err) 419 } 420 if predicted != len(buf) { 421 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)) 422 } 423 } 424} 425 426func TestMsgCompressionMultipleQuestions(t *testing.T) { 427 msg := new(Msg) 428 msg.Compress = true 429 msg.SetQuestion("www.example.org.", TypeA) 430 msg.Question = append(msg.Question, Question{"other.example.org.", TypeA, ClassINET}) 431 432 predicted := msg.Len() 433 buf, err := msg.Pack() 434 if err != nil { 435 t.Error(err) 436 } 437 if predicted != len(buf) { 438 t.Fatalf("predicted compressed length is wrong: predicted %d, actual %d", predicted, len(buf)) 439 } 440} 441 442func TestMsgCompressMultipleCompressedNames(t *testing.T) { 443 msg := new(Msg) 444 msg.Compress = true 445 msg.SetQuestion("www.example.com.", TypeSRV) 446 msg.Answer = append(msg.Answer, &MINFO{ 447 Hdr: RR_Header{Name: "www.example.com.", Class: 1, Rrtype: TypeSRV, Ttl: 0x3c}, 448 Rmail: "mail.example.org.", 449 Email: "mail.example.org.", 450 }) 451 msg.Answer = append(msg.Answer, &SOA{ 452 Hdr: RR_Header{Name: "www.example.com.", Class: 1, Rrtype: TypeSRV, Ttl: 0x3c}, 453 Ns: "ns.example.net.", 454 Mbox: "mail.example.net.", 455 }) 456 457 predicted := msg.Len() 458 buf, err := msg.Pack() 459 if err != nil { 460 t.Error(err) 461 } 462 if predicted != len(buf) { 463 t.Fatalf("predicted compressed length is wrong: predicted %d, actual %d", predicted, len(buf)) 464 } 465} 466 467func TestMsgCompressLengthEscapingMatch(t *testing.T) { 468 // Although slightly non-optimal, "example.org." and "ex\\097mple.org." 469 // are not considered equal in the compression map, even though \097 is 470 // a valid escaping of a. This test ensures that the Len code and the 471 // Pack code don't disagree on this. 472 473 msg := new(Msg) 474 msg.Compress = true 475 msg.SetQuestion("www.example.org.", TypeA) 476 msg.Answer = append(msg.Answer, &NS{Hdr: RR_Header{Name: "ex\\097mple.org.", Rrtype: TypeNS, Class: ClassINET}, Ns: "ns.example.org."}) 477 478 predicted := msg.Len() 479 buf, err := msg.Pack() 480 if err != nil { 481 t.Error(err) 482 } 483 if predicted != len(buf) { 484 t.Fatalf("predicted compressed length is wrong: predicted %d, actual %d", predicted, len(buf)) 485 } 486} 487 488func TestMsgLengthEscaped(t *testing.T) { 489 msg := new(Msg) 490 msg.SetQuestion(`\000\001\002.\003\004\005\006\007\008\009.\a\b\c.`, TypeA) 491 492 predicted := msg.Len() 493 buf, err := msg.Pack() 494 if err != nil { 495 t.Error(err) 496 } 497 if predicted != len(buf) { 498 t.Fatalf("predicted compressed length is wrong: predicted %d, actual %d", predicted, len(buf)) 499 } 500} 501 502func TestMsgCompressLengthEscaped(t *testing.T) { 503 msg := new(Msg) 504 msg.Compress = true 505 msg.SetQuestion("www.example.org.", TypeA) 506 msg.Answer = append(msg.Answer, &NS{Hdr: RR_Header{Name: `\000\001\002.example.org.`, Rrtype: TypeNS, Class: ClassINET}, Ns: `ns.\e\x\a\m\p\l\e.org.`}) 507 msg.Answer = append(msg.Answer, &NS{Hdr: RR_Header{Name: `www.\e\x\a\m\p\l\e.org.`, Rrtype: TypeNS, Class: ClassINET}, Ns: "ns.example.org."}) 508 509 predicted := msg.Len() 510 buf, err := msg.Pack() 511 if err != nil { 512 t.Error(err) 513 } 514 if predicted != len(buf) { 515 t.Fatalf("predicted compressed length is wrong: predicted %d, actual %d", predicted, len(buf)) 516 } 517} 518