github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/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 return rr.Hdr.Walk(f) && f(&rr.Txt, "Txt", "") 310 } 311 312 type dnsRR_SRV struct { 313 Hdr dnsRR_Header 314 Priority uint16 315 Weight uint16 316 Port uint16 317 Target string `net:"domain-name"` 318 } 319 320 func (rr *dnsRR_SRV) Header() *dnsRR_Header { 321 return &rr.Hdr 322 } 323 324 func (rr *dnsRR_SRV) Walk(f func(v interface{}, name, tag string) bool) bool { 325 return rr.Hdr.Walk(f) && 326 f(&rr.Priority, "Priority", "") && 327 f(&rr.Weight, "Weight", "") && 328 f(&rr.Port, "Port", "") && 329 f(&rr.Target, "Target", "domain") 330 } 331 332 type dnsRR_A struct { 333 Hdr dnsRR_Header 334 A uint32 `net:"ipv4"` 335 } 336 337 func (rr *dnsRR_A) Header() *dnsRR_Header { 338 return &rr.Hdr 339 } 340 341 func (rr *dnsRR_A) Walk(f func(v interface{}, name, tag string) bool) bool { 342 return rr.Hdr.Walk(f) && f(&rr.A, "A", "ipv4") 343 } 344 345 type dnsRR_AAAA struct { 346 Hdr dnsRR_Header 347 AAAA [16]byte `net:"ipv6"` 348 } 349 350 func (rr *dnsRR_AAAA) Header() *dnsRR_Header { 351 return &rr.Hdr 352 } 353 354 func (rr *dnsRR_AAAA) Walk(f func(v interface{}, name, tag string) bool) bool { 355 return rr.Hdr.Walk(f) && f(rr.AAAA[:], "AAAA", "ipv6") 356 } 357 358 // Packing and unpacking. 359 // 360 // All the packers and unpackers take a (msg []byte, off int) 361 // and return (off1 int, ok bool). If they return ok==false, they 362 // also return off1==len(msg), so that the next unpacker will 363 // also fail. This lets us avoid checks of ok until the end of a 364 // packing sequence. 365 366 // Map of constructors for each RR wire type. 367 var rr_mk = map[int]func() dnsRR{ 368 dnsTypeCNAME: func() dnsRR { return new(dnsRR_CNAME) }, 369 dnsTypeHINFO: func() dnsRR { return new(dnsRR_HINFO) }, 370 dnsTypeMB: func() dnsRR { return new(dnsRR_MB) }, 371 dnsTypeMG: func() dnsRR { return new(dnsRR_MG) }, 372 dnsTypeMINFO: func() dnsRR { return new(dnsRR_MINFO) }, 373 dnsTypeMR: func() dnsRR { return new(dnsRR_MR) }, 374 dnsTypeMX: func() dnsRR { return new(dnsRR_MX) }, 375 dnsTypeNS: func() dnsRR { return new(dnsRR_NS) }, 376 dnsTypePTR: func() dnsRR { return new(dnsRR_PTR) }, 377 dnsTypeSOA: func() dnsRR { return new(dnsRR_SOA) }, 378 dnsTypeTXT: func() dnsRR { return new(dnsRR_TXT) }, 379 dnsTypeSRV: func() dnsRR { return new(dnsRR_SRV) }, 380 dnsTypeA: func() dnsRR { return new(dnsRR_A) }, 381 dnsTypeAAAA: func() dnsRR { return new(dnsRR_AAAA) }, 382 } 383 384 // Pack a domain name s into msg[off:]. 385 // Domain names are a sequence of counted strings 386 // split at the dots. They end with a zero-length string. 387 func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) { 388 // Add trailing dot to canonicalize name. 389 if n := len(s); n == 0 || s[n-1] != '.' { 390 s += "." 391 } 392 393 // Each dot ends a segment of the name. 394 // We trade each dot byte for a length byte. 395 // There is also a trailing zero. 396 // Check that we have all the space we need. 397 tot := len(s) + 1 398 if off+tot > len(msg) { 399 return len(msg), false 400 } 401 402 // Emit sequence of counted strings, chopping at dots. 403 begin := 0 404 for i := 0; i < len(s); i++ { 405 if s[i] == '.' { 406 if i-begin >= 1<<6 { // top two bits of length must be clear 407 return len(msg), false 408 } 409 msg[off] = byte(i - begin) 410 off++ 411 for j := begin; j < i; j++ { 412 msg[off] = s[j] 413 off++ 414 } 415 begin = i + 1 416 } 417 } 418 msg[off] = 0 419 off++ 420 return off, true 421 } 422 423 // Unpack a domain name. 424 // In addition to the simple sequences of counted strings above, 425 // domain names are allowed to refer to strings elsewhere in the 426 // packet, to avoid repeating common suffixes when returning 427 // many entries in a single domain. The pointers are marked 428 // by a length byte with the top two bits set. Ignoring those 429 // two bits, that byte and the next give a 14 bit offset from msg[0] 430 // where we should pick up the trail. 431 // Note that if we jump elsewhere in the packet, 432 // we return off1 == the offset after the first pointer we found, 433 // which is where the next record will start. 434 // In theory, the pointers are only allowed to jump backward. 435 // We let them jump anywhere and stop jumping after a while. 436 func unpackDomainName(msg []byte, off int) (s string, off1 int, ok bool) { 437 s = "" 438 ptr := 0 // number of pointers followed 439 Loop: 440 for { 441 if off >= len(msg) { 442 return "", len(msg), false 443 } 444 c := int(msg[off]) 445 off++ 446 switch c & 0xC0 { 447 case 0x00: 448 if c == 0x00 { 449 // end of name 450 break Loop 451 } 452 // literal string 453 if off+c > len(msg) { 454 return "", len(msg), false 455 } 456 s += string(msg[off:off+c]) + "." 457 off += c 458 case 0xC0: 459 // pointer to somewhere else in msg. 460 // remember location after first ptr, 461 // since that's how many bytes we consumed. 462 // also, don't follow too many pointers -- 463 // maybe there's a loop. 464 if off >= len(msg) { 465 return "", len(msg), false 466 } 467 c1 := msg[off] 468 off++ 469 if ptr == 0 { 470 off1 = off 471 } 472 if ptr++; ptr > 10 { 473 return "", len(msg), false 474 } 475 off = (c^0xC0)<<8 | int(c1) 476 default: 477 // 0x80 and 0x40 are reserved 478 return "", len(msg), false 479 } 480 } 481 if ptr == 0 { 482 off1 = off 483 } 484 return s, off1, true 485 } 486 487 // packStruct packs a structure into msg at specified offset off, and 488 // returns off1 such that msg[off:off1] is the encoded data. 489 func packStruct(any dnsStruct, msg []byte, off int) (off1 int, ok bool) { 490 ok = any.Walk(func(field interface{}, name, tag string) bool { 491 switch fv := field.(type) { 492 default: 493 println("net: dns: unknown packing type") 494 return false 495 case *uint16: 496 i := *fv 497 if off+2 > len(msg) { 498 return false 499 } 500 msg[off] = byte(i >> 8) 501 msg[off+1] = byte(i) 502 off += 2 503 case *uint32: 504 i := *fv 505 msg[off] = byte(i >> 24) 506 msg[off+1] = byte(i >> 16) 507 msg[off+2] = byte(i >> 8) 508 msg[off+3] = byte(i) 509 off += 4 510 case []byte: 511 n := len(fv) 512 if off+n > len(msg) { 513 return false 514 } 515 copy(msg[off:off+n], fv) 516 off += n 517 case *string: 518 s := *fv 519 switch tag { 520 default: 521 println("net: dns: unknown string tag", tag) 522 return false 523 case "domain": 524 off, ok = packDomainName(s, msg, off) 525 if !ok { 526 return false 527 } 528 case "": 529 // Counted string: 1 byte length. 530 if len(s) > 255 || off+1+len(s) > len(msg) { 531 return false 532 } 533 msg[off] = byte(len(s)) 534 off++ 535 off += copy(msg[off:], s) 536 } 537 } 538 return true 539 }) 540 if !ok { 541 return len(msg), false 542 } 543 return off, true 544 } 545 546 // unpackStruct decodes msg[off:] into the given structure, and 547 // returns off1 such that msg[off:off1] is the encoded data. 548 func unpackStruct(any dnsStruct, msg []byte, off int) (off1 int, ok bool) { 549 ok = any.Walk(func(field interface{}, name, tag string) bool { 550 switch fv := field.(type) { 551 default: 552 println("net: dns: unknown packing type") 553 return false 554 case *uint16: 555 if off+2 > len(msg) { 556 return false 557 } 558 *fv = uint16(msg[off])<<8 | uint16(msg[off+1]) 559 off += 2 560 case *uint32: 561 if off+4 > len(msg) { 562 return false 563 } 564 *fv = uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | 565 uint32(msg[off+2])<<8 | uint32(msg[off+3]) 566 off += 4 567 case []byte: 568 n := len(fv) 569 if off+n > len(msg) { 570 return false 571 } 572 copy(fv, msg[off:off+n]) 573 off += n 574 case *string: 575 var s string 576 switch tag { 577 default: 578 println("net: dns: unknown string tag", tag) 579 return false 580 case "domain": 581 s, off, ok = unpackDomainName(msg, off) 582 if !ok { 583 return false 584 } 585 case "": 586 if off >= len(msg) || off+1+int(msg[off]) > len(msg) { 587 return false 588 } 589 n := int(msg[off]) 590 off++ 591 b := make([]byte, n) 592 for i := 0; i < n; i++ { 593 b[i] = msg[off+i] 594 } 595 off += n 596 s = string(b) 597 } 598 *fv = s 599 } 600 return true 601 }) 602 if !ok { 603 return len(msg), false 604 } 605 return off, true 606 } 607 608 // Generic struct printer. Prints fields with tag "ipv4" or "ipv6" 609 // as IP addresses. 610 func printStruct(any dnsStruct) string { 611 s := "{" 612 i := 0 613 any.Walk(func(val interface{}, name, tag string) bool { 614 i++ 615 if i > 1 { 616 s += ", " 617 } 618 s += name + "=" 619 switch tag { 620 case "ipv4": 621 i := *val.(*uint32) 622 s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String() 623 case "ipv6": 624 i := val.([]byte) 625 s += IP(i).String() 626 default: 627 var i int64 628 switch v := val.(type) { 629 default: 630 // can't really happen. 631 s += "<unknown type>" 632 return true 633 case *string: 634 s += *v 635 return true 636 case []byte: 637 s += string(v) 638 return true 639 case *bool: 640 if *v { 641 s += "true" 642 } else { 643 s += "false" 644 } 645 return true 646 case *int: 647 i = int64(*v) 648 case *uint: 649 i = int64(*v) 650 case *uint8: 651 i = int64(*v) 652 case *uint16: 653 i = int64(*v) 654 case *uint32: 655 i = int64(*v) 656 case *uint64: 657 i = int64(*v) 658 case *uintptr: 659 i = int64(*v) 660 } 661 s += itoa(int(i)) 662 } 663 return true 664 }) 665 s += "}" 666 return s 667 } 668 669 // Resource record packer. 670 func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) { 671 var off1 int 672 // pack twice, once to find end of header 673 // and again to find end of packet. 674 // a bit inefficient but this doesn't need to be fast. 675 // off1 is end of header 676 // off2 is end of rr 677 off1, ok = packStruct(rr.Header(), msg, off) 678 off2, ok = packStruct(rr, msg, off) 679 if !ok { 680 return len(msg), false 681 } 682 // pack a third time; redo header with correct data length 683 rr.Header().Rdlength = uint16(off2 - off1) 684 packStruct(rr.Header(), msg, off) 685 return off2, true 686 } 687 688 // Resource record unpacker. 689 func unpackRR(msg []byte, off int) (rr dnsRR, off1 int, ok bool) { 690 // unpack just the header, to find the rr type and length 691 var h dnsRR_Header 692 off0 := off 693 if off, ok = unpackStruct(&h, msg, off); !ok { 694 return nil, len(msg), false 695 } 696 end := off + int(h.Rdlength) 697 698 // make an rr of that type and re-unpack. 699 // again inefficient but doesn't need to be fast. 700 mk, known := rr_mk[int(h.Rrtype)] 701 if !known { 702 return &h, end, true 703 } 704 rr = mk() 705 off, ok = unpackStruct(rr, msg, off0) 706 if off != end { 707 return &h, end, true 708 } 709 return rr, off, ok 710 } 711 712 // Usable representation of a DNS packet. 713 714 // A manually-unpacked version of (id, bits). 715 // This is in its own struct for easy printing. 716 type dnsMsgHdr struct { 717 id uint16 718 response bool 719 opcode int 720 authoritative bool 721 truncated bool 722 recursion_desired bool 723 recursion_available bool 724 rcode int 725 } 726 727 func (h *dnsMsgHdr) Walk(f func(v interface{}, name, tag string) bool) bool { 728 return f(&h.id, "id", "") && 729 f(&h.response, "response", "") && 730 f(&h.opcode, "opcode", "") && 731 f(&h.authoritative, "authoritative", "") && 732 f(&h.truncated, "truncated", "") && 733 f(&h.recursion_desired, "recursion_desired", "") && 734 f(&h.recursion_available, "recursion_available", "") && 735 f(&h.rcode, "rcode", "") 736 } 737 738 type dnsMsg struct { 739 dnsMsgHdr 740 question []dnsQuestion 741 answer []dnsRR 742 ns []dnsRR 743 extra []dnsRR 744 } 745 746 func (dns *dnsMsg) Pack() (msg []byte, ok bool) { 747 var dh dnsHeader 748 749 // Convert convenient dnsMsg into wire-like dnsHeader. 750 dh.Id = dns.id 751 dh.Bits = uint16(dns.opcode)<<11 | uint16(dns.rcode) 752 if dns.recursion_available { 753 dh.Bits |= _RA 754 } 755 if dns.recursion_desired { 756 dh.Bits |= _RD 757 } 758 if dns.truncated { 759 dh.Bits |= _TC 760 } 761 if dns.authoritative { 762 dh.Bits |= _AA 763 } 764 if dns.response { 765 dh.Bits |= _QR 766 } 767 768 // Prepare variable sized arrays. 769 question := dns.question 770 answer := dns.answer 771 ns := dns.ns 772 extra := dns.extra 773 774 dh.Qdcount = uint16(len(question)) 775 dh.Ancount = uint16(len(answer)) 776 dh.Nscount = uint16(len(ns)) 777 dh.Arcount = uint16(len(extra)) 778 779 // Could work harder to calculate message size, 780 // but this is far more than we need and not 781 // big enough to hurt the allocator. 782 msg = make([]byte, 2000) 783 784 // Pack it in: header and then the pieces. 785 off := 0 786 off, ok = packStruct(&dh, msg, off) 787 for i := 0; i < len(question); i++ { 788 off, ok = packStruct(&question[i], msg, off) 789 } 790 for i := 0; i < len(answer); i++ { 791 off, ok = packRR(answer[i], msg, off) 792 } 793 for i := 0; i < len(ns); i++ { 794 off, ok = packRR(ns[i], msg, off) 795 } 796 for i := 0; i < len(extra); i++ { 797 off, ok = packRR(extra[i], msg, off) 798 } 799 if !ok { 800 return nil, false 801 } 802 return msg[0:off], true 803 } 804 805 func (dns *dnsMsg) Unpack(msg []byte) bool { 806 // Header. 807 var dh dnsHeader 808 off := 0 809 var ok bool 810 if off, ok = unpackStruct(&dh, msg, off); !ok { 811 return false 812 } 813 dns.id = dh.Id 814 dns.response = (dh.Bits & _QR) != 0 815 dns.opcode = int(dh.Bits>>11) & 0xF 816 dns.authoritative = (dh.Bits & _AA) != 0 817 dns.truncated = (dh.Bits & _TC) != 0 818 dns.recursion_desired = (dh.Bits & _RD) != 0 819 dns.recursion_available = (dh.Bits & _RA) != 0 820 dns.rcode = int(dh.Bits & 0xF) 821 822 // Arrays. 823 dns.question = make([]dnsQuestion, dh.Qdcount) 824 dns.answer = make([]dnsRR, 0, dh.Ancount) 825 dns.ns = make([]dnsRR, 0, dh.Nscount) 826 dns.extra = make([]dnsRR, 0, dh.Arcount) 827 828 var rec dnsRR 829 830 for i := 0; i < len(dns.question); i++ { 831 off, ok = unpackStruct(&dns.question[i], msg, off) 832 } 833 for i := 0; i < int(dh.Ancount); i++ { 834 rec, off, ok = unpackRR(msg, off) 835 if !ok { 836 return false 837 } 838 dns.answer = append(dns.answer, rec) 839 } 840 for i := 0; i < int(dh.Nscount); i++ { 841 rec, off, ok = unpackRR(msg, off) 842 if !ok { 843 return false 844 } 845 dns.ns = append(dns.ns, rec) 846 } 847 for i := 0; i < int(dh.Arcount); i++ { 848 rec, off, ok = unpackRR(msg, off) 849 if !ok { 850 return false 851 } 852 dns.extra = append(dns.extra, rec) 853 } 854 // if off != len(msg) { 855 // println("extra bytes in dns packet", off, "<", len(msg)); 856 // } 857 return true 858 } 859 860 func (dns *dnsMsg) String() string { 861 s := "DNS: " + printStruct(&dns.dnsMsgHdr) + "\n" 862 if len(dns.question) > 0 { 863 s += "-- Questions\n" 864 for i := 0; i < len(dns.question); i++ { 865 s += printStruct(&dns.question[i]) + "\n" 866 } 867 } 868 if len(dns.answer) > 0 { 869 s += "-- Answers\n" 870 for i := 0; i < len(dns.answer); i++ { 871 s += printStruct(dns.answer[i]) + "\n" 872 } 873 } 874 if len(dns.ns) > 0 { 875 s += "-- Name servers\n" 876 for i := 0; i < len(dns.ns); i++ { 877 s += printStruct(dns.ns[i]) + "\n" 878 } 879 } 880 if len(dns.extra) > 0 { 881 s += "-- Extra\n" 882 for i := 0; i < len(dns.extra); i++ { 883 s += printStruct(dns.extra[i]) + "\n" 884 } 885 } 886 return s 887 }