1package dns 2 3import ( 4 "bytes" 5 "crypto/rsa" 6 "encoding/hex" 7 "fmt" 8 "math/rand" 9 "net" 10 "reflect" 11 "regexp" 12 "strconv" 13 "strings" 14 "testing" 15 "testing/quick" 16) 17 18func TestDotInName(t *testing.T) { 19 buf := make([]byte, 20) 20 PackDomainName("aa\\.bb.nl.", buf, 0, nil, false) 21 // index 3 must be a real dot 22 if buf[3] != '.' { 23 t.Error("dot should be a real dot") 24 } 25 26 if buf[6] != 2 { 27 t.Error("this must have the value 2") 28 } 29 dom, _, _ := UnpackDomainName(buf, 0) 30 // printing it should yield the backspace again 31 if dom != "aa\\.bb.nl." { 32 t.Error("dot should have been escaped: ", dom) 33 } 34} 35 36func TestDotLastInLabel(t *testing.T) { 37 sample := "aa\\..au." 38 buf := make([]byte, 20) 39 _, err := PackDomainName(sample, buf, 0, nil, false) 40 if err != nil { 41 t.Fatalf("unexpected error packing domain: %v", err) 42 } 43 dom, _, _ := UnpackDomainName(buf, 0) 44 if dom != sample { 45 t.Fatalf("unpacked domain `%s' doesn't match packed domain", dom) 46 } 47} 48 49func TestTooLongDomainName(t *testing.T) { 50 l := "aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrsssttt." 51 dom := l + l + l + l + l + l + l 52 _, err := NewRR(dom + " IN A 127.0.0.1") 53 if err == nil { 54 t.Error("should be too long") 55 } 56 _, err = NewRR("..com. IN A 127.0.0.1") 57 if err == nil { 58 t.Error("should fail") 59 } 60} 61 62func TestDomainName(t *testing.T) { 63 tests := []string{"r\\.gieben.miek.nl.", "www\\.www.miek.nl.", 64 "www.*.miek.nl.", "www.*.miek.nl.", 65 } 66 dbuff := make([]byte, 40) 67 68 for _, ts := range tests { 69 if _, err := PackDomainName(ts, dbuff, 0, nil, false); err != nil { 70 t.Error("not a valid domain name") 71 continue 72 } 73 n, _, err := UnpackDomainName(dbuff, 0) 74 if err != nil { 75 t.Error("failed to unpack packed domain name") 76 continue 77 } 78 if ts != n { 79 t.Errorf("must be equal: in: %s, out: %s", ts, n) 80 } 81 } 82} 83 84func TestDomainNameAndTXTEscapes(t *testing.T) { 85 tests := []byte{'.', '(', ')', ';', ' ', '@', '"', '\\', 9, 13, 10, 0, 255} 86 for _, b := range tests { 87 rrbytes := []byte{ 88 1, b, 0, // owner 89 byte(TypeTXT >> 8), byte(TypeTXT), 90 byte(ClassINET >> 8), byte(ClassINET), 91 0, 0, 0, 1, // TTL 92 0, 2, 1, b, // Data 93 } 94 rr1, _, err := UnpackRR(rrbytes, 0) 95 if err != nil { 96 panic(err) 97 } 98 s := rr1.String() 99 rr2, err := NewRR(s) 100 if err != nil { 101 t.Errorf("error parsing unpacked RR's string: %v", err) 102 } 103 repacked := make([]byte, len(rrbytes)) 104 if _, err := PackRR(rr2, repacked, 0, nil, false); err != nil { 105 t.Errorf("error packing parsed RR: %v", err) 106 } 107 if !bytes.Equal(repacked, rrbytes) { 108 t.Error("packed bytes don't match original bytes") 109 } 110 } 111} 112 113func TestTXTEscapeParsing(t *testing.T) { 114 test := [][]string{ 115 {`";"`, `";"`}, 116 {`\;`, `";"`}, 117 {`"\t"`, `"t"`}, 118 {`"\r"`, `"r"`}, 119 {`"\ "`, `" "`}, 120 {`"\;"`, `";"`}, 121 {`"\;\""`, `";\""`}, 122 {`"\(a\)"`, `"(a)"`}, 123 {`"\(a)"`, `"(a)"`}, 124 {`"(a\)"`, `"(a)"`}, 125 {`"(a)"`, `"(a)"`}, 126 {`"\048"`, `"0"`}, 127 {`"\` + "\t" + `"`, `"\009"`}, 128 {`"\` + "\n" + `"`, `"\010"`}, 129 {`"\` + "\r" + `"`, `"\013"`}, 130 {`"\` + "\x11" + `"`, `"\017"`}, 131 {`"\'"`, `"'"`}, 132 } 133 for _, s := range test { 134 rr, err := NewRR(fmt.Sprintf("example.com. IN TXT %v", s[0])) 135 if err != nil { 136 t.Errorf("could not parse %v TXT: %s", s[0], err) 137 continue 138 } 139 140 txt := sprintTxt(rr.(*TXT).Txt) 141 if txt != s[1] { 142 t.Errorf("mismatch after parsing `%v` TXT record: `%v` != `%v`", s[0], txt, s[1]) 143 } 144 } 145} 146 147func GenerateDomain(r *rand.Rand, size int) []byte { 148 dnLen := size % 70 // artificially limit size so there's less to interpret if a failure occurs 149 var dn []byte 150 done := false 151 for i := 0; i < dnLen && !done; { 152 max := dnLen - i 153 if max > 63 { 154 max = 63 155 } 156 lLen := max 157 if lLen != 0 { 158 lLen = int(r.Int31()) % max 159 } 160 done = lLen == 0 161 if done { 162 continue 163 } 164 l := make([]byte, lLen+1) 165 l[0] = byte(lLen) 166 for j := 0; j < lLen; j++ { 167 l[j+1] = byte(rand.Int31()) 168 } 169 dn = append(dn, l...) 170 i += 1 + lLen 171 } 172 return append(dn, 0) 173} 174 175func TestDomainQuick(t *testing.T) { 176 r := rand.New(rand.NewSource(0)) 177 f := func(l int) bool { 178 db := GenerateDomain(r, l) 179 ds, _, err := UnpackDomainName(db, 0) 180 if err != nil { 181 panic(err) 182 } 183 buf := make([]byte, 255) 184 off, err := PackDomainName(ds, buf, 0, nil, false) 185 if err != nil { 186 t.Errorf("error packing domain: %v", err) 187 t.Errorf(" bytes: %v", db) 188 t.Errorf("string: %v", ds) 189 return false 190 } 191 if !bytes.Equal(db, buf[:off]) { 192 t.Errorf("repacked domain doesn't match original:") 193 t.Errorf("src bytes: %v", db) 194 t.Errorf(" string: %v", ds) 195 t.Errorf("out bytes: %v", buf[:off]) 196 return false 197 } 198 return true 199 } 200 if err := quick.Check(f, nil); err != nil { 201 t.Error(err) 202 } 203} 204 205func GenerateTXT(r *rand.Rand, size int) []byte { 206 rdLen := size % 300 // artificially limit size so there's less to interpret if a failure occurs 207 var rd []byte 208 for i := 0; i < rdLen; { 209 max := rdLen - 1 210 if max > 255 { 211 max = 255 212 } 213 sLen := max 214 if max != 0 { 215 sLen = int(r.Int31()) % max 216 } 217 s := make([]byte, sLen+1) 218 s[0] = byte(sLen) 219 for j := 0; j < sLen; j++ { 220 s[j+1] = byte(rand.Int31()) 221 } 222 rd = append(rd, s...) 223 i += 1 + sLen 224 } 225 return rd 226} 227 228// Ok, 2 things. 1) this test breaks with the new functionality of splitting up larger txt 229// chunks into 255 byte pieces. 2) I don't like the random nature of this thing, because I can't 230// place the quotes where they need to be. 231// So either add some code the places the quotes in just the right spots, make this non random 232// or do something else. 233// Disabled for now. (miek) 234func testTXTRRQuick(t *testing.T) { 235 s := rand.NewSource(0) 236 r := rand.New(s) 237 typeAndClass := []byte{ 238 byte(TypeTXT >> 8), byte(TypeTXT), 239 byte(ClassINET >> 8), byte(ClassINET), 240 0, 0, 0, 1, // TTL 241 } 242 f := func(l int) bool { 243 owner := GenerateDomain(r, l) 244 rdata := GenerateTXT(r, l) 245 rrbytes := make([]byte, 0, len(owner)+2+2+4+2+len(rdata)) 246 rrbytes = append(rrbytes, owner...) 247 rrbytes = append(rrbytes, typeAndClass...) 248 rrbytes = append(rrbytes, byte(len(rdata)>>8), byte(len(rdata))) 249 rrbytes = append(rrbytes, rdata...) 250 rr, _, err := UnpackRR(rrbytes, 0) 251 if err != nil { 252 panic(err) 253 } 254 buf := make([]byte, len(rrbytes)*3) 255 off, err := PackRR(rr, buf, 0, nil, false) 256 if err != nil { 257 t.Errorf("pack Error: %v\nRR: %v", err, rr) 258 return false 259 } 260 buf = buf[:off] 261 if !bytes.Equal(buf, rrbytes) { 262 t.Errorf("packed bytes don't match original bytes") 263 t.Errorf("src bytes: %v", rrbytes) 264 t.Errorf(" struct: %v", rr) 265 t.Errorf("out bytes: %v", buf) 266 return false 267 } 268 if len(rdata) == 0 { 269 // stringifying won't produce any data to parse 270 return true 271 } 272 rrString := rr.String() 273 rr2, err := NewRR(rrString) 274 if err != nil { 275 t.Errorf("error parsing own output: %v", err) 276 t.Errorf("struct: %v", rr) 277 t.Errorf("string: %v", rrString) 278 return false 279 } 280 if rr2.String() != rrString { 281 t.Errorf("parsed rr.String() doesn't match original string") 282 t.Errorf("original: %v", rrString) 283 t.Errorf(" parsed: %v", rr2.String()) 284 return false 285 } 286 287 buf = make([]byte, len(rrbytes)*3) 288 off, err = PackRR(rr2, buf, 0, nil, false) 289 if err != nil { 290 t.Errorf("error packing parsed rr: %v", err) 291 t.Errorf("unpacked Struct: %v", rr) 292 t.Errorf(" string: %v", rrString) 293 t.Errorf(" parsed Struct: %v", rr2) 294 return false 295 } 296 buf = buf[:off] 297 if !bytes.Equal(buf, rrbytes) { 298 t.Errorf("parsed packed bytes don't match original bytes") 299 t.Errorf(" source bytes: %v", rrbytes) 300 t.Errorf("unpacked struct: %v", rr) 301 t.Errorf(" string: %v", rrString) 302 t.Errorf(" parsed struct: %v", rr2) 303 t.Errorf(" repacked bytes: %v", buf) 304 return false 305 } 306 return true 307 } 308 c := &quick.Config{MaxCountScale: 10} 309 if err := quick.Check(f, c); err != nil { 310 t.Error(err) 311 } 312} 313 314func TestParseDirectiveMisc(t *testing.T) { 315 tests := map[string]string{ 316 "$ORIGIN miek.nl.\na IN NS b": "a.miek.nl.\t3600\tIN\tNS\tb.miek.nl.", 317 "$TTL 2H\nmiek.nl. IN NS b.": "miek.nl.\t7200\tIN\tNS\tb.", 318 "miek.nl. 1D IN NS b.": "miek.nl.\t86400\tIN\tNS\tb.", 319 `name. IN SOA a6.nstld.com. hostmaster.nic.name. ( 320 203362132 ; serial 321 5m ; refresh (5 minutes) 322 5m ; retry (5 minutes) 323 2w ; expire (2 weeks) 324 300 ; minimum (5 minutes) 325)`: "name.\t3600\tIN\tSOA\ta6.nstld.com. hostmaster.nic.name. 203362132 300 300 1209600 300", 326 ". 3600000 IN NS ONE.MY-ROOTS.NET.": ".\t3600000\tIN\tNS\tONE.MY-ROOTS.NET.", 327 "ONE.MY-ROOTS.NET. 3600000 IN A 192.168.1.1": "ONE.MY-ROOTS.NET.\t3600000\tIN\tA\t192.168.1.1", 328 } 329 for i, o := range tests { 330 rr, err := NewRR(i) 331 if err != nil { 332 t.Error("failed to parse RR: ", err) 333 continue 334 } 335 if rr.String() != o { 336 t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) 337 } 338 } 339} 340 341func TestNSEC(t *testing.T) { 342 nsectests := map[string]string{ 343 "nl. IN NSEC3PARAM 1 0 5 30923C44C6CBBB8F": "nl.\t3600\tIN\tNSEC3PARAM\t1 0 5 30923C44C6CBBB8F", 344 "p2209hipbpnm681knjnu0m1febshlv4e.nl. IN NSEC3 1 1 5 30923C44C6CBBB8F P90DG1KE8QEAN0B01613LHQDG0SOJ0TA NS SOA TXT RRSIG DNSKEY NSEC3PARAM": "p2209hipbpnm681knjnu0m1febshlv4e.nl.\t3600\tIN\tNSEC3\t1 1 5 30923C44C6CBBB8F P90DG1KE8QEAN0B01613LHQDG0SOJ0TA NS SOA TXT RRSIG DNSKEY NSEC3PARAM", 345 "localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSEC": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC", 346 "localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSEC TYPE65534": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC TYPE65534", 347 "localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSec Type65534": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC TYPE65534", 348 "44ohaq2njb0idnvolt9ggthvsk1e1uv8.skydns.test. NSEC3 1 0 0 - 44OHAQ2NJB0IDNVOLT9GGTHVSK1E1UVA": "44ohaq2njb0idnvolt9ggthvsk1e1uv8.skydns.test.\t3600\tIN\tNSEC3\t1 0 0 - 44OHAQ2NJB0IDNVOLT9GGTHVSK1E1UVA", 349 } 350 for i, o := range nsectests { 351 rr, err := NewRR(i) 352 if err != nil { 353 t.Error("failed to parse RR: ", err) 354 continue 355 } 356 if rr.String() != o { 357 t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) 358 } 359 } 360 rr, err := NewRR("nl. IN NSEC3PARAM 1 0 5 30923C44C6CBBB8F") 361 if err != nil { 362 t.Fatal("failed to parse RR: ", err) 363 } 364 if nsec3param, ok := rr.(*NSEC3PARAM); ok { 365 if nsec3param.SaltLength != 8 { 366 t.Fatalf("nsec3param saltlen %d != 8", nsec3param.SaltLength) 367 } 368 } else { 369 t.Fatal("not nsec3 param: ", err) 370 } 371} 372 373func TestParseLOC(t *testing.T) { 374 lt := map[string]string{ 375 "SW1A2AA.find.me.uk. LOC 51 30 12.748 N 00 07 39.611 W 0.00m 0.00m 0.00m 0.00m": "SW1A2AA.find.me.uk.\t3600\tIN\tLOC\t51 30 12.748 N 00 07 39.611 W 0m 0.00m 0.00m 0.00m", 376 "SW1A2AA.find.me.uk. LOC 51 0 0.0 N 00 07 39.611 W 0.00m 0.00m 0.00m 0.00m": "SW1A2AA.find.me.uk.\t3600\tIN\tLOC\t51 00 0.000 N 00 07 39.611 W 0m 0.00m 0.00m 0.00m", 377 "SW1A2AA.find.me.uk. LOC 51 30 12.748 N 00 07 39.611 W 0.00m": "SW1A2AA.find.me.uk.\t3600\tIN\tLOC\t51 30 12.748 N 00 07 39.611 W 0m 1m 10000m 10m", 378 // Exercise boundary cases 379 "SW1A2AA.find.me.uk. LOC 90 0 0.0 N 180 0 0.0 W 42849672.95 90000000.00m 90000000.00m 90000000.00m": "SW1A2AA.find.me.uk.\t3600\tIN\tLOC\t90 00 0.000 N 180 00 0.000 W 42849672.95m 90000000m 90000000m 90000000m", 380 "SW1A2AA.find.me.uk. LOC 89 59 59.999 N 179 59 59.999 W -100000 90000000.00m 90000000.00m 90000000m": "SW1A2AA.find.me.uk.\t3600\tIN\tLOC\t89 59 59.999 N 179 59 59.999 W -100000m 90000000m 90000000m 90000000m", 381 // use float64 to have enough precision. 382 "example.com. LOC 42 21 43.952 N 71 5 6.344 W -24m 1m 200m 10m": "example.com.\t3600\tIN\tLOC\t42 21 43.952 N 71 05 6.344 W -24m 1m 200m 10m", 383 } 384 for i, o := range lt { 385 rr, err := NewRR(i) 386 if err != nil { 387 t.Error("failed to parse RR: ", err) 388 continue 389 } 390 if rr.String() != o { 391 t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) 392 } 393 } 394 395 // Invalid cases (out of range values) 396 lt = map[string]string{ // Pair of (invalid) RDATA and the bad field name 397 // One of the subfields is out of range. 398 "91 0 0.0 N 00 07 39.611 W 0m": "Latitude", 399 "89 60 0.0 N 00 07 39.611 W 0m": "Latitude", 400 "89 00 60.0 N 00 07 39.611 W 0m": "Latitude", 401 "1 00 -1 N 00 07 39.611 W 0m": "Latitude", 402 "0 0 0.0 N 181 00 0.0 W 0m": "Longitude", 403 "0 0 0.0 N 179 60 0.0 W 0m": "Longitude", 404 "0 0 0.0 N 179 00 60.0 W 0m": "Longitude", 405 "0 0 0.0 N 1 00 -1 W 0m": "Longitude", 406 407 // Each subfield is valid, but resulting latitude would be out of range. 408 "90 01 00.0 N 00 07 39.611 W 0m": "Latitude", 409 "0 0 0.0 N 180 01 0.0 W 0m": "Longitude", 410 } 411 for rdata, field := range lt { 412 _, err := NewRR(fmt.Sprintf("example.com. LOC %s", rdata)) 413 if err == nil || !strings.Contains(err.Error(), field) { 414 t.Errorf("expected error to contain %q, but got %v", field, err) 415 } 416 } 417} 418 419// this tests a subroutine for the LOC RR parser. It's complicated enough to test separately. 420func TestStringToCm(t *testing.T) { 421 tests := []struct { 422 // Test description: the input token and the expected return values from stringToCm. 423 token string 424 e uint8 425 m uint8 426 ok bool 427 }{ 428 {"100", 4, 1, true}, 429 {"0100", 4, 1, true}, // leading 0 (allowed) 430 {"100.99", 4, 1, true}, 431 {"90000000", 9, 9, true}, 432 {"90000000.00", 9, 9, true}, 433 {"0", 0, 0, true}, 434 {"0.00", 0, 0, true}, 435 {"0.01", 0, 1, true}, 436 {".01", 0, 1, true}, // empty 'meter' part (allowed) 437 {"0.1", 1, 1, true}, 438 439 // out of range (too large) 440 {"90000001", 0, 0, false}, 441 {"90000000.01", 0, 0, false}, 442 443 // more than 2 digits in 'cmeter' part 444 {"0.000", 0, 0, false}, 445 {"0.001", 0, 0, false}, 446 {"0.999", 0, 0, false}, 447 // with plus or minus sign (disallowed) 448 {"-100", 0, 0, false}, 449 {"+100", 0, 0, false}, 450 {"0.-10", 0, 0, false}, 451 {"0.+10", 0, 0, false}, 452 {"0a.00", 0, 0, false}, // invalid string for 'meter' part 453 {".1x", 0, 0, false}, // invalid string for 'cmeter' part 454 {".", 0, 0, false}, // empty 'cmeter' part (disallowed) 455 {"1.", 0, 0, false}, // ditto 456 {"m", 0, 0, false}, // only the "m" suffix 457 } 458 for _, tc := range tests { 459 tc := tc 460 t.Run(tc.token, func(t *testing.T) { 461 // In all cases the expected result is the same with or without the 'm' suffix. 462 // So we test both cases using the same test code. 463 for _, sfx := range []string{"", "m"} { 464 token := tc.token + sfx 465 e, m, ok := stringToCm(token) 466 if ok != tc.ok { 467 t.Fatal("unexpected validation result") 468 } 469 if m != tc.m { 470 t.Fatalf("Expected %d, got %d", tc.m, m) 471 } 472 if e != tc.e { 473 t.Fatalf("Expected %d, got %d", tc.e, e) 474 } 475 } 476 }) 477 } 478} 479 480func TestParseDS(t *testing.T) { 481 dt := map[string]string{ 482 "example.net. 3600 IN DS 40692 12 3 22261A8B0E0D799183E35E24E2AD6BB58533CBA7E3B14D659E9CA09B 2071398F": "example.net.\t3600\tIN\tDS\t40692 12 3 22261A8B0E0D799183E35E24E2AD6BB58533CBA7E3B14D659E9CA09B2071398F", 483 } 484 for i, o := range dt { 485 rr, err := NewRR(i) 486 if err != nil { 487 t.Error("failed to parse RR: ", err) 488 continue 489 } 490 if rr.String() != o { 491 t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) 492 } 493 } 494} 495 496func TestQuotes(t *testing.T) { 497 tests := map[string]string{ 498 `t.example.com. IN TXT "a bc"`: "t.example.com.\t3600\tIN\tTXT\t\"a bc\"", 499 `t.example.com. IN TXT "a 500 bc"`: "t.example.com.\t3600\tIN\tTXT\t\"a\\010 bc\"", 501 `t.example.com. IN TXT ""`: "t.example.com.\t3600\tIN\tTXT\t\"\"", 502 `t.example.com. IN TXT "a"`: "t.example.com.\t3600\tIN\tTXT\t\"a\"", 503 `t.example.com. IN TXT "aa"`: "t.example.com.\t3600\tIN\tTXT\t\"aa\"", 504 `t.example.com. IN TXT "aaa" ;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"", 505 `t.example.com. IN TXT "abc" "DEF"`: "t.example.com.\t3600\tIN\tTXT\t\"abc\" \"DEF\"", 506 `t.example.com. IN TXT "abc" ( "DEF" )`: "t.example.com.\t3600\tIN\tTXT\t\"abc\" \"DEF\"", 507 `t.example.com. IN TXT aaa ;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"", 508 `t.example.com. IN TXT aaa aaa;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\" \"aaa\"", 509 `t.example.com. IN TXT aaa aaa`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\" \"aaa\"", 510 `t.example.com. IN TXT aaa`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"", 511 "cid.urn.arpa. NAPTR 100 50 \"s\" \"z3950+I2L+I2C\" \"\" _z3950._tcp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"z3950+I2L+I2C\" \"\" _z3950._tcp.gatech.edu.", 512 "cid.urn.arpa. NAPTR 100 50 \"s\" \"rcds+I2C\" \"\" _rcds._udp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"rcds+I2C\" \"\" _rcds._udp.gatech.edu.", 513 "cid.urn.arpa. NAPTR 100 50 \"s\" \"http+I2L+I2C+I2R\" \"\" _http._tcp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"http+I2L+I2C+I2R\" \"\" _http._tcp.gatech.edu.", 514 "cid.urn.arpa. NAPTR 100 10 \"\" \"\" \"/urn:cid:.+@([^\\.]+\\.)(.*)$/\\2/i\" .": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 10 \"\" \"\" \"/urn:cid:.+@([^\\.]+\\.)(.*)$/\\2/i\" .", 515 } 516 for i, o := range tests { 517 rr, err := NewRR(i) 518 if err != nil { 519 t.Error("failed to parse RR: ", err) 520 continue 521 } 522 if rr.String() != o { 523 t.Errorf("`%s' should be equal to\n`%s', but is\n`%s'", i, o, rr.String()) 524 } 525 } 526} 527 528func TestParseClass(t *testing.T) { 529 tests := map[string]string{ 530 "t.example.com. IN A 127.0.0.1": "t.example.com. 3600 IN A 127.0.0.1", 531 "t.example.com. CS A 127.0.0.1": "t.example.com. 3600 CS A 127.0.0.1", 532 "t.example.com. CH A 127.0.0.1": "t.example.com. 3600 CH A 127.0.0.1", 533 // ClassANY can not occur in zone files 534 // "t.example.com. ANY A 127.0.0.1": "t.example.com. 3600 ANY A 127.0.0.1", 535 "t.example.com. NONE A 127.0.0.1": "t.example.com. 3600 NONE A 127.0.0.1", 536 "t.example.com. CLASS255 A 127.0.0.1": "t.example.com. 3600 CLASS255 A 127.0.0.1", 537 } 538 for i, o := range tests { 539 rr, err := NewRR(i) 540 if err != nil { 541 t.Error("failed to parse RR: ", err) 542 continue 543 } 544 if rr.String() != o { 545 t.Errorf("`%s' should be equal to\n`%s', but is\n`%s'", i, o, rr.String()) 546 } 547 } 548} 549 550func TestBrace(t *testing.T) { 551 tests := map[string]string{ 552 "(miek.nl.) 3600 IN A 127.0.1.1": "miek.nl.\t3600\tIN\tA\t127.0.1.1", 553 "miek.nl. (3600) IN MX (10) elektron.atoom.net.": "miek.nl.\t3600\tIN\tMX\t10 elektron.atoom.net.", 554 `miek.nl. IN ( 555 3600 A 127.0.0.1)`: "miek.nl.\t3600\tIN\tA\t127.0.0.1", 556 "(miek.nl.) (A) (127.0.2.1)": "miek.nl.\t3600\tIN\tA\t127.0.2.1", 557 "miek.nl A 127.0.3.1": "miek.nl.\t3600\tIN\tA\t127.0.3.1", 558 "_ssh._tcp.local. 60 IN (PTR) stora._ssh._tcp.local.": "_ssh._tcp.local.\t60\tIN\tPTR\tstora._ssh._tcp.local.", 559 "miek.nl. NS ns.miek.nl": "miek.nl.\t3600\tIN\tNS\tns.miek.nl.", 560 `(miek.nl.) ( 561 (IN) 562 (AAAA) 563 (::1) )`: "miek.nl.\t3600\tIN\tAAAA\t::1", 564 `(miek.nl.) ( 565 (IN) 566 (AAAA) 567 (::1))`: "miek.nl.\t3600\tIN\tAAAA\t::1", 568 "miek.nl. IN AAAA ::2": "miek.nl.\t3600\tIN\tAAAA\t::2", 569 `((m)(i)ek.(n)l.) (SOA) (soa.) (soa.) ( 570 2009032802 ; serial 571 21600 ; refresh (6 hours) 572 7(2)00 ; retry (2 hours) 573 604()800 ; expire (1 week) 574 3600 ; minimum (1 hour) 575 )`: "miek.nl.\t3600\tIN\tSOA\tsoa. soa. 2009032802 21600 7200 604800 3600", 576 "miek\\.nl. IN A 127.0.0.10": "miek\\.nl.\t3600\tIN\tA\t127.0.0.10", 577 "miek.nl. IN A 127.0.0.11": "miek.nl.\t3600\tIN\tA\t127.0.0.11", 578 "miek.nl. A 127.0.0.12": "miek.nl.\t3600\tIN\tA\t127.0.0.12", 579 `miek.nl. 86400 IN SOA elektron.atoom.net. miekg.atoom.net. ( 580 2009032802 ; serial 581 21600 ; refresh (6 hours) 582 7200 ; retry (2 hours) 583 604800 ; expire (1 week) 584 3600 ; minimum (1 hour) 585 )`: "miek.nl.\t86400\tIN\tSOA\telektron.atoom.net. miekg.atoom.net. 2009032802 21600 7200 604800 3600", 586 } 587 for i, o := range tests { 588 rr, err := NewRR(i) 589 if err != nil { 590 t.Errorf("failed to parse RR: %v\n\t%s", err, i) 591 continue 592 } 593 if rr.String() != o { 594 t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) 595 } 596 } 597} 598 599func TestParseFailure(t *testing.T) { 600 tests := []string{"miek.nl. IN A 327.0.0.1", 601 "miek.nl. IN AAAA ::x", 602 "miek.nl. IN MX a0 miek.nl.", 603 "miek.nl aap IN MX mx.miek.nl.", 604 "miek.nl 200 IN mxx 10 mx.miek.nl.", 605 "miek.nl. inn MX 10 mx.miek.nl.", 606 // "miek.nl. IN CNAME ", // actually valid nowadays, zero size rdata 607 "miek.nl. IN CNAME ..", 608 "miek.nl. PA MX 10 miek.nl.", 609 "miek.nl. ) IN MX 10 miek.nl.", 610 } 611 612 for _, s := range tests { 613 _, err := NewRR(s) 614 if err == nil { 615 t.Errorf("should have triggered an error: \"%s\"", s) 616 } 617 } 618} 619 620func TestOmittedTTL(t *testing.T) { 621 zone := ` 622$ORIGIN example.com. 623example.com. 42 IN SOA ns1.example.com. hostmaster.example.com. 1 86400 60 86400 3600 ; TTL=42 SOA 624example.com. NS 2 ; TTL=42 absolute owner name 625@ MD 3 ; TTL=42 current-origin owner name 626 MF 4 ; TTL=42 leading-space implied owner name 627 43 TYPE65280 \# 1 05 ; TTL=43 implied owner name explicit TTL 628 MB 6 ; TTL=43 leading-tab implied owner name 629$TTL 1337 630example.com. 88 MG 7 ; TTL=88 explicit TTL 631example.com. MR 8 ; TTL=1337 after first $TTL 632$TTL 314 633 1 TXT 9 ; TTL=1 implied owner name explicit TTL 634example.com. DNAME 10 ; TTL=314 after second $TTL 635` 636 reCaseFromComment := regexp.MustCompile(`TTL=(\d+)\s+(.*)`) 637 z := NewZoneParser(strings.NewReader(zone), "", "") 638 var i int 639 640 for rr, ok := z.Next(); ok; rr, ok = z.Next() { 641 i++ 642 expected := reCaseFromComment.FindStringSubmatch(z.Comment()) 643 if len(expected) != 3 { 644 t.Errorf("regexp didn't match for record %d", i) 645 continue 646 } 647 expectedTTL, _ := strconv.ParseUint(expected[1], 10, 32) 648 ttl := rr.Header().Ttl 649 if ttl != uint32(expectedTTL) { 650 t.Errorf("%s: expected TTL %d, got %d", expected[2], expectedTTL, ttl) 651 } 652 } 653 if err := z.Err(); err != nil { 654 t.Error(err) 655 } 656 if i != 10 { 657 t.Errorf("expected %d records, got %d", 5, i) 658 } 659} 660 661func TestRelativeNameErrors(t *testing.T) { 662 var badZones = []struct { 663 label string 664 zoneContents string 665 expectedErr string 666 }{ 667 { 668 "relative owner name without origin", 669 "example.com 3600 IN SOA ns.example.com. hostmaster.example.com. 1 86400 60 86400 3600", 670 "bad owner name", 671 }, 672 { 673 "relative owner name in RDATA", 674 "example.com. 3600 IN SOA ns hostmaster 1 86400 60 86400 3600", 675 "bad SOA Ns", 676 }, 677 { 678 "origin reference without origin", 679 "@ 3600 IN SOA ns.example.com. hostmaster.example.com. 1 86400 60 86400 3600", 680 "bad owner name", 681 }, 682 { 683 "relative owner name in $INCLUDE", 684 "$INCLUDE file.db example.com", 685 "bad origin name", 686 }, 687 { 688 "relative owner name in $ORIGIN", 689 "$ORIGIN example.com", 690 "bad origin name", 691 }, 692 } 693 for _, errorCase := range badZones { 694 z := NewZoneParser(strings.NewReader(errorCase.zoneContents), "", "") 695 z.Next() 696 if err := z.Err(); err == nil { 697 t.Errorf("%s: expected error, got nil", errorCase.label) 698 } else if !strings.Contains(err.Error(), errorCase.expectedErr) { 699 t.Errorf("%s: expected error `%s`, got `%s`", errorCase.label, errorCase.expectedErr, err) 700 } 701 } 702} 703 704func TestHIP(t *testing.T) { 705 h := `www.example.com. IN HIP ( 2 200100107B1A74DF365639CC39F1D578 706 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p 7079+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQ 708b1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D 709 rvs1.example.com. 710 rvs2.example.com. )` 711 rr, err := NewRR(h) 712 if err != nil { 713 t.Fatalf("failed to parse RR: %v", err) 714 } 715 msg := new(Msg) 716 msg.Answer = []RR{rr, rr} 717 bytes, err := msg.Pack() 718 if err != nil { 719 t.Fatalf("failed to pack msg: %v", err) 720 } 721 if err := msg.Unpack(bytes); err != nil { 722 t.Fatalf("failed to unpack msg: %v", err) 723 } 724 if len(msg.Answer) != 2 { 725 t.Fatalf("2 answers expected: %v", msg) 726 } 727 for i, rr := range msg.Answer { 728 rr := rr.(*HIP) 729 if l := len(rr.RendezvousServers); l != 2 { 730 t.Fatalf("2 servers expected, only %d in record %d:\n%v", l, i, msg) 731 } 732 for j, s := range []string{"rvs1.example.com.", "rvs2.example.com."} { 733 if rr.RendezvousServers[j] != s { 734 t.Fatalf("expected server %d of record %d to be %s:\n%v", j, i, s, msg) 735 } 736 } 737 } 738} 739 740// Test with no known RR on the line 741func TestLineNumberError2(t *testing.T) { 742 tests := map[string]string{ 743 "example.com. 1000 SO master.example.com. admin.example.com. 1 4294967294 4294967293 4294967295 100": "dns: expecting RR type or class, not this...: \"SO\" at line: 1:21", 744 "example.com 1000 IN TALINK a.example.com. b..example.com.": "dns: bad TALINK NextName: \"b..example.com.\" at line: 1:57", 745 "example.com 1000 IN TALINK ( a.example.com. b..example.com. )": "dns: bad TALINK NextName: \"b..example.com.\" at line: 1:60", 746 `example.com 1000 IN TALINK ( a.example.com. 747 bb..example.com. )`: "dns: bad TALINK NextName: \"bb..example.com.\" at line: 2:18", 748 // This is a bug, it should report an error on line 1, but the new is already processed. 749 `example.com 1000 IN TALINK ( a.example.com. b...example.com. 750 )`: "dns: bad TALINK NextName: \"b...example.com.\" at line: 2:1"} 751 752 for in, errStr := range tests { 753 _, err := NewRR(in) 754 if err == nil { 755 t.Error("err is nil") 756 } else { 757 if err.Error() != errStr { 758 t.Errorf("%s: error should be %s is %v", in, errStr, err) 759 } 760 } 761 } 762} 763 764// Test if the calculations are correct 765func TestRfc1982(t *testing.T) { 766 // If the current time and the timestamp are more than 68 years apart 767 // it means the date has wrapped. 0 is 1970 768 769 // fall in the current 68 year span 770 strtests := []string{"20120525134203", "19700101000000", "20380119031408"} 771 for _, v := range strtests { 772 if x, _ := StringToTime(v); v != TimeToString(x) { 773 t.Errorf("1982 arithmetic string failure %s (%s:%d)", v, TimeToString(x), x) 774 } 775 } 776 777 inttests := map[uint32]string{0: "19700101000000", 778 1 << 31: "20380119031408", 779 1<<32 - 1: "21060207062815", 780 } 781 for i, v := range inttests { 782 if TimeToString(i) != v { 783 t.Errorf("1982 arithmetic int failure %d:%s (%s)", i, v, TimeToString(i)) 784 } 785 } 786 787 // Future tests, these dates get parsed to a date within the current 136 year span 788 future := map[string]string{"22680119031408": "20631123173144", 789 "19010101121212": "20370206184028", 790 "19210101121212": "20570206184028", 791 "19500101121212": "20860206184028", 792 "19700101000000": "19700101000000", 793 "19690101000000": "21050207062816", 794 "29210101121212": "21040522212236", 795 } 796 for from, to := range future { 797 x, _ := StringToTime(from) 798 y := TimeToString(x) 799 if y != to { 800 t.Errorf("1982 arithmetic future failure %s:%s (%s)", from, to, y) 801 } 802 } 803} 804 805func TestEmpty(t *testing.T) { 806 z := NewZoneParser(strings.NewReader(""), "", "") 807 for _, ok := z.Next(); ok; _, ok = z.Next() { 808 t.Errorf("should be empty") 809 } 810 if err := z.Err(); err != nil { 811 t.Error("got an error when it shouldn't") 812 } 813} 814 815func TestLowercaseTokens(t *testing.T) { 816 var testrecords = []string{ 817 "example.org. 300 IN a 1.2.3.4", 818 "example.org. 300 in A 1.2.3.4", 819 "example.org. 300 in a 1.2.3.4", 820 "example.org. 300 a 1.2.3.4", 821 "example.org. 300 A 1.2.3.4", 822 "example.org. IN a 1.2.3.4", 823 "example.org. in A 1.2.3.4", 824 "example.org. in a 1.2.3.4", 825 "example.org. a 1.2.3.4", 826 "example.org. A 1.2.3.4", 827 "example.org. a 1.2.3.4", 828 "$ORIGIN example.org.\n a 1.2.3.4", 829 "$Origin example.org.\n a 1.2.3.4", 830 "$origin example.org.\n a 1.2.3.4", 831 "example.org. Class1 Type1 1.2.3.4", 832 } 833 for _, testrr := range testrecords { 834 _, err := NewRR(testrr) 835 if err != nil { 836 t.Errorf("failed to parse %#v, got %v", testrr, err) 837 } 838 } 839} 840 841func TestSRVPacking(t *testing.T) { 842 msg := Msg{} 843 844 things := []string{"1.2.3.4:8484", 845 "45.45.45.45:8484", 846 "84.84.84.84:8484", 847 } 848 849 for i, n := range things { 850 h, p, err := net.SplitHostPort(n) 851 if err != nil { 852 continue 853 } 854 port, _ := strconv.ParseUint(p, 10, 16) 855 856 rr := &SRV{ 857 Hdr: RR_Header{Name: "somename.", 858 Rrtype: TypeSRV, 859 Class: ClassINET, 860 Ttl: 5}, 861 Priority: uint16(i), 862 Weight: 5, 863 Port: uint16(port), 864 Target: h + ".", 865 } 866 867 msg.Answer = append(msg.Answer, rr) 868 } 869 870 _, err := msg.Pack() 871 if err != nil { 872 t.Fatalf("couldn't pack %v: %v", msg, err) 873 } 874} 875 876func TestParseBackslash(t *testing.T) { 877 if _, err := NewRR("nul\\000gap.test.globnix.net. 600 IN A 192.0.2.10"); err != nil { 878 t.Errorf("could not create RR with \\000 in it") 879 } 880 if _, err := NewRR(`nul\000gap.test.globnix.net. 600 IN TXT "Hello\123"`); err != nil { 881 t.Errorf("could not create RR with \\000 in it") 882 } 883 if _, err := NewRR(`m\ @\ iek.nl. IN 3600 A 127.0.0.1`); err != nil { 884 t.Errorf("could not create RR with \\ and \\@ in it") 885 } 886} 887 888func TestILNP(t *testing.T) { 889 tests := []string{ 890 "host1.example.com.\t3600\tIN\tNID\t10 0014:4fff:ff20:ee64", 891 "host1.example.com.\t3600\tIN\tNID\t20 0015:5fff:ff21:ee65", 892 "host2.example.com.\t3600\tIN\tNID\t10 0016:6fff:ff22:ee66", 893 "host1.example.com.\t3600\tIN\tL32\t10 10.1.2.0", 894 "host1.example.com.\t3600\tIN\tL32\t20 10.1.4.0", 895 "host2.example.com.\t3600\tIN\tL32\t10 10.1.8.0", 896 "host1.example.com.\t3600\tIN\tL64\t10 2001:0DB8:1140:1000", 897 "host1.example.com.\t3600\tIN\tL64\t20 2001:0DB8:2140:2000", 898 "host2.example.com.\t3600\tIN\tL64\t10 2001:0DB8:4140:4000", 899 "host1.example.com.\t3600\tIN\tLP\t10 l64-subnet1.example.com.", 900 "host1.example.com.\t3600\tIN\tLP\t10 l64-subnet2.example.com.", 901 "host1.example.com.\t3600\tIN\tLP\t20 l32-subnet1.example.com.", 902 } 903 for _, t1 := range tests { 904 r, err := NewRR(t1) 905 if err != nil { 906 t.Fatalf("an error occurred: %v", err) 907 } else { 908 if t1 != r.String() { 909 t.Fatalf("strings should be equal %s %s", t1, r.String()) 910 } 911 } 912 } 913} 914 915func TestGposEidNimloc(t *testing.T) { 916 dt := map[string]string{ 917 "444433332222111199990123000000ff. NSAP-PTR foo.bar.com.": "444433332222111199990123000000ff.\t3600\tIN\tNSAP-PTR\tfoo.bar.com.", 918 "lillee. IN GPOS -32.6882 116.8652 10.0": "lillee.\t3600\tIN\tGPOS\t-32.6882 116.8652 10.0", 919 "hinault. IN GPOS -22.6882 116.8652 250.0": "hinault.\t3600\tIN\tGPOS\t-22.6882 116.8652 250.0", 920 "VENERA. IN NIMLOC 75234159EAC457800920": "VENERA.\t3600\tIN\tNIMLOC\t75234159EAC457800920", 921 "VAXA. IN EID 3141592653589793": "VAXA.\t3600\tIN\tEID\t3141592653589793", 922 } 923 for i, o := range dt { 924 rr, err := NewRR(i) 925 if err != nil { 926 t.Error("failed to parse RR: ", err) 927 continue 928 } 929 if rr.String() != o { 930 t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) 931 } 932 } 933} 934 935func TestPX(t *testing.T) { 936 dt := map[string]string{ 937 "*.net2.it. IN PX 10 net2.it. PRMD-net2.ADMD-p400.C-it.": "*.net2.it.\t3600\tIN\tPX\t10 net2.it. PRMD-net2.ADMD-p400.C-it.", 938 "ab.net2.it. IN PX 10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.": "ab.net2.it.\t3600\tIN\tPX\t10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.", 939 } 940 for i, o := range dt { 941 rr, err := NewRR(i) 942 if err != nil { 943 t.Error("failed to parse RR: ", err) 944 continue 945 } 946 if rr.String() != o { 947 t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) 948 } 949 } 950} 951 952func TestComment(t *testing.T) { 953 // Comments we must see 954 comments := map[string]bool{ 955 "; this is comment 1": true, 956 "; this is comment 2": true, 957 "; this is comment 4": true, 958 "; this is comment 6": true, 959 "; this is comment 7": true, 960 "; this is comment 8": true, 961 } 962 zone := ` 963foo. IN A 10.0.0.1 ; this is comment 1 964foo. IN A ( 965 10.0.0.2 ; this is comment 2 966) 967; this is comment 3 968foo. IN A 10.0.0.3 969foo. IN A ( 10.0.0.4 ); this is comment 4 970 971foo. IN A 10.0.0.5 972; this is comment 5 973 974foo. IN A 10.0.0.6 975 976foo. IN DNSKEY 256 3 5 AwEAAb+8l ; this is comment 6 977foo. IN NSEC miek.nl. TXT RRSIG NSEC; this is comment 7 978foo. IN TXT "THIS IS TEXT MAN"; this is comment 8 979` 980 z := NewZoneParser(strings.NewReader(zone), ".", "") 981 for _, ok := z.Next(); ok; _, ok = z.Next() { 982 if z.Comment() != "" { 983 if _, okC := comments[z.Comment()]; !okC { 984 t.Errorf("wrong comment %q", z.Comment()) 985 } 986 } 987 } 988 if err := z.Err(); err != nil { 989 t.Error("got an error when it shouldn't") 990 } 991} 992 993func TestZoneParserComments(t *testing.T) { 994 for i, test := range []struct { 995 zone string 996 comments []string 997 }{ 998 { 999 `name. IN SOA a6.nstld.com. hostmaster.nic.name. ( 1000 203362132 ; serial 1001 5m ; refresh (5 minutes) 1002 5m ; retry (5 minutes) 1003 2w ; expire (2 weeks) 1004 300 ; minimum (5 minutes) 1005 ) ; y 1006. 3600000 IN NS ONE.MY-ROOTS.NET. ; x`, 1007 []string{"; serial ; refresh (5 minutes) ; retry (5 minutes) ; expire (2 weeks) ; minimum (5 minutes) ; y", "; x"}, 1008 }, 1009 { 1010 `name. IN SOA a6.nstld.com. hostmaster.nic.name. ( 1011 203362132 ; serial 1012 5m ; refresh (5 minutes) 1013 5m ; retry (5 minutes) 1014 2w ; expire (2 weeks) 1015 300 ; minimum (5 minutes) 1016 ) ; y 1017. 3600000 IN NS ONE.MY-ROOTS.NET.`, 1018 []string{"; serial ; refresh (5 minutes) ; retry (5 minutes) ; expire (2 weeks) ; minimum (5 minutes) ; y", ""}, 1019 }, 1020 { 1021 `name. IN SOA a6.nstld.com. hostmaster.nic.name. ( 1022 203362132 ; serial 1023 5m ; refresh (5 minutes) 1024 5m ; retry (5 minutes) 1025 2w ; expire (2 weeks) 1026 300 ; minimum (5 minutes) 1027 ) 1028. 3600000 IN NS ONE.MY-ROOTS.NET.`, 1029 []string{"; serial ; refresh (5 minutes) ; retry (5 minutes) ; expire (2 weeks) ; minimum (5 minutes)", ""}, 1030 }, 1031 { 1032 `name. IN SOA a6.nstld.com. hostmaster.nic.name. ( 1033 203362132 ; serial 1034 5m ; refresh (5 minutes) 1035 5m ; retry (5 minutes) 1036 2w ; expire (2 weeks) 1037 300 ; minimum (5 minutes) 1038 ) 1039. 3600000 IN NS ONE.MY-ROOTS.NET. ; x`, 1040 []string{"; serial ; refresh (5 minutes) ; retry (5 minutes) ; expire (2 weeks) ; minimum (5 minutes)", "; x"}, 1041 }, 1042 { 1043 `name. IN SOA a6.nstld.com. hostmaster.nic.name. ( 1044 203362132 ; serial 1045 5m ; refresh (5 minutes) 1046 5m ; retry (5 minutes) 1047 2w ; expire (2 weeks) 1048 300 ; minimum (5 minutes) 1049 )`, 1050 []string{"; serial ; refresh (5 minutes) ; retry (5 minutes) ; expire (2 weeks) ; minimum (5 minutes)"}, 1051 }, 1052 { 1053 `. 3600000 IN NS ONE.MY-ROOTS.NET. ; x`, 1054 []string{"; x"}, 1055 }, 1056 { 1057 `. 3600000 IN NS ONE.MY-ROOTS.NET.`, 1058 []string{""}, 1059 }, 1060 { 1061 `. 3600000 IN NS ONE.MY-ROOTS.NET. ;;x`, 1062 []string{";;x"}, 1063 }, 1064 } { 1065 r := strings.NewReader(test.zone) 1066 1067 var j int 1068 z := NewZoneParser(r, "", "") 1069 for rr, ok := z.Next(); ok; rr, ok = z.Next() { 1070 if j >= len(test.comments) { 1071 t.Fatalf("too many records for zone %d at %d record, expected %d", i, j+1, len(test.comments)) 1072 } 1073 1074 if z.Comment() != test.comments[j] { 1075 t.Errorf("invalid comment for record %d:%d %v", i, j, rr) 1076 t.Logf("expected %q", test.comments[j]) 1077 t.Logf("got %q", z.Comment()) 1078 } 1079 1080 j++ 1081 } 1082 1083 if err := z.Err(); err != nil { 1084 t.Fatal(err) 1085 } 1086 1087 if j != len(test.comments) { 1088 t.Errorf("too few records for zone %d, got %d, expected %d", i, j, len(test.comments)) 1089 } 1090 } 1091} 1092 1093func TestEUIxx(t *testing.T) { 1094 tests := map[string]string{ 1095 "host.example. IN EUI48 00-00-5e-90-01-2a": "host.example.\t3600\tIN\tEUI48\t00-00-5e-90-01-2a", 1096 "host.example. IN EUI64 00-00-5e-ef-00-00-00-2a": "host.example.\t3600\tIN\tEUI64\t00-00-5e-ef-00-00-00-2a", 1097 } 1098 for i, o := range tests { 1099 r, err := NewRR(i) 1100 if err != nil { 1101 t.Errorf("failed to parse %s: %v", i, err) 1102 } 1103 if r.String() != o { 1104 t.Errorf("want %s, got %s", o, r.String()) 1105 } 1106 } 1107} 1108 1109func TestUserRR(t *testing.T) { 1110 tests := map[string]string{ 1111 "host.example. IN UID 1234": "host.example.\t3600\tIN\tUID\t1234", 1112 "host.example. IN GID 1234556": "host.example.\t3600\tIN\tGID\t1234556", 1113 "host.example. IN UINFO \"Miek Gieben\"": "host.example.\t3600\tIN\tUINFO\t\"Miek Gieben\"", 1114 } 1115 for i, o := range tests { 1116 r, err := NewRR(i) 1117 if err != nil { 1118 t.Errorf("failed to parse %s: %v", i, err) 1119 } 1120 if r.String() != o { 1121 t.Errorf("want %s, got %s", o, r.String()) 1122 } 1123 } 1124} 1125 1126func TestTXT(t *testing.T) { 1127 // Test single entry TXT record 1128 rr, err := NewRR(`_raop._tcp.local. 60 IN TXT "single value"`) 1129 if err != nil { 1130 t.Error("failed to parse single value TXT record", err) 1131 } else if rr, ok := rr.(*TXT); !ok { 1132 t.Error("wrong type, record should be of type TXT") 1133 } else { 1134 if len(rr.Txt) != 1 { 1135 t.Error("bad size of TXT value:", len(rr.Txt)) 1136 } else if rr.Txt[0] != "single value" { 1137 t.Error("bad single value") 1138 } 1139 if rr.String() != `_raop._tcp.local. 60 IN TXT "single value"` { 1140 t.Error("bad representation of TXT record:", rr.String()) 1141 } 1142 if Len(rr) != 28+1+12 { 1143 t.Error("bad size of serialized record:", Len(rr)) 1144 } 1145 } 1146 1147 // Test multi entries TXT record 1148 rr, err = NewRR(`_raop._tcp.local. 60 IN TXT "a=1" "b=2" "c=3" "d=4"`) 1149 if err != nil { 1150 t.Error("failed to parse multi-values TXT record", err) 1151 } else if rr, ok := rr.(*TXT); !ok { 1152 t.Error("wrong type, record should be of type TXT") 1153 } else { 1154 if len(rr.Txt) != 4 { 1155 t.Error("bad size of TXT multi-value:", len(rr.Txt)) 1156 } else if rr.Txt[0] != "a=1" || rr.Txt[1] != "b=2" || rr.Txt[2] != "c=3" || rr.Txt[3] != "d=4" { 1157 t.Error("bad values in TXT records") 1158 } 1159 if rr.String() != `_raop._tcp.local. 60 IN TXT "a=1" "b=2" "c=3" "d=4"` { 1160 t.Error("bad representation of TXT multi value record:", rr.String()) 1161 } 1162 if Len(rr) != 28+1+3+1+3+1+3+1+3 { 1163 t.Error("bad size of serialized multi value record:", Len(rr)) 1164 } 1165 } 1166 1167 // Test empty-string in TXT record 1168 rr, err = NewRR(`_raop._tcp.local. 60 IN TXT ""`) 1169 if err != nil { 1170 t.Error("failed to parse empty-string TXT record", err) 1171 } else if rr, ok := rr.(*TXT); !ok { 1172 t.Error("wrong type, record should be of type TXT") 1173 } else { 1174 if len(rr.Txt) != 1 { 1175 t.Error("bad size of TXT empty-string value:", len(rr.Txt)) 1176 } else if rr.Txt[0] != "" { 1177 t.Error("bad value for empty-string TXT record") 1178 } 1179 if rr.String() != `_raop._tcp.local. 60 IN TXT ""` { 1180 t.Error("bad representation of empty-string TXT record:", rr.String()) 1181 } 1182 if Len(rr) != 28+1 { 1183 t.Error("bad size of serialized record:", Len(rr)) 1184 } 1185 } 1186 1187 // Test TXT record with chunk larger than 255 bytes, they should be split up, by the parser 1188 s := "" 1189 for i := 0; i < 255; i++ { 1190 s += "a" 1191 } 1192 s += "b" 1193 rr, err = NewRR(`test.local. 60 IN TXT "` + s + `"`) 1194 if err != nil { 1195 t.Error("failed to parse empty-string TXT record", err) 1196 } 1197 if rr.(*TXT).Txt[1] != "b" { 1198 t.Errorf("Txt should have two chunk, last one my be 'b', but is %s", rr.(*TXT).Txt[1]) 1199 } 1200} 1201 1202func TestTypeXXXX(t *testing.T) { 1203 _, err := NewRR("example.com IN TYPE1234 \\# 4 aabbccdd") 1204 if err != nil { 1205 t.Errorf("failed to parse TYPE1234 RR: %v", err) 1206 } 1207 _, err = NewRR("example.com IN TYPE655341 \\# 8 aabbccddaabbccdd") 1208 if err == nil { 1209 t.Errorf("this should not work, for TYPE655341") 1210 } 1211 _, err = NewRR("example.com IN TYPE1 \\# 4 0a000001") 1212 if err != nil { 1213 t.Errorf("failed to parse TYPE1 RR: %v", err) 1214 } 1215} 1216 1217func TestPTR(t *testing.T) { 1218 _, err := NewRR("144.2.0.192.in-addr.arpa. 900 IN PTR ilouse03146p0\\(.example.com.") 1219 if err != nil { 1220 t.Error("failed to parse ", err) 1221 } 1222} 1223 1224func TestDigit(t *testing.T) { 1225 tests := map[string]byte{ 1226 "miek\\000.nl. 100 IN TXT \"A\"": 0, 1227 "miek\\001.nl. 100 IN TXT \"A\"": 1, 1228 "miek\\254.nl. 100 IN TXT \"A\"": 254, 1229 "miek\\255.nl. 100 IN TXT \"A\"": 255, 1230 "miek\\256.nl. 100 IN TXT \"A\"": 0, 1231 "miek\\257.nl. 100 IN TXT \"A\"": 1, 1232 "miek\\004.nl. 100 IN TXT \"A\"": 4, 1233 } 1234 for s, i := range tests { 1235 r, err := NewRR(s) 1236 buf := make([]byte, 40) 1237 if err != nil { 1238 t.Fatalf("failed to parse %v", err) 1239 } 1240 PackRR(r, buf, 0, nil, false) 1241 if buf[5] != i { 1242 t.Fatalf("5 pos must be %d, is %d", i, buf[5]) 1243 } 1244 r1, _, _ := UnpackRR(buf, 0) 1245 if r1.Header().Ttl != 100 { 1246 t.Fatalf("TTL should %d, is %d", 100, r1.Header().Ttl) 1247 } 1248 } 1249} 1250 1251func TestParseRRSIGTimestamp(t *testing.T) { 1252 tests := map[string]bool{ 1253 `miek.nl. IN RRSIG SOA 8 2 43200 20140210031301 20140111031301 12051 miek.nl. MVZUyrYwq0iZhMFDDnVXD2BvuNiUJjSYlJAgzyAE6CF875BMvvZa+Sb0 RlSCL7WODQSQHhCx/fegHhVVF+Iz8N8kOLrmXD1+jO3Bm6Prl5UhcsPx WTBsg/kmxbp8sR1kvH4oZJtVfakG3iDerrxNaf0sQwhZzyfJQAqpC7pcBoc=`: true, 1254 `miek.nl. IN RRSIG SOA 8 2 43200 315565800 4102477800 12051 miek.nl. MVZUyrYwq0iZhMFDDnVXD2BvuNiUJjSYlJAgzyAE6CF875BMvvZa+Sb0 RlSCL7WODQSQHhCx/fegHhVVF+Iz8N8kOLrmXD1+jO3Bm6Prl5UhcsPx WTBsg/kmxbp8sR1kvH4oZJtVfakG3iDerrxNaf0sQwhZzyfJQAqpC7pcBoc=`: true, 1255 } 1256 for r := range tests { 1257 _, err := NewRR(r) 1258 if err != nil { 1259 t.Error(err) 1260 } 1261 } 1262} 1263 1264func TestTxtEqual(t *testing.T) { 1265 rr1 := new(TXT) 1266 rr1.Hdr = RR_Header{Name: ".", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0} 1267 rr1.Txt = []string{"a\"a", "\"", "b"} 1268 rr2, _ := NewRR(rr1.String()) 1269 if rr1.String() != rr2.String() { 1270 // This is not an error, but keep this test. 1271 t.Errorf("these two TXT records should match:\n%s\n%s", rr1.String(), rr2.String()) 1272 } 1273} 1274 1275func TestTxtLong(t *testing.T) { 1276 rr1 := new(TXT) 1277 rr1.Hdr = RR_Header{Name: ".", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0} 1278 // Make a long txt record, this breaks when sending the packet, 1279 // but not earlier. 1280 rr1.Txt = []string{"start-"} 1281 for i := 0; i < 200; i++ { 1282 rr1.Txt[0] += "start-" 1283 } 1284 str := rr1.String() 1285 if len(str) < len(rr1.Txt[0]) { 1286 t.Error("string conversion should work") 1287 } 1288} 1289 1290// Basically, don't crash. 1291func TestMalformedPackets(t *testing.T) { 1292 var packets = []string{ 1293 "0021641c0000000100000000000078787878787878787878787303636f6d0000100001", 1294 } 1295 1296 // com = 63 6f 6d 1297 for _, packet := range packets { 1298 data, _ := hex.DecodeString(packet) 1299 var msg Msg 1300 msg.Unpack(data) 1301 } 1302} 1303 1304type algorithm struct { 1305 name uint8 1306 bits int 1307} 1308 1309func TestNewPrivateKey(t *testing.T) { 1310 if testing.Short() { 1311 t.Skip("skipping test in short mode.") 1312 } 1313 algorithms := []algorithm{ 1314 {ECDSAP256SHA256, 256}, 1315 {ECDSAP384SHA384, 384}, 1316 {RSASHA1, 512}, 1317 {RSASHA256, 512}, 1318 {ED25519, 256}, 1319 } 1320 1321 for _, algo := range algorithms { 1322 key := new(DNSKEY) 1323 key.Hdr.Rrtype = TypeDNSKEY 1324 key.Hdr.Name = "miek.nl." 1325 key.Hdr.Class = ClassINET 1326 key.Hdr.Ttl = 14400 1327 key.Flags = 256 1328 key.Protocol = 3 1329 key.Algorithm = algo.name 1330 privkey, err := key.Generate(algo.bits) 1331 if err != nil { 1332 t.Fatal(err) 1333 } 1334 1335 newPrivKey, err := key.NewPrivateKey(key.PrivateKeyString(privkey)) 1336 if err != nil { 1337 t.Error(key.String()) 1338 t.Error(key.PrivateKeyString(privkey)) 1339 t.Fatal(err) 1340 } 1341 1342 switch newPrivKey := newPrivKey.(type) { 1343 case *rsa.PrivateKey: 1344 newPrivKey.Precompute() 1345 } 1346 1347 if !reflect.DeepEqual(privkey, newPrivKey) { 1348 t.Errorf("[%v] Private keys differ:\n%#v\n%#v", AlgorithmToString[algo.name], privkey, newPrivKey) 1349 } 1350 } 1351} 1352 1353// special input test 1354func TestNewRRSpecial(t *testing.T) { 1355 var ( 1356 rr RR 1357 err error 1358 expect string 1359 ) 1360 1361 rr, err = NewRR("; comment") 1362 expect = "" 1363 if err != nil { 1364 t.Errorf("unexpected err: %v", err) 1365 } 1366 if rr != nil { 1367 t.Errorf("unexpected result: [%s] != [%s]", rr, expect) 1368 } 1369 1370 rr, err = NewRR("") 1371 expect = "" 1372 if err != nil { 1373 t.Errorf("unexpected err: %v", err) 1374 } 1375 if rr != nil { 1376 t.Errorf("unexpected result: [%s] != [%s]", rr, expect) 1377 } 1378 1379 rr, err = NewRR("$ORIGIN foo.") 1380 expect = "" 1381 if err != nil { 1382 t.Errorf("unexpected err: %v", err) 1383 } 1384 if rr != nil { 1385 t.Errorf("unexpected result: [%s] != [%s]", rr, expect) 1386 } 1387 1388 rr, err = NewRR(" ") 1389 expect = "" 1390 if err != nil { 1391 t.Errorf("unexpected err: %v", err) 1392 } 1393 if rr != nil { 1394 t.Errorf("unexpected result: [%s] != [%s]", rr, expect) 1395 } 1396 1397 rr, err = NewRR("\n") 1398 expect = "" 1399 if err != nil { 1400 t.Errorf("unexpected err: %v", err) 1401 } 1402 if rr != nil { 1403 t.Errorf("unexpected result: [%s] != [%s]", rr, expect) 1404 } 1405 1406 rr, err = NewRR("foo. A 1.1.1.1\nbar. A 2.2.2.2") 1407 expect = "foo.\t3600\tIN\tA\t1.1.1.1" 1408 if err != nil { 1409 t.Errorf("unexpected err: %v", err) 1410 } 1411 if rr == nil || rr.String() != expect { 1412 t.Errorf("unexpected result: [%s] != [%s]", rr, expect) 1413 } 1414} 1415 1416func TestPrintfVerbsRdata(t *testing.T) { 1417 x, _ := NewRR("www.miek.nl. IN MX 20 mx.miek.nl.") 1418 if Field(x, 1) != "20" { 1419 t.Errorf("should be 20") 1420 } 1421 if Field(x, 2) != "mx.miek.nl." { 1422 t.Errorf("should be mx.miek.nl.") 1423 } 1424 1425 x, _ = NewRR("www.miek.nl. IN A 127.0.0.1") 1426 if Field(x, 1) != "127.0.0.1" { 1427 t.Errorf("should be 127.0.0.1") 1428 } 1429 1430 x, _ = NewRR("www.miek.nl. IN AAAA ::1") 1431 if Field(x, 1) != "::1" { 1432 t.Errorf("should be ::1") 1433 } 1434 1435 x, _ = NewRR("www.miek.nl. IN NSEC a.miek.nl. A NS SOA MX AAAA") 1436 if Field(x, 1) != "a.miek.nl." { 1437 t.Errorf("should be a.miek.nl.") 1438 } 1439 if Field(x, 2) != "A NS SOA MX AAAA" { 1440 t.Errorf("should be A NS SOA MX AAAA") 1441 } 1442 1443 x, _ = NewRR("www.miek.nl. IN TXT \"first\" \"second\"") 1444 if Field(x, 1) != "first second" { 1445 t.Errorf("should be first second") 1446 } 1447 if Field(x, 0) != "" { 1448 t.Errorf("should be empty") 1449 } 1450} 1451 1452func TestParseTokenOverflow(t *testing.T) { 1453 _, err := NewRR("_443._tcp.example.org. IN TLSA 0 0 0 308205e8308204d0a00302010202100411de8f53b462f6a5a861b712ec6b59300d06092a864886f70d01010b05003070310b300906035504061302555331153013060355040a130c446967694365727420496e6331193017060355040b13107777772e64696769636572742e636f6d312f302d06035504031326446967694365727420534841322048696768204173737572616e636520536572766572204341301e170d3134313130363030303030305a170d3135313131333132303030305a3081a5310b3009060355040613025553311330110603550408130a43616c69666f726e6961311430120603550407130b4c6f7320416e67656c6573313c303a060355040a1333496e7465726e657420436f72706f726174696f6e20666f722041737369676e6564204e616d657320616e64204e756d6265727331133011060355040b130a546563686e6f6c6f6779311830160603550403130f7777772e6578616d706c652e6f726730820122300d06092a864886f70d01010105000382010f003082010a02820101009e663f52a3d18cb67cdfed547408a4e47e4036538988da2798da3b6655f7240d693ed1cb3fe6d6ad3a9e657ff6efa86b83b0cad24e5d31ff2bf70ec3b78b213f1b4bf61bdc669cbbc07d67154128ca92a9b3cbb4213a836fb823ddd4d7cc04918314d25f06086fa9970ba17e357cca9b458c27eb71760ab95e3f9bc898ae89050ae4d09ba2f7e4259d9ff1e072a6971b18355a8b9e53670c3d5dbdbd283f93a764e71b3a4140ca0746090c08510e2e21078d7d07844bf9c03865b531a0bf2ee766bc401f6451c5a1e6f6fb5d5c1d6a97a0abe91ae8b02e89241e07353909ccd5b41c46de207c06801e08f20713603827f2ae3e68cf15ef881d7e0608f70742e30203010001a382024630820242301f0603551d230418301680145168ff90af0207753cccd9656462a212b859723b301d0603551d0e04160414b000a7f422e9b1ce216117c4c46e7164c8e60c553081810603551d11047a3078820f7777772e6578616d706c652e6f7267820b6578616d706c652e636f6d820b6578616d706c652e656475820b6578616d706c652e6e6574820b6578616d706c652e6f7267820f7777772e6578616d706c652e636f6d820f7777772e6578616d706c652e656475820f7777772e6578616d706c652e6e6574300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b0601050507030230750603551d1f046e306c3034a032a030862e687474703a2f2f63726c332e64696769636572742e636f6d2f736861322d68612d7365727665722d67332e63726c3034a032a030862e687474703a2f2f63726c342e64696769636572742e636f6d2f736861322d68612d7365727665722d67332e63726c30420603551d20043b3039303706096086480186fd6c0101302a302806082b06010505070201161c68747470733a2f2f7777772e64696769636572742e636f6d2f43505330818306082b0601050507010104773075302406082b060105050730018618687474703a2f2f6f6373702e64696769636572742e636f6d304d06082b060105050730028641687474703a2f2f636163657274732e64696769636572742e636f6d2f446967694365727453484132486967684173737572616e636553657276657243412e637274300c0603551d130101ff04023000300d06092a864886f70d01010b050003820101005eac2124dedb3978a86ff3608406acb542d3cb54cb83facd63aec88144d6a1bf15dbf1f215c4a73e241e582365cba9ea50dd306541653b3513af1a0756c1b2720e8d112b34fb67181efad9c4609bdc670fb025fa6e6d42188161b026cf3089a08369c2f3609fc84bcc3479140c1922ede430ca8dbac2b2a3cdacb305ba15dc7361c4c3a5e6daa99cb446cb221b28078a7a944efba70d96f31ac143d959bccd2fd50e30c325ea2624fb6b6dbe9344dbcf133bfbd5b4e892d635dbf31596451672c6b65ba5ac9b3cddea92b35dab1065cae3c8cb6bb450a62ea2f72ea7c6bdc7b65fa09b012392543734083c7687d243f8d0375304d99ccd2e148966a8637a6797") 1454 if err == nil { 1455 t.Fatalf("token overflow should return an error") 1456 } 1457} 1458 1459func TestParseTLSA(t *testing.T) { 1460 lt := []string{ 1461 "_443._tcp.example.org.\t3600\tIN\tTLSA\t1 1 1 c22be239f483c08957bc106219cc2d3ac1a308dfbbdd0a365f17b9351234cf00", 1462 "_443._tcp.example.org.\t3600\tIN\tTLSA\t2 1 2 4e85f45179e9cd6e0e68e2eb5be2e85ec9b92d91c609caf3ef0315213e3f92ece92c38397a607214de95c7fadc0ad0f1c604a469a0387959745032c0d51492f3", 1463 "_443._tcp.example.org.\t3600\tIN\tTLSA\t3 0 2 69ec8d2277360b215d0cd956b0e2747108dff34b27d461a41c800629e38ee6c2d1230cc9e8e36711330adc6766e6ff7c5fbb37f106f248337c1a20ad682888d2", 1464 } 1465 for _, o := range lt { 1466 rr, err := NewRR(o) 1467 if err != nil { 1468 t.Error("failed to parse RR: ", err) 1469 continue 1470 } 1471 if rr.String() != o { 1472 t.Errorf("`%s' should be equal to\n`%s', but is `%s'", o, o, rr.String()) 1473 } 1474 } 1475} 1476 1477func TestParseSMIMEA(t *testing.T) { 1478 lt := map[string]string{ 1479 "2e85e1db3e62be6ea._smimecert.example.com.\t3600\tIN\tSMIMEA\t1 1 2 bd80f334566928fc18f58df7e4928c1886f48f71ca3fd41cd9b1854aca7c2180aaacad2819612ed68e7bd3701cc39be7f2529b017c0bc6a53e8fb3f0c7d48070": "2e85e1db3e62be6ea._smimecert.example.com.\t3600\tIN\tSMIMEA\t1 1 2 bd80f334566928fc18f58df7e4928c1886f48f71ca3fd41cd9b1854aca7c2180aaacad2819612ed68e7bd3701cc39be7f2529b017c0bc6a53e8fb3f0c7d48070", 1480 "2e85e1db3e62be6ea._smimecert.example.com.\t3600\tIN\tSMIMEA\t0 0 1 cdcf0fc66b182928c5217ddd42c826983f5a4b94160ee6c1c9be62d38199f710": "2e85e1db3e62be6ea._smimecert.example.com.\t3600\tIN\tSMIMEA\t0 0 1 cdcf0fc66b182928c5217ddd42c826983f5a4b94160ee6c1c9be62d38199f710", 1481 "2e85e1db3e62be6ea._smimecert.example.com.\t3600\tIN\tSMIMEA\t3 0 2 499a1eda2af8828b552cdb9d80c3744a25872fddd73f3898d8e4afa3549595d2dd4340126e759566fe8c26b251fa0c887ba4869f011a65f7e79967c2eb729f5b": "2e85e1db3e62be6ea._smimecert.example.com.\t3600\tIN\tSMIMEA\t3 0 2 499a1eda2af8828b552cdb9d80c3744a25872fddd73f3898d8e4afa3549595d2dd4340126e759566fe8c26b251fa0c887ba4869f011a65f7e79967c2eb729f5b", 1482 "2e85e1db3e62be6eb._smimecert.example.com.\t3600\tIN\tSMIMEA\t3 0 2 499a1eda2af8828b552cdb9d80c3744a25872fddd73f3898d8e4afa3549595d2dd4340126e759566fe8 c26b251fa0c887ba4869f01 1a65f7e79967c2eb729f5b": "2e85e1db3e62be6eb._smimecert.example.com.\t3600\tIN\tSMIMEA\t3 0 2 499a1eda2af8828b552cdb9d80c3744a25872fddd73f3898d8e4afa3549595d2dd4340126e759566fe8c26b251fa0c887ba4869f011a65f7e79967c2eb729f5b", 1483 } 1484 for i, o := range lt { 1485 rr, err := NewRR(i) 1486 if err != nil { 1487 t.Error("failed to parse RR: ", err) 1488 continue 1489 } 1490 if rr.String() != o { 1491 t.Errorf("`%s' should be equal to\n`%s', but is `%s'", o, o, rr.String()) 1492 } 1493 } 1494} 1495 1496func TestParseSSHFP(t *testing.T) { 1497 lt := []string{ 1498 "test.example.org.\t300\tSSHFP\t1 2 (\n" + 1499 "\t\t\t\t\tBC6533CDC95A79078A39A56EA7635984ED655318ADA9\n" + 1500 "\t\t\t\t\tB6159E30723665DA95BB )", 1501 "test.example.org.\t300\tSSHFP\t1 2 ( BC6533CDC 95A79078A39A56EA7635984ED655318AD A9B6159E3072366 5DA95BB )", 1502 } 1503 result := "test.example.org.\t300\tIN\tSSHFP\t1 2 BC6533CDC95A79078A39A56EA7635984ED655318ADA9B6159E30723665DA95BB" 1504 for _, o := range lt { 1505 rr, err := NewRR(o) 1506 if err != nil { 1507 t.Error("failed to parse RR: ", err) 1508 continue 1509 } 1510 if rr.String() != result { 1511 t.Errorf("`%s' should be equal to\n\n`%s', but is \n`%s'", o, result, rr.String()) 1512 } 1513 } 1514} 1515 1516func TestParseHINFO(t *testing.T) { 1517 dt := map[string]string{ 1518 "example.net. HINFO A B": "example.net. 3600 IN HINFO \"A\" \"B\"", 1519 "example.net. HINFO \"A\" \"B\"": "example.net. 3600 IN HINFO \"A\" \"B\"", 1520 "example.net. HINFO A B C D E F": "example.net. 3600 IN HINFO \"A\" \"B C D E F\"", 1521 "example.net. HINFO AB": "example.net. 3600 IN HINFO \"AB\" \"\"", 1522 // "example.net. HINFO PC-Intel-700mhz \"Redhat Linux 7.1\"": "example.net. 3600 IN HINFO \"PC-Intel-700mhz\" \"Redhat Linux 7.1\"", 1523 // This one is recommended in Pro Bind book http://www.zytrax.com/books/dns/ch8/hinfo.html 1524 // but effectively, even Bind would replace it to correctly formed text when you AXFR 1525 // TODO: remove this set of comments or figure support for quoted/unquoted combinations in endingToTxtSlice function 1526 } 1527 for i, o := range dt { 1528 rr, err := NewRR(i) 1529 if err != nil { 1530 t.Error("failed to parse RR: ", err) 1531 continue 1532 } 1533 if rr.String() != o { 1534 t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) 1535 } 1536 } 1537} 1538 1539func TestParseCAA(t *testing.T) { 1540 lt := map[string]string{ 1541 "example.net. CAA 0 issue \"symantec.com\"": "example.net.\t3600\tIN\tCAA\t0 issue \"symantec.com\"", 1542 "example.net. CAA 0 issuewild \"symantec.com; stuff\"": "example.net.\t3600\tIN\tCAA\t0 issuewild \"symantec.com; stuff\"", 1543 "example.net. CAA 128 tbs \"critical\"": "example.net.\t3600\tIN\tCAA\t128 tbs \"critical\"", 1544 "example.net. CAA 2 auth \"0>09\\006\\010+\\006\\001\\004\\001\\214y\\002\\003\\001\\006\\009`\\134H\\001e\\003\\004\\002\\001\\004 y\\209\\012\\221r\\220\\156Q\\218\\150\\150{\\166\\245:\\231\\182%\\157:\\133\\179}\\1923r\\238\\151\\255\\128q\\145\\002\\001\\000\"": "example.net.\t3600\tIN\tCAA\t2 auth \"0>09\\006\\010+\\006\\001\\004\\001\\214y\\002\\003\\001\\006\\009`\\134H\\001e\\003\\004\\002\\001\\004 y\\209\\012\\221r\\220\\156Q\\218\\150\\150{\\166\\245:\\231\\182%\\157:\\133\\179}\\1923r\\238\\151\\255\\128q\\145\\002\\001\\000\"", 1545 "example.net. TYPE257 0 issue \"symantec.com\"": "example.net.\t3600\tIN\tCAA\t0 issue \"symantec.com\"", 1546 } 1547 for i, o := range lt { 1548 rr, err := NewRR(i) 1549 if err != nil { 1550 t.Error("failed to parse RR: ", err) 1551 continue 1552 } 1553 if rr.String() != o { 1554 t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) 1555 } 1556 } 1557} 1558 1559func TestPackCAA(t *testing.T) { 1560 m := new(Msg) 1561 record := new(CAA) 1562 record.Hdr = RR_Header{Name: "example.com.", Rrtype: TypeCAA, Class: ClassINET, Ttl: 0} 1563 record.Tag = "issue" 1564 record.Value = "symantec.com" 1565 record.Flag = 1 1566 1567 m.Answer = append(m.Answer, record) 1568 bytes, err := m.Pack() 1569 if err != nil { 1570 t.Fatalf("failed to pack msg: %v", err) 1571 } 1572 if err := m.Unpack(bytes); err != nil { 1573 t.Fatalf("failed to unpack msg: %v", err) 1574 } 1575 if len(m.Answer) != 1 { 1576 t.Fatalf("incorrect number of answers unpacked") 1577 } 1578 rr := m.Answer[0].(*CAA) 1579 if rr.Tag != "issue" { 1580 t.Fatalf("invalid tag for unpacked answer") 1581 } else if rr.Value != "symantec.com" { 1582 t.Fatalf("invalid value for unpacked answer") 1583 } else if rr.Flag != 1 { 1584 t.Fatalf("invalid flag for unpacked answer") 1585 } 1586} 1587 1588func TestParseURI(t *testing.T) { 1589 lt := map[string]string{ 1590 "_http._tcp. IN URI 10 1 \"http://www.example.com/path\"": "_http._tcp.\t3600\tIN\tURI\t10 1 \"http://www.example.com/path\"", 1591 "_http._tcp. IN URI 10 1 \"\"": "_http._tcp.\t3600\tIN\tURI\t10 1 \"\"", 1592 } 1593 for i, o := range lt { 1594 rr, err := NewRR(i) 1595 if err != nil { 1596 t.Error("failed to parse RR: ", err) 1597 continue 1598 } 1599 if rr.String() != o { 1600 t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) 1601 } 1602 } 1603} 1604 1605func TestParseAVC(t *testing.T) { 1606 avcs := map[string]string{ 1607 `example.org. IN AVC "app-name:WOLFGANG|app-class:OAM|business=yes"`: `example.org. 3600 IN AVC "app-name:WOLFGANG|app-class:OAM|business=yes"`, 1608 } 1609 for avc, o := range avcs { 1610 rr, err := NewRR(avc) 1611 if err != nil { 1612 t.Error("failed to parse RR: ", err) 1613 continue 1614 } 1615 if rr.String() != o { 1616 t.Errorf("`%s' should be equal to\n`%s', but is `%s'", avc, o, rr.String()) 1617 } 1618 } 1619} 1620 1621func TestParseCSYNC(t *testing.T) { 1622 syncs := map[string]string{ 1623 `example.com. 3600 IN CSYNC 66 3 A NS AAAA`: `example.com. 3600 IN CSYNC 66 3 A NS AAAA`, 1624 } 1625 for s, o := range syncs { 1626 rr, err := NewRR(s) 1627 if err != nil { 1628 t.Error("failed to parse RR: ", err) 1629 continue 1630 } 1631 if rr.String() != o { 1632 t.Errorf("`%s' should be equal to\n`%s', but is `%s'", s, o, rr.String()) 1633 } 1634 } 1635} 1636 1637func TestParseSVCB(t *testing.T) { 1638 svcbs := map[string]string{ 1639 `example.com. 3600 IN SVCB 0 cloudflare.com.`: `example.com. 3600 IN SVCB 0 cloudflare.com.`, 1640 `example.com. 3600 IN SVCB 65000 cloudflare.com. alpn=h2 ipv4hint=3.4.3.2`: `example.com. 3600 IN SVCB 65000 cloudflare.com. alpn="h2" ipv4hint="3.4.3.2"`, 1641 `example.com. 3600 IN SVCB 65000 cloudflare.com. key65000=4\ 3 key65001="\" " key65002 key65003= key65004="" key65005== key65006==\"\" key65007=\254 key65008=\032`: `example.com. 3600 IN SVCB 65000 cloudflare.com. key65000="4\ 3" key65001="\"\ " key65002="" key65003="" key65004="" key65005="=" key65006="=\"\"" key65007="\254" key65008="\ "`, 1642 } 1643 for s, o := range svcbs { 1644 rr, err := NewRR(s) 1645 if err != nil { 1646 t.Error("failed to parse RR: ", err) 1647 continue 1648 } 1649 if rr.String() != o { 1650 t.Errorf("`%s' should be equal to\n`%s', but is `%s'", s, o, rr.String()) 1651 } 1652 } 1653} 1654 1655func TestParseBadSVCB(t *testing.T) { 1656 header := `example.com. 3600 IN HTTPS ` 1657 evils := []string{ 1658 `0 . no-default-alpn`, // aliasform 1659 `65536 . no-default-alpn`, // bad priority 1660 `1 ..`, // bad domain 1661 `1 . no-default-alpn=1`, // value illegal 1662 `1 . key`, // invalid key 1663 `1 . key=`, // invalid key 1664 `1 . =`, // invalid key 1665 `1 . ==`, // invalid key 1666 `1 . =a`, // invalid key 1667 `1 . ""`, // invalid key 1668 `1 . ""=`, // invalid key 1669 `1 . "a"`, // invalid key 1670 `1 . "a"=`, // invalid key 1671 `1 . key1=`, // we know that key 1672 `1 . key65535`, // key reserved 1673 `1 . key065534`, // key can't be padded 1674 `1 . key65534="f`, // unterminated value 1675 `1 . key65534="`, // unterminated value 1676 `1 . key65534=\2`, // invalid numeric escape 1677 `1 . key65534=\24`, // invalid numeric escape 1678 `1 . key65534=\256`, // invalid numeric escape 1679 `1 . key65534=\`, // invalid numeric escape 1680 `1 . key65534=""alpn`, // zQuote ending needs whitespace 1681 `1 . key65534="a"alpn`, // zQuote ending needs whitespace 1682 `1 . ipv6hint=1.1.1.1`, // not ipv6 1683 `1 . ipv6hint=1:1:1:1`, // not ipv6 1684 `1 . ipv6hint=a`, // not ipv6 1685 `1 . ipv4hint=1.1.1.1.1`, // not ipv4 1686 `1 . ipv4hint=::fc`, // not ipv4 1687 `1 . ipv4hint=..11`, // not ipv4 1688 `1 . ipv4hint=a`, // not ipv4 1689 `1 . port=`, // empty port 1690 `1 . echconfig=YUd`, // bad base64 1691 } 1692 for _, o := range evils { 1693 _, err := NewRR(header + o) 1694 if err == nil { 1695 t.Error("failed to reject invalid RR: ", header+o) 1696 continue 1697 } 1698 } 1699} 1700 1701func TestParseBadNAPTR(t *testing.T) { 1702 // Should look like: mplus.ims.vodafone.com. 3600 IN NAPTR 10 100 "S" "SIP+D2U" "" _sip._udp.mplus.ims.vodafone.com. 1703 naptr := `mplus.ims.vodafone.com. 3600 IN NAPTR 10 100 S SIP+D2U _sip._udp.mplus.ims.vodafone.com.` 1704 _, err := NewRR(naptr) // parse fails, we should not have leaked a goroutine. 1705 if err == nil { 1706 t.Fatalf("parsing NAPTR should have failed: %s", naptr) 1707 } 1708 if err := goroutineLeaked(); err != nil { 1709 t.Errorf("leaked goroutines: %s", err) 1710 } 1711} 1712 1713func TestUnbalancedParens(t *testing.T) { 1714 sig := `example.com. 3600 IN RRSIG MX 15 2 3600 ( 1715 1440021600 1438207200 3613 example.com. ( 1716 oL9krJun7xfBOIWcGHi7mag5/hdZrKWw15jPGrHpjQeRAvTdszaPD+QLs3f 1717 x8A4M3e23mRZ9VrbpMngwcrqNAg== )` 1718 _, err := NewRR(sig) 1719 if err == nil { 1720 t.Fatalf("failed to detect extra opening brace") 1721 } 1722} 1723 1724func TestBad(t *testing.T) { 1725 tests := []string{ 1726 `" TYPE257 9 1E12\x00\x105"`, 1727 `" TYPE256 9 5"`, 1728 `" TYPE257 0\"00000000000000400000000000000000000\x00\x10000000000000000000000000000000000 9 l\x16\x01\x005266"`, 1729 } 1730 for i := range tests { 1731 s, err := strconv.Unquote(tests[i]) 1732 if err != nil { 1733 t.Fatalf("failed to unquote: %q: %s", tests[i], err) 1734 } 1735 if _, err = NewRR(s); err == nil { 1736 t.Errorf("correctly parsed %q", s) 1737 } 1738 } 1739} 1740 1741func TestNULLRecord(t *testing.T) { 1742 // packet captured from iodine 1743 packet := `8116840000010001000000000569627a6c700474657374046d69656b026e6c00000a0001c00c000a0001000000000005497f000001` 1744 data, _ := hex.DecodeString(packet) 1745 msg := new(Msg) 1746 err := msg.Unpack(data) 1747 if err != nil { 1748 t.Fatalf("Failed to unpack NULL record") 1749 } 1750 if _, ok := msg.Answer[0].(*NULL); !ok { 1751 t.Fatalf("Expected packet to contain NULL record") 1752 } 1753} 1754 1755func TestParseAPL(t *testing.T) { 1756 tests := []struct { 1757 name string 1758 in string 1759 expect string 1760 }{ 1761 { 1762 "v4", 1763 ". APL 1:192.0.2.0/24", 1764 ".\t3600\tIN\tAPL\t1:192.0.2.0/24", 1765 }, 1766 { 1767 "v6", 1768 ". APL 2:2001:db8::/32", 1769 ".\t3600\tIN\tAPL\t2:2001:db8::/32", 1770 }, 1771 { 1772 "null v6", 1773 ". APL 2:::/0", 1774 ".\t3600\tIN\tAPL\t2:::/0", 1775 }, 1776 { 1777 "null v4", 1778 ". APL 1:0.0.0.0/0", 1779 ".\t3600\tIN\tAPL\t1:0.0.0.0/0", 1780 }, 1781 { 1782 "full v6", 1783 ". APL 2:::/0", 1784 ".\t3600\tIN\tAPL\t2:::/0", 1785 }, 1786 { 1787 "full v4", 1788 ". APL 1:192.0.2.1/32", 1789 ".\t3600\tIN\tAPL\t1:192.0.2.1/32", 1790 }, 1791 { 1792 "full v6", 1793 ". APL 2:2001:0db8:d2b4:b6ba:50db:49cc:a8d1:5bb1/128", 1794 ".\t3600\tIN\tAPL\t2:2001:db8:d2b4:b6ba:50db:49cc:a8d1:5bb1/128", 1795 }, 1796 { 1797 "v4in6", 1798 ". APL 2:::ffff:192.0.2.0/120", 1799 ".\t3600\tIN\tAPL\t2:::ffff:192.0.2.0/120", 1800 }, 1801 { 1802 "v4in6 v6 syntax", 1803 ". APL 2:::ffff:c000:0200/120", 1804 ".\t3600\tIN\tAPL\t2:::ffff:192.0.2.0/120", 1805 }, 1806 { 1807 "negate", 1808 ". APL !1:192.0.2.0/24", 1809 ".\t3600\tIN\tAPL\t!1:192.0.2.0/24", 1810 }, 1811 { 1812 "multiple", 1813 ". APL 1:192.0.2.0/24 !1:192.0.2.1/32 2:2001:db8::/32 !2:2001:db8:1::0/48", 1814 ".\t3600\tIN\tAPL\t1:192.0.2.0/24 !1:192.0.2.1/32 2:2001:db8::/32 !2:2001:db8:1::/48", 1815 }, 1816 { 1817 "no address", 1818 ". APL", 1819 ".\t3600\tIN\tAPL\t", 1820 }, 1821 } 1822 for _, tc := range tests { 1823 t.Run(tc.name, func(t *testing.T) { 1824 rr, err := NewRR(tc.in) 1825 if err != nil { 1826 t.Fatalf("failed to parse RR: %s", err) 1827 } 1828 1829 got := rr.String() 1830 if got != tc.expect { 1831 t.Errorf("expected %q, got %q", tc.expect, got) 1832 } 1833 }) 1834 } 1835} 1836 1837func TestParseAPLErrors(t *testing.T) { 1838 tests := []struct { 1839 name string 1840 in string 1841 }{ 1842 { 1843 "unexpected", 1844 `. APL ""`, 1845 }, 1846 { 1847 "unrecognized family", 1848 ". APL 3:0.0.0.0/0", 1849 }, 1850 { 1851 "malformed family", 1852 ". APL foo:0.0.0.0/0", 1853 }, 1854 { 1855 "malformed address", 1856 ". APL 1:192.0.2/16", 1857 }, 1858 { 1859 "extra bits", 1860 ". APL 2:2001:db8::/0", 1861 }, 1862 { 1863 "address mismatch v2", 1864 ". APL 1:2001:db8::/64", 1865 }, 1866 { 1867 "address mismatch v6", 1868 ". APL 2:192.0.2.1/32", 1869 }, 1870 { 1871 "no prefix", 1872 ". APL 1:192.0.2.1", 1873 }, 1874 { 1875 "no family", 1876 ". APL 0.0.0.0/0", 1877 }, 1878 } 1879 for _, tc := range tests { 1880 t.Run(tc.name, func(t *testing.T) { 1881 _, err := NewRR(tc.in) 1882 if err == nil { 1883 t.Fatal("expected error, got none") 1884 } 1885 }) 1886 } 1887} 1888 1889func TestUnpackRRWithHeaderInvalidLengths(t *testing.T) { 1890 rr, err := NewRR("test.example.org. 300 IN SSHFP 1 2 BC6533CDC95A79078A39A56EA7635984ED655318ADA9B6159E30723665DA95BB") 1891 if err != nil { 1892 t.Fatalf("failed to parse SSHFP record: %v", err) 1893 } 1894 1895 buf := make([]byte, Len(rr)) 1896 headerEnd, end, err := packRR(rr, buf, 0, compressionMap{}, false) 1897 if err != nil { 1898 t.Fatalf("failed to pack A record: %v", err) 1899 } 1900 1901 rr.Header().Rdlength = uint16(end - headerEnd) 1902 for _, off := range []int{ 1903 -1, 1904 end + 1, 1905 1<<16 - 1, 1906 } { 1907 _, _, err := UnpackRRWithHeader(*rr.Header(), buf, off) 1908 if de, ok := err.(*Error); !ok || de.err != "bad off" { 1909 t.Errorf("UnpackRRWithHeader with bad offset (%d) returned wrong or no error: %v", off, err) 1910 } 1911 } 1912 1913 for _, rdlength := range []uint16{ 1914 uint16(end - headerEnd + 1), 1915 uint16(end), 1916 1<<16 - 1, 1917 } { 1918 rr.Header().Rdlength = rdlength 1919 1920 _, _, err := UnpackRRWithHeader(*rr.Header(), buf, headerEnd) 1921 if de, ok := err.(*Error); !ok || de.err != "bad rdlength" { 1922 t.Errorf("UnpackRRWithHeader with bad rdlength (%d) returned wrong or no error: %v", rdlength, err) 1923 } 1924 } 1925} 1926 1927func TestParseZONEMD(t *testing.T) { 1928 // Uses examples from https://tools.ietf.org/html/rfc8976 1929 dt := map[string]string{ 1930 // Simple Zone 1931 `example. 86400 IN ZONEMD 2018031900 1 1 ( 1932 c68090d90a7aed71 1933 6bc459f9340e3d7c 1934 1370d4d24b7e2fc3 1935 a1ddc0b9a87153b9 1936 a9713b3c9ae5cc27 1937 777f98b8e730044c ) 1938 `: "example.\t86400\tIN\tZONEMD\t2018031900 1 1 c68090d90a7aed716bc459f9340e3d7c1370d4d24b7e2fc3a1ddc0b9a87153b9a9713b3c9ae5cc27777f98b8e730044c", 1939 // Complex Zone 1940 `example. 86400 IN ZONEMD 2018031900 1 1 ( 1941 a3b69bad980a3504 1942 e1cffcb0fd6397f9 1943 3848071c93151f55 1944 2ae2f6b1711d4bd2 1945 d8b39808226d7b9d 1946 b71e34b72077f8fe ) 1947 `: "example.\t86400\tIN\tZONEMD\t2018031900 1 1 a3b69bad980a3504e1cffcb0fd6397f93848071c93151f552ae2f6b1711d4bd2d8b39808226d7b9db71e34b72077f8fe", 1948 // Multiple Digests Zone 1949 `example. 86400 IN ZONEMD 2018031900 1 1 ( 1950 62e6cf51b02e54b9 1951 b5f967d547ce4313 1952 6792901f9f88e637 1953 493daaf401c92c27 1954 9dd10f0edb1c56f8 1955 080211f8480ee306 ) 1956 `: "example.\t86400\tIN\tZONEMD\t2018031900 1 1 62e6cf51b02e54b9b5f967d547ce43136792901f9f88e637493daaf401c92c279dd10f0edb1c56f8080211f8480ee306", 1957 `example. 86400 IN ZONEMD 2018031900 1 2 ( 1958 08cfa1115c7b948c 1959 4163a901270395ea 1960 226a930cd2cbcf2f 1961 a9a5e6eb85f37c8a 1962 4e114d884e66f176 1963 eab121cb02db7d65 1964 2e0cc4827e7a3204 1965 f166b47e5613fd27 ) 1966 `: "example.\t86400\tIN\tZONEMD\t2018031900 1 2 08cfa1115c7b948c4163a901270395ea226a930cd2cbcf2fa9a5e6eb85f37c8a4e114d884e66f176eab121cb02db7d652e0cc4827e7a3204f166b47e5613fd27", 1967 `example. 86400 IN ZONEMD 2018031900 1 240 ( 1968 e2d523f654b9422a 1969 96c5a8f44607bbee ) 1970 `: "example. 86400 IN ZONEMD 2018031900 1 240 e2d523f654b9422a96c5a8f44607bbee", 1971 `example. 86400 IN ZONEMD 2018031900 241 1 ( 1972 e1846540e33a9e41 1973 89792d18d5d131f6 1974 05fc283e ) 1975 `: "example. 86400 IN ZONEMD 2018031900 241 1 e1846540e33a9e4189792d18d5d131f605fc283e", 1976 // URI.ARPA zone 1977 `uri.arpa. 3600 IN ZONEMD 2018100702 1 1 ( 1978 0dbc3c4dbfd75777c12ca19c337854b1577799901307c482e9d91d5d15 1979 cd934d16319d98e30c4201cf25a1d5a0254960 )`: "uri.arpa.\t3600\tIN\tZONEMD\t2018100702 1 1 0dbc3c4dbfd75777c12ca19c337854b1577799901307c482e9d91d5d15cd934d16319d98e30c4201cf25a1d5a0254960", 1980 // ROOT-SERVERS.NET Zone 1981 `root-servers.net. 3600000 IN ZONEMD 2018091100 1 1 ( 1982 f1ca0ccd91bd5573d9f431c00ee0101b2545c97602be0a97 1983 8a3b11dbfc1c776d5b3e86ae3d973d6b5349ba7f04340f79 ) 1984 `: "root-servers.net.\t3600000\tIN\tZONEMD\t2018091100 1 1 f1ca0ccd91bd5573d9f431c00ee0101b2545c97602be0a978a3b11dbfc1c776d5b3e86ae3d973d6b5349ba7f04340f79", 1985 } 1986 for i, o := range dt { 1987 rr, err := NewRR(i) 1988 if err != nil { 1989 t.Error("failed to parse RR: ", err) 1990 continue 1991 } 1992 if rr.String() != o { 1993 t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) 1994 } 1995 } 1996} 1997