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 23package net 24 25// Packet formats 26 27// Wire constants. 28const ( 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. 73type 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. 86type dnsHeader struct { 87 Id uint16 88 Bits uint16 89 Qdcount, Ancount, Nscount, Arcount uint16 90} 91 92func (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 101const ( 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. 111type dnsQuestion struct { 112 Name string `net:"domain-name"` // `net:"domain-name"` specifies encoding; see packers below 113 Qtype uint16 114 Qclass uint16 115} 116 117func (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. 126type 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 134func (h *dnsRR_Header) Header() *dnsRR_Header { 135 return h 136} 137 138func (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 146type dnsRR interface { 147 dnsStruct 148 Header() *dnsRR_Header 149} 150 151// Specific DNS RR formats for each query type. 152 153type dnsRR_CNAME struct { 154 Hdr dnsRR_Header 155 Cname string `net:"domain-name"` 156} 157 158func (rr *dnsRR_CNAME) Header() *dnsRR_Header { 159 return &rr.Hdr 160} 161 162func (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 166type dnsRR_HINFO struct { 167 Hdr dnsRR_Header 168 Cpu string 169 Os string 170} 171 172func (rr *dnsRR_HINFO) Header() *dnsRR_Header { 173 return &rr.Hdr 174} 175 176func (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 180type dnsRR_MB struct { 181 Hdr dnsRR_Header 182 Mb string `net:"domain-name"` 183} 184 185func (rr *dnsRR_MB) Header() *dnsRR_Header { 186 return &rr.Hdr 187} 188 189func (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 193type dnsRR_MG struct { 194 Hdr dnsRR_Header 195 Mg string `net:"domain-name"` 196} 197 198func (rr *dnsRR_MG) Header() *dnsRR_Header { 199 return &rr.Hdr 200} 201 202func (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 206type dnsRR_MINFO struct { 207 Hdr dnsRR_Header 208 Rmail string `net:"domain-name"` 209 Email string `net:"domain-name"` 210} 211 212func (rr *dnsRR_MINFO) Header() *dnsRR_Header { 213 return &rr.Hdr 214} 215 216func (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 220type dnsRR_MR struct { 221 Hdr dnsRR_Header 222 Mr string `net:"domain-name"` 223} 224 225func (rr *dnsRR_MR) Header() *dnsRR_Header { 226 return &rr.Hdr 227} 228 229func (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 233type dnsRR_MX struct { 234 Hdr dnsRR_Header 235 Pref uint16 236 Mx string `net:"domain-name"` 237} 238 239func (rr *dnsRR_MX) Header() *dnsRR_Header { 240 return &rr.Hdr 241} 242 243func (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 247type dnsRR_NS struct { 248 Hdr dnsRR_Header 249 Ns string `net:"domain-name"` 250} 251 252func (rr *dnsRR_NS) Header() *dnsRR_Header { 253 return &rr.Hdr 254} 255 256func (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 260type dnsRR_PTR struct { 261 Hdr dnsRR_Header 262 Ptr string `net:"domain-name"` 263} 264 265func (rr *dnsRR_PTR) Header() *dnsRR_Header { 266 return &rr.Hdr 267} 268 269func (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 273type 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 284func (rr *dnsRR_SOA) Header() *dnsRR_Header { 285 return &rr.Hdr 286} 287 288func (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 299type dnsRR_TXT struct { 300 Hdr dnsRR_Header 301 Txt string // not domain name 302} 303 304func (rr *dnsRR_TXT) Header() *dnsRR_Header { 305 return &rr.Hdr 306} 307 308func (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 328type dnsRR_SRV struct { 329 Hdr dnsRR_Header 330 Priority uint16 331 Weight uint16 332 Port uint16 333 Target string `net:"domain-name"` 334} 335 336func (rr *dnsRR_SRV) Header() *dnsRR_Header { 337 return &rr.Hdr 338} 339 340func (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 348type dnsRR_A struct { 349 Hdr dnsRR_Header 350 A uint32 `net:"ipv4"` 351} 352 353func (rr *dnsRR_A) Header() *dnsRR_Header { 354 return &rr.Hdr 355} 356 357func (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 361type dnsRR_AAAA struct { 362 Hdr dnsRR_Header 363 AAAA [16]byte `net:"ipv6"` 364} 365 366func (rr *dnsRR_AAAA) Header() *dnsRR_Header { 367 return &rr.Hdr 368} 369 370func (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. 383var 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. 403func 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. 452func unpackDomainName(msg []byte, off int) (s string, off1 int, ok bool) { 453 s = "" 454 ptr := 0 // number of pointers followed 455Loop: 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. 505func 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. 564func 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. 626func 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. 686func 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. 708func 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. 735type 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 746func (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 757type dnsMsg struct { 758 dnsMsgHdr 759 question []dnsQuestion 760 answer []dnsRR 761 ns []dnsRR 762 extra []dnsRR 763} 764 765func (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 824func (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 879func (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} 907