github.com/peggyl/go@v0.0.0-20151008231540-ae315999c2d5/src/net/dnsmsg.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // DNS packet assembly. See RFC 1035. 6 // 7 // This is intended to support name resolution during Dial. 8 // It doesn't have to be blazing fast. 9 // 10 // Each message structure has a Walk method that is used by 11 // a generic pack/unpack routine. Thus, if in the future we need 12 // to define new message structs, no new pack/unpack/printing code 13 // needs to be written. 14 // 15 // The first half of this file defines the DNS message formats. 16 // The second half implements the conversion to and from wire format. 17 // A few of the structure elements have string tags to aid the 18 // generic pack/unpack routines. 19 // 20 // TODO(rsc): There are enough names defined in this file that they're all 21 // prefixed with dns. Perhaps put this in its own package later. 22 23 package net 24 25 // Packet formats 26 27 // Wire constants. 28 const ( 29 // valid dnsRR_Header.Rrtype and dnsQuestion.qtype 30 dnsTypeA = 1 31 dnsTypeNS = 2 32 dnsTypeMD = 3 33 dnsTypeMF = 4 34 dnsTypeCNAME = 5 35 dnsTypeSOA = 6 36 dnsTypeMB = 7 37 dnsTypeMG = 8 38 dnsTypeMR = 9 39 dnsTypeNULL = 10 40 dnsTypeWKS = 11 41 dnsTypePTR = 12 42 dnsTypeHINFO = 13 43 dnsTypeMINFO = 14 44 dnsTypeMX = 15 45 dnsTypeTXT = 16 46 dnsTypeAAAA = 28 47 dnsTypeSRV = 33 48 49 // valid dnsQuestion.qtype only 50 dnsTypeAXFR = 252 51 dnsTypeMAILB = 253 52 dnsTypeMAILA = 254 53 dnsTypeALL = 255 54 55 // valid dnsQuestion.qclass 56 dnsClassINET = 1 57 dnsClassCSNET = 2 58 dnsClassCHAOS = 3 59 dnsClassHESIOD = 4 60 dnsClassANY = 255 61 62 // dnsMsg.rcode 63 dnsRcodeSuccess = 0 64 dnsRcodeFormatError = 1 65 dnsRcodeServerFailure = 2 66 dnsRcodeNameError = 3 67 dnsRcodeNotImplemented = 4 68 dnsRcodeRefused = 5 69 ) 70 71 // A dnsStruct describes how to iterate over its fields to emulate 72 // reflective marshalling. 73 type dnsStruct interface { 74 // Walk iterates over fields of a structure and calls f 75 // with a reference to that field, the name of the field 76 // and a tag ("", "domain", "ipv4", "ipv6") specifying 77 // particular encodings. Possible concrete types 78 // for v are *uint16, *uint32, *string, or []byte, and 79 // *int, *bool in the case of dnsMsgHdr. 80 // Whenever f returns false, Walk must stop and return 81 // false, and otherwise return true. 82 Walk(f func(v interface{}, name, tag string) (ok bool)) (ok bool) 83 } 84 85 // The wire format for the DNS packet header. 86 type dnsHeader struct { 87 Id uint16 88 Bits uint16 89 Qdcount, Ancount, Nscount, Arcount uint16 90 } 91 92 func (h *dnsHeader) Walk(f func(v interface{}, name, tag string) bool) bool { 93 return f(&h.Id, "Id", "") && 94 f(&h.Bits, "Bits", "") && 95 f(&h.Qdcount, "Qdcount", "") && 96 f(&h.Ancount, "Ancount", "") && 97 f(&h.Nscount, "Nscount", "") && 98 f(&h.Arcount, "Arcount", "") 99 } 100 101 const ( 102 // dnsHeader.Bits 103 _QR = 1 << 15 // query/response (response=1) 104 _AA = 1 << 10 // authoritative 105 _TC = 1 << 9 // truncated 106 _RD = 1 << 8 // recursion desired 107 _RA = 1 << 7 // recursion available 108 ) 109 110 // DNS queries. 111 type dnsQuestion struct { 112 Name string `net:"domain-name"` // `net:"domain-name"` specifies encoding; see packers below 113 Qtype uint16 114 Qclass uint16 115 } 116 117 func (q *dnsQuestion) Walk(f func(v interface{}, name, tag string) bool) bool { 118 return f(&q.Name, "Name", "domain") && 119 f(&q.Qtype, "Qtype", "") && 120 f(&q.Qclass, "Qclass", "") 121 } 122 123 // DNS responses (resource records). 124 // There are many types of messages, 125 // but they all share the same header. 126 type dnsRR_Header struct { 127 Name string `net:"domain-name"` 128 Rrtype uint16 129 Class uint16 130 Ttl uint32 131 Rdlength uint16 // length of data after header 132 } 133 134 func (h *dnsRR_Header) Header() *dnsRR_Header { 135 return h 136 } 137 138 func (h *dnsRR_Header) Walk(f func(v interface{}, name, tag string) bool) bool { 139 return f(&h.Name, "Name", "domain") && 140 f(&h.Rrtype, "Rrtype", "") && 141 f(&h.Class, "Class", "") && 142 f(&h.Ttl, "Ttl", "") && 143 f(&h.Rdlength, "Rdlength", "") 144 } 145 146 type dnsRR interface { 147 dnsStruct 148 Header() *dnsRR_Header 149 } 150 151 // Specific DNS RR formats for each query type. 152 153 type dnsRR_CNAME struct { 154 Hdr dnsRR_Header 155 Cname string `net:"domain-name"` 156 } 157 158 func (rr *dnsRR_CNAME) Header() *dnsRR_Header { 159 return &rr.Hdr 160 } 161 162 func (rr *dnsRR_CNAME) Walk(f func(v interface{}, name, tag string) bool) bool { 163 return rr.Hdr.Walk(f) && f(&rr.Cname, "Cname", "domain") 164 } 165 166 type dnsRR_HINFO struct { 167 Hdr dnsRR_Header 168 Cpu string 169 Os string 170 } 171 172 func (rr *dnsRR_HINFO) Header() *dnsRR_Header { 173 return &rr.Hdr 174 } 175 176 func (rr *dnsRR_HINFO) Walk(f func(v interface{}, name, tag string) bool) bool { 177 return rr.Hdr.Walk(f) && f(&rr.Cpu, "Cpu", "") && f(&rr.Os, "Os", "") 178 } 179 180 type dnsRR_MB struct { 181 Hdr dnsRR_Header 182 Mb string `net:"domain-name"` 183 } 184 185 func (rr *dnsRR_MB) Header() *dnsRR_Header { 186 return &rr.Hdr 187 } 188 189 func (rr *dnsRR_MB) Walk(f func(v interface{}, name, tag string) bool) bool { 190 return rr.Hdr.Walk(f) && f(&rr.Mb, "Mb", "domain") 191 } 192 193 type dnsRR_MG struct { 194 Hdr dnsRR_Header 195 Mg string `net:"domain-name"` 196 } 197 198 func (rr *dnsRR_MG) Header() *dnsRR_Header { 199 return &rr.Hdr 200 } 201 202 func (rr *dnsRR_MG) Walk(f func(v interface{}, name, tag string) bool) bool { 203 return rr.Hdr.Walk(f) && f(&rr.Mg, "Mg", "domain") 204 } 205 206 type dnsRR_MINFO struct { 207 Hdr dnsRR_Header 208 Rmail string `net:"domain-name"` 209 Email string `net:"domain-name"` 210 } 211 212 func (rr *dnsRR_MINFO) Header() *dnsRR_Header { 213 return &rr.Hdr 214 } 215 216 func (rr *dnsRR_MINFO) Walk(f func(v interface{}, name, tag string) bool) bool { 217 return rr.Hdr.Walk(f) && f(&rr.Rmail, "Rmail", "domain") && f(&rr.Email, "Email", "domain") 218 } 219 220 type dnsRR_MR struct { 221 Hdr dnsRR_Header 222 Mr string `net:"domain-name"` 223 } 224 225 func (rr *dnsRR_MR) Header() *dnsRR_Header { 226 return &rr.Hdr 227 } 228 229 func (rr *dnsRR_MR) Walk(f func(v interface{}, name, tag string) bool) bool { 230 return rr.Hdr.Walk(f) && f(&rr.Mr, "Mr", "domain") 231 } 232 233 type dnsRR_MX struct { 234 Hdr dnsRR_Header 235 Pref uint16 236 Mx string `net:"domain-name"` 237 } 238 239 func (rr *dnsRR_MX) Header() *dnsRR_Header { 240 return &rr.Hdr 241 } 242 243 func (rr *dnsRR_MX) Walk(f func(v interface{}, name, tag string) bool) bool { 244 return rr.Hdr.Walk(f) && f(&rr.Pref, "Pref", "") && f(&rr.Mx, "Mx", "domain") 245 } 246 247 type dnsRR_NS struct { 248 Hdr dnsRR_Header 249 Ns string `net:"domain-name"` 250 } 251 252 func (rr *dnsRR_NS) Header() *dnsRR_Header { 253 return &rr.Hdr 254 } 255 256 func (rr *dnsRR_NS) Walk(f func(v interface{}, name, tag string) bool) bool { 257 return rr.Hdr.Walk(f) && f(&rr.Ns, "Ns", "domain") 258 } 259 260 type dnsRR_PTR struct { 261 Hdr dnsRR_Header 262 Ptr string `net:"domain-name"` 263 } 264 265 func (rr *dnsRR_PTR) Header() *dnsRR_Header { 266 return &rr.Hdr 267 } 268 269 func (rr *dnsRR_PTR) Walk(f func(v interface{}, name, tag string) bool) bool { 270 return rr.Hdr.Walk(f) && f(&rr.Ptr, "Ptr", "domain") 271 } 272 273 type dnsRR_SOA struct { 274 Hdr dnsRR_Header 275 Ns string `net:"domain-name"` 276 Mbox string `net:"domain-name"` 277 Serial uint32 278 Refresh uint32 279 Retry uint32 280 Expire uint32 281 Minttl uint32 282 } 283 284 func (rr *dnsRR_SOA) Header() *dnsRR_Header { 285 return &rr.Hdr 286 } 287 288 func (rr *dnsRR_SOA) Walk(f func(v interface{}, name, tag string) bool) bool { 289 return rr.Hdr.Walk(f) && 290 f(&rr.Ns, "Ns", "domain") && 291 f(&rr.Mbox, "Mbox", "domain") && 292 f(&rr.Serial, "Serial", "") && 293 f(&rr.Refresh, "Refresh", "") && 294 f(&rr.Retry, "Retry", "") && 295 f(&rr.Expire, "Expire", "") && 296 f(&rr.Minttl, "Minttl", "") 297 } 298 299 type dnsRR_TXT struct { 300 Hdr dnsRR_Header 301 Txt string // not domain name 302 } 303 304 func (rr *dnsRR_TXT) Header() *dnsRR_Header { 305 return &rr.Hdr 306 } 307 308 func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool { 309 if !rr.Hdr.Walk(f) { 310 return false 311 } 312 var n uint16 = 0 313 for n < rr.Hdr.Rdlength { 314 var txt string 315 if !f(&txt, "Txt", "") { 316 return false 317 } 318 // more bytes than rr.Hdr.Rdlength said there woudld be 319 if rr.Hdr.Rdlength-n < uint16(len(txt))+1 { 320 return false 321 } 322 n += uint16(len(txt)) + 1 323 rr.Txt += txt 324 } 325 return true 326 } 327 328 type dnsRR_SRV struct { 329 Hdr dnsRR_Header 330 Priority uint16 331 Weight uint16 332 Port uint16 333 Target string `net:"domain-name"` 334 } 335 336 func (rr *dnsRR_SRV) Header() *dnsRR_Header { 337 return &rr.Hdr 338 } 339 340 func (rr *dnsRR_SRV) Walk(f func(v interface{}, name, tag string) bool) bool { 341 return rr.Hdr.Walk(f) && 342 f(&rr.Priority, "Priority", "") && 343 f(&rr.Weight, "Weight", "") && 344 f(&rr.Port, "Port", "") && 345 f(&rr.Target, "Target", "domain") 346 } 347 348 type dnsRR_A struct { 349 Hdr dnsRR_Header 350 A uint32 `net:"ipv4"` 351 } 352 353 func (rr *dnsRR_A) Header() *dnsRR_Header { 354 return &rr.Hdr 355 } 356 357 func (rr *dnsRR_A) Walk(f func(v interface{}, name, tag string) bool) bool { 358 return rr.Hdr.Walk(f) && f(&rr.A, "A", "ipv4") 359 } 360 361 type dnsRR_AAAA struct { 362 Hdr dnsRR_Header 363 AAAA [16]byte `net:"ipv6"` 364 } 365 366 func (rr *dnsRR_AAAA) Header() *dnsRR_Header { 367 return &rr.Hdr 368 } 369 370 func (rr *dnsRR_AAAA) Walk(f func(v interface{}, name, tag string) bool) bool { 371 return rr.Hdr.Walk(f) && f(rr.AAAA[:], "AAAA", "ipv6") 372 } 373 374 // Packing and unpacking. 375 // 376 // All the packers and unpackers take a (msg []byte, off int) 377 // and return (off1 int, ok bool). If they return ok==false, they 378 // also return off1==len(msg), so that the next unpacker will 379 // also fail. This lets us avoid checks of ok until the end of a 380 // packing sequence. 381 382 // Map of constructors for each RR wire type. 383 var rr_mk = map[int]func() dnsRR{ 384 dnsTypeCNAME: func() dnsRR { return new(dnsRR_CNAME) }, 385 dnsTypeHINFO: func() dnsRR { return new(dnsRR_HINFO) }, 386 dnsTypeMB: func() dnsRR { return new(dnsRR_MB) }, 387 dnsTypeMG: func() dnsRR { return new(dnsRR_MG) }, 388 dnsTypeMINFO: func() dnsRR { return new(dnsRR_MINFO) }, 389 dnsTypeMR: func() dnsRR { return new(dnsRR_MR) }, 390 dnsTypeMX: func() dnsRR { return new(dnsRR_MX) }, 391 dnsTypeNS: func() dnsRR { return new(dnsRR_NS) }, 392 dnsTypePTR: func() dnsRR { return new(dnsRR_PTR) }, 393 dnsTypeSOA: func() dnsRR { return new(dnsRR_SOA) }, 394 dnsTypeTXT: func() dnsRR { return new(dnsRR_TXT) }, 395 dnsTypeSRV: func() dnsRR { return new(dnsRR_SRV) }, 396 dnsTypeA: func() dnsRR { return new(dnsRR_A) }, 397 dnsTypeAAAA: func() dnsRR { return new(dnsRR_AAAA) }, 398 } 399 400 // Pack a domain name s into msg[off:]. 401 // Domain names are a sequence of counted strings 402 // split at the dots. They end with a zero-length string. 403 func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) { 404 // Add trailing dot to canonicalize name. 405 if n := len(s); n == 0 || s[n-1] != '.' { 406 s += "." 407 } 408 409 // Each dot ends a segment of the name. 410 // We trade each dot byte for a length byte. 411 // There is also a trailing zero. 412 // Check that we have all the space we need. 413 tot := len(s) + 1 414 if off+tot > len(msg) { 415 return len(msg), false 416 } 417 418 // Emit sequence of counted strings, chopping at dots. 419 begin := 0 420 for i := 0; i < len(s); i++ { 421 if s[i] == '.' { 422 if i-begin >= 1<<6 { // top two bits of length must be clear 423 return len(msg), false 424 } 425 msg[off] = byte(i - begin) 426 off++ 427 for j := begin; j < i; j++ { 428 msg[off] = s[j] 429 off++ 430 } 431 begin = i + 1 432 } 433 } 434 msg[off] = 0 435 off++ 436 return off, true 437 } 438 439 // Unpack a domain name. 440 // In addition to the simple sequences of counted strings above, 441 // domain names are allowed to refer to strings elsewhere in the 442 // packet, to avoid repeating common suffixes when returning 443 // many entries in a single domain. The pointers are marked 444 // by a length byte with the top two bits set. Ignoring those 445 // two bits, that byte and the next give a 14 bit offset from msg[0] 446 // where we should pick up the trail. 447 // Note that if we jump elsewhere in the packet, 448 // we return off1 == the offset after the first pointer we found, 449 // which is where the next record will start. 450 // In theory, the pointers are only allowed to jump backward. 451 // We let them jump anywhere and stop jumping after a while. 452 func unpackDomainName(msg []byte, off int) (s string, off1 int, ok bool) { 453 s = "" 454 ptr := 0 // number of pointers followed 455 Loop: 456 for { 457 if off >= len(msg) { 458 return "", len(msg), false 459 } 460 c := int(msg[off]) 461 off++ 462 switch c & 0xC0 { 463 case 0x00: 464 if c == 0x00 { 465 // end of name 466 break Loop 467 } 468 // literal string 469 if off+c > len(msg) { 470 return "", len(msg), false 471 } 472 s += string(msg[off:off+c]) + "." 473 off += c 474 case 0xC0: 475 // pointer to somewhere else in msg. 476 // remember location after first ptr, 477 // since that's how many bytes we consumed. 478 // also, don't follow too many pointers -- 479 // maybe there's a loop. 480 if off >= len(msg) { 481 return "", len(msg), false 482 } 483 c1 := msg[off] 484 off++ 485 if ptr == 0 { 486 off1 = off 487 } 488 if ptr++; ptr > 10 { 489 return "", len(msg), false 490 } 491 off = (c^0xC0)<<8 | int(c1) 492 default: 493 // 0x80 and 0x40 are reserved 494 return "", len(msg), false 495 } 496 } 497 if ptr == 0 { 498 off1 = off 499 } 500 return s, off1, true 501 } 502 503 // packStruct packs a structure into msg at specified offset off, and 504 // returns off1 such that msg[off:off1] is the encoded data. 505 func packStruct(any dnsStruct, msg []byte, off int) (off1 int, ok bool) { 506 ok = any.Walk(func(field interface{}, name, tag string) bool { 507 switch fv := field.(type) { 508 default: 509 println("net: dns: unknown packing type") 510 return false 511 case *uint16: 512 i := *fv 513 if off+2 > len(msg) { 514 return false 515 } 516 msg[off] = byte(i >> 8) 517 msg[off+1] = byte(i) 518 off += 2 519 case *uint32: 520 i := *fv 521 msg[off] = byte(i >> 24) 522 msg[off+1] = byte(i >> 16) 523 msg[off+2] = byte(i >> 8) 524 msg[off+3] = byte(i) 525 off += 4 526 case []byte: 527 n := len(fv) 528 if off+n > len(msg) { 529 return false 530 } 531 copy(msg[off:off+n], fv) 532 off += n 533 case *string: 534 s := *fv 535 switch tag { 536 default: 537 println("net: dns: unknown string tag", tag) 538 return false 539 case "domain": 540 off, ok = packDomainName(s, msg, off) 541 if !ok { 542 return false 543 } 544 case "": 545 // Counted string: 1 byte length. 546 if len(s) > 255 || off+1+len(s) > len(msg) { 547 return false 548 } 549 msg[off] = byte(len(s)) 550 off++ 551 off += copy(msg[off:], s) 552 } 553 } 554 return true 555 }) 556 if !ok { 557 return len(msg), false 558 } 559 return off, true 560 } 561 562 // unpackStruct decodes msg[off:] into the given structure, and 563 // returns off1 such that msg[off:off1] is the encoded data. 564 func unpackStruct(any dnsStruct, msg []byte, off int) (off1 int, ok bool) { 565 ok = any.Walk(func(field interface{}, name, tag string) bool { 566 switch fv := field.(type) { 567 default: 568 println("net: dns: unknown packing type") 569 return false 570 case *uint16: 571 if off+2 > len(msg) { 572 return false 573 } 574 *fv = uint16(msg[off])<<8 | uint16(msg[off+1]) 575 off += 2 576 case *uint32: 577 if off+4 > len(msg) { 578 return false 579 } 580 *fv = uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | 581 uint32(msg[off+2])<<8 | uint32(msg[off+3]) 582 off += 4 583 case []byte: 584 n := len(fv) 585 if off+n > len(msg) { 586 return false 587 } 588 copy(fv, msg[off:off+n]) 589 off += n 590 case *string: 591 var s string 592 switch tag { 593 default: 594 println("net: dns: unknown string tag", tag) 595 return false 596 case "domain": 597 s, off, ok = unpackDomainName(msg, off) 598 if !ok { 599 return false 600 } 601 case "": 602 if off >= len(msg) || off+1+int(msg[off]) > len(msg) { 603 return false 604 } 605 n := int(msg[off]) 606 off++ 607 b := make([]byte, n) 608 for i := 0; i < n; i++ { 609 b[i] = msg[off+i] 610 } 611 off += n 612 s = string(b) 613 } 614 *fv = s 615 } 616 return true 617 }) 618 if !ok { 619 return len(msg), false 620 } 621 return off, true 622 } 623 624 // Generic struct printer. Prints fields with tag "ipv4" or "ipv6" 625 // as IP addresses. 626 func printStruct(any dnsStruct) string { 627 s := "{" 628 i := 0 629 any.Walk(func(val interface{}, name, tag string) bool { 630 i++ 631 if i > 1 { 632 s += ", " 633 } 634 s += name + "=" 635 switch tag { 636 case "ipv4": 637 i := *val.(*uint32) 638 s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String() 639 case "ipv6": 640 i := val.([]byte) 641 s += IP(i).String() 642 default: 643 var i int64 644 switch v := val.(type) { 645 default: 646 // can't really happen. 647 s += "<unknown type>" 648 return true 649 case *string: 650 s += *v 651 return true 652 case []byte: 653 s += string(v) 654 return true 655 case *bool: 656 if *v { 657 s += "true" 658 } else { 659 s += "false" 660 } 661 return true 662 case *int: 663 i = int64(*v) 664 case *uint: 665 i = int64(*v) 666 case *uint8: 667 i = int64(*v) 668 case *uint16: 669 i = int64(*v) 670 case *uint32: 671 i = int64(*v) 672 case *uint64: 673 i = int64(*v) 674 case *uintptr: 675 i = int64(*v) 676 } 677 s += itoa(int(i)) 678 } 679 return true 680 }) 681 s += "}" 682 return s 683 } 684 685 // Resource record packer. 686 func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) { 687 var off1 int 688 // pack twice, once to find end of header 689 // and again to find end of packet. 690 // a bit inefficient but this doesn't need to be fast. 691 // off1 is end of header 692 // off2 is end of rr 693 off1, ok = packStruct(rr.Header(), msg, off) 694 if !ok { 695 return len(msg), false 696 } 697 off2, ok = packStruct(rr, msg, off) 698 if !ok { 699 return len(msg), false 700 } 701 // pack a third time; redo header with correct data length 702 rr.Header().Rdlength = uint16(off2 - off1) 703 packStruct(rr.Header(), msg, off) 704 return off2, true 705 } 706 707 // Resource record unpacker. 708 func unpackRR(msg []byte, off int) (rr dnsRR, off1 int, ok bool) { 709 // unpack just the header, to find the rr type and length 710 var h dnsRR_Header 711 off0 := off 712 if off, ok = unpackStruct(&h, msg, off); !ok { 713 return nil, len(msg), false 714 } 715 end := off + int(h.Rdlength) 716 717 // make an rr of that type and re-unpack. 718 // again inefficient but doesn't need to be fast. 719 mk, known := rr_mk[int(h.Rrtype)] 720 if !known { 721 return &h, end, true 722 } 723 rr = mk() 724 off, ok = unpackStruct(rr, msg, off0) 725 if off != end { 726 return &h, end, true 727 } 728 return rr, off, ok 729 } 730 731 // Usable representation of a DNS packet. 732 733 // A manually-unpacked version of (id, bits). 734 // This is in its own struct for easy printing. 735 type dnsMsgHdr struct { 736 id uint16 737 response bool 738 opcode int 739 authoritative bool 740 truncated bool 741 recursion_desired bool 742 recursion_available bool 743 rcode int 744 } 745 746 func (h *dnsMsgHdr) Walk(f func(v interface{}, name, tag string) bool) bool { 747 return f(&h.id, "id", "") && 748 f(&h.response, "response", "") && 749 f(&h.opcode, "opcode", "") && 750 f(&h.authoritative, "authoritative", "") && 751 f(&h.truncated, "truncated", "") && 752 f(&h.recursion_desired, "recursion_desired", "") && 753 f(&h.recursion_available, "recursion_available", "") && 754 f(&h.rcode, "rcode", "") 755 } 756 757 type dnsMsg struct { 758 dnsMsgHdr 759 question []dnsQuestion 760 answer []dnsRR 761 ns []dnsRR 762 extra []dnsRR 763 } 764 765 func (dns *dnsMsg) Pack() (msg []byte, ok bool) { 766 var dh dnsHeader 767 768 // Convert convenient dnsMsg into wire-like dnsHeader. 769 dh.Id = dns.id 770 dh.Bits = uint16(dns.opcode)<<11 | uint16(dns.rcode) 771 if dns.recursion_available { 772 dh.Bits |= _RA 773 } 774 if dns.recursion_desired { 775 dh.Bits |= _RD 776 } 777 if dns.truncated { 778 dh.Bits |= _TC 779 } 780 if dns.authoritative { 781 dh.Bits |= _AA 782 } 783 if dns.response { 784 dh.Bits |= _QR 785 } 786 787 // Prepare variable sized arrays. 788 question := dns.question 789 answer := dns.answer 790 ns := dns.ns 791 extra := dns.extra 792 793 dh.Qdcount = uint16(len(question)) 794 dh.Ancount = uint16(len(answer)) 795 dh.Nscount = uint16(len(ns)) 796 dh.Arcount = uint16(len(extra)) 797 798 // Could work harder to calculate message size, 799 // but this is far more than we need and not 800 // big enough to hurt the allocator. 801 msg = make([]byte, 2000) 802 803 // Pack it in: header and then the pieces. 804 off := 0 805 off, ok = packStruct(&dh, msg, off) 806 for i := 0; i < len(question); i++ { 807 off, ok = packStruct(&question[i], msg, off) 808 } 809 for i := 0; i < len(answer); i++ { 810 off, ok = packRR(answer[i], msg, off) 811 } 812 for i := 0; i < len(ns); i++ { 813 off, ok = packRR(ns[i], msg, off) 814 } 815 for i := 0; i < len(extra); i++ { 816 off, ok = packRR(extra[i], msg, off) 817 } 818 if !ok { 819 return nil, false 820 } 821 return msg[0:off], true 822 } 823 824 func (dns *dnsMsg) Unpack(msg []byte) bool { 825 // Header. 826 var dh dnsHeader 827 off := 0 828 var ok bool 829 if off, ok = unpackStruct(&dh, msg, off); !ok { 830 return false 831 } 832 dns.id = dh.Id 833 dns.response = (dh.Bits & _QR) != 0 834 dns.opcode = int(dh.Bits>>11) & 0xF 835 dns.authoritative = (dh.Bits & _AA) != 0 836 dns.truncated = (dh.Bits & _TC) != 0 837 dns.recursion_desired = (dh.Bits & _RD) != 0 838 dns.recursion_available = (dh.Bits & _RA) != 0 839 dns.rcode = int(dh.Bits & 0xF) 840 841 // Arrays. 842 dns.question = make([]dnsQuestion, dh.Qdcount) 843 dns.answer = make([]dnsRR, 0, dh.Ancount) 844 dns.ns = make([]dnsRR, 0, dh.Nscount) 845 dns.extra = make([]dnsRR, 0, dh.Arcount) 846 847 var rec dnsRR 848 849 for i := 0; i < len(dns.question); i++ { 850 off, ok = unpackStruct(&dns.question[i], msg, off) 851 } 852 for i := 0; i < int(dh.Ancount); i++ { 853 rec, off, ok = unpackRR(msg, off) 854 if !ok { 855 return false 856 } 857 dns.answer = append(dns.answer, rec) 858 } 859 for i := 0; i < int(dh.Nscount); i++ { 860 rec, off, ok = unpackRR(msg, off) 861 if !ok { 862 return false 863 } 864 dns.ns = append(dns.ns, rec) 865 } 866 for i := 0; i < int(dh.Arcount); i++ { 867 rec, off, ok = unpackRR(msg, off) 868 if !ok { 869 return false 870 } 871 dns.extra = append(dns.extra, rec) 872 } 873 // if off != len(msg) { 874 // println("extra bytes in dns packet", off, "<", len(msg)); 875 // } 876 return true 877 } 878 879 func (dns *dnsMsg) String() string { 880 s := "DNS: " + printStruct(&dns.dnsMsgHdr) + "\n" 881 if len(dns.question) > 0 { 882 s += "-- Questions\n" 883 for i := 0; i < len(dns.question); i++ { 884 s += printStruct(&dns.question[i]) + "\n" 885 } 886 } 887 if len(dns.answer) > 0 { 888 s += "-- Answers\n" 889 for i := 0; i < len(dns.answer); i++ { 890 s += printStruct(dns.answer[i]) + "\n" 891 } 892 } 893 if len(dns.ns) > 0 { 894 s += "-- Name servers\n" 895 for i := 0; i < len(dns.ns); i++ { 896 s += printStruct(dns.ns[i]) + "\n" 897 } 898 } 899 if len(dns.extra) > 0 { 900 s += "-- Extra\n" 901 for i := 0; i < len(dns.extra); i++ { 902 s += printStruct(dns.extra[i]) + "\n" 903 } 904 } 905 return s 906 }