1package dns 2 3import ( 4 "encoding/binary" 5 "encoding/hex" 6 "errors" 7 "fmt" 8 "net" 9 "strconv" 10) 11 12// EDNS0 Option codes. 13const ( 14 EDNS0LLQ = 0x1 // long lived queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01 15 EDNS0UL = 0x2 // update lease draft: http://files.dns-sd.org/draft-sekar-dns-ul.txt 16 EDNS0NSID = 0x3 // nsid (See RFC 5001) 17 EDNS0DAU = 0x5 // DNSSEC Algorithm Understood 18 EDNS0DHU = 0x6 // DS Hash Understood 19 EDNS0N3U = 0x7 // NSEC3 Hash Understood 20 EDNS0SUBNET = 0x8 // client-subnet (See RFC 7871) 21 EDNS0EXPIRE = 0x9 // EDNS0 expire 22 EDNS0COOKIE = 0xa // EDNS0 Cookie 23 EDNS0TCPKEEPALIVE = 0xb // EDNS0 tcp keep alive (See RFC 7828) 24 EDNS0PADDING = 0xc // EDNS0 padding (See RFC 7830) 25 EDNS0EDE = 0xf // EDNS0 extended DNS errors (See RFC 8914) 26 EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (See RFC 6891) 27 EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (See RFC 6891) 28 _DO = 1 << 15 // DNSSEC OK 29) 30 31// OPT is the EDNS0 RR appended to messages to convey extra (meta) information. 32// See RFC 6891. 33type OPT struct { 34 Hdr RR_Header 35 Option []EDNS0 `dns:"opt"` 36} 37 38func (rr *OPT) String() string { 39 s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; " 40 if rr.Do() { 41 s += "flags: do; " 42 } else { 43 s += "flags: ; " 44 } 45 s += "udp: " + strconv.Itoa(int(rr.UDPSize())) 46 47 for _, o := range rr.Option { 48 switch o.(type) { 49 case *EDNS0_NSID: 50 s += "\n; NSID: " + o.String() 51 h, e := o.pack() 52 var r string 53 if e == nil { 54 for _, c := range h { 55 r += "(" + string(c) + ")" 56 } 57 s += " " + r 58 } 59 case *EDNS0_SUBNET: 60 s += "\n; SUBNET: " + o.String() 61 case *EDNS0_COOKIE: 62 s += "\n; COOKIE: " + o.String() 63 case *EDNS0_UL: 64 s += "\n; UPDATE LEASE: " + o.String() 65 case *EDNS0_LLQ: 66 s += "\n; LONG LIVED QUERIES: " + o.String() 67 case *EDNS0_DAU: 68 s += "\n; DNSSEC ALGORITHM UNDERSTOOD: " + o.String() 69 case *EDNS0_DHU: 70 s += "\n; DS HASH UNDERSTOOD: " + o.String() 71 case *EDNS0_N3U: 72 s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String() 73 case *EDNS0_LOCAL: 74 s += "\n; LOCAL OPT: " + o.String() 75 case *EDNS0_PADDING: 76 s += "\n; PADDING: " + o.String() 77 case *EDNS0_EDE: 78 s += "\n; EDE: " + o.String() 79 } 80 } 81 return s 82} 83 84func (rr *OPT) len(off int, compression map[string]struct{}) int { 85 l := rr.Hdr.len(off, compression) 86 for _, o := range rr.Option { 87 l += 4 // Account for 2-byte option code and 2-byte option length. 88 lo, _ := o.pack() 89 l += len(lo) 90 } 91 return l 92} 93 94func (*OPT) parse(c *zlexer, origin string) *ParseError { 95 return &ParseError{err: "OPT records do not have a presentation format"} 96} 97 98func (r1 *OPT) isDuplicate(r2 RR) bool { return false } 99 100// return the old value -> delete SetVersion? 101 102// Version returns the EDNS version used. Only zero is defined. 103func (rr *OPT) Version() uint8 { 104 return uint8(rr.Hdr.Ttl & 0x00FF0000 >> 16) 105} 106 107// SetVersion sets the version of EDNS. This is usually zero. 108func (rr *OPT) SetVersion(v uint8) { 109 rr.Hdr.Ttl = rr.Hdr.Ttl&0xFF00FFFF | uint32(v)<<16 110} 111 112// ExtendedRcode returns the EDNS extended RCODE field (the upper 8 bits of the TTL). 113func (rr *OPT) ExtendedRcode() int { 114 return int(rr.Hdr.Ttl&0xFF000000>>24) << 4 115} 116 117// SetExtendedRcode sets the EDNS extended RCODE field. 118// 119// If the RCODE is not an extended RCODE, will reset the extended RCODE field to 0. 120func (rr *OPT) SetExtendedRcode(v uint16) { 121 rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | uint32(v>>4)<<24 122} 123 124// UDPSize returns the UDP buffer size. 125func (rr *OPT) UDPSize() uint16 { 126 return rr.Hdr.Class 127} 128 129// SetUDPSize sets the UDP buffer size. 130func (rr *OPT) SetUDPSize(size uint16) { 131 rr.Hdr.Class = size 132} 133 134// Do returns the value of the DO (DNSSEC OK) bit. 135func (rr *OPT) Do() bool { 136 return rr.Hdr.Ttl&_DO == _DO 137} 138 139// SetDo sets the DO (DNSSEC OK) bit. 140// If we pass an argument, set the DO bit to that value. 141// It is possible to pass 2 or more arguments. Any arguments after the 1st is silently ignored. 142func (rr *OPT) SetDo(do ...bool) { 143 if len(do) == 1 { 144 if do[0] { 145 rr.Hdr.Ttl |= _DO 146 } else { 147 rr.Hdr.Ttl &^= _DO 148 } 149 } else { 150 rr.Hdr.Ttl |= _DO 151 } 152} 153 154// Z returns the Z part of the OPT RR as a uint16 with only the 15 least significant bits used. 155func (rr *OPT) Z() uint16 { 156 return uint16(rr.Hdr.Ttl & 0x7FFF) 157} 158 159// SetZ sets the Z part of the OPT RR, note only the 15 least significant bits of z are used. 160func (rr *OPT) SetZ(z uint16) { 161 rr.Hdr.Ttl = rr.Hdr.Ttl&^0x7FFF | uint32(z&0x7FFF) 162} 163 164// EDNS0 defines an EDNS0 Option. An OPT RR can have multiple options appended to it. 165type EDNS0 interface { 166 // Option returns the option code for the option. 167 Option() uint16 168 // pack returns the bytes of the option data. 169 pack() ([]byte, error) 170 // unpack sets the data as found in the buffer. Is also sets 171 // the length of the slice as the length of the option data. 172 unpack([]byte) error 173 // String returns the string representation of the option. 174 String() string 175 // copy returns a deep-copy of the option. 176 copy() EDNS0 177} 178 179// EDNS0_NSID option is used to retrieve a nameserver 180// identifier. When sending a request Nsid must be set to the empty string 181// The identifier is an opaque string encoded as hex. 182// Basic use pattern for creating an nsid option: 183// 184// o := new(dns.OPT) 185// o.Hdr.Name = "." 186// o.Hdr.Rrtype = dns.TypeOPT 187// e := new(dns.EDNS0_NSID) 188// e.Code = dns.EDNS0NSID 189// e.Nsid = "AA" 190// o.Option = append(o.Option, e) 191type EDNS0_NSID struct { 192 Code uint16 // Always EDNS0NSID 193 Nsid string // This string needs to be hex encoded 194} 195 196func (e *EDNS0_NSID) pack() ([]byte, error) { 197 h, err := hex.DecodeString(e.Nsid) 198 if err != nil { 199 return nil, err 200 } 201 return h, nil 202} 203 204// Option implements the EDNS0 interface. 205func (e *EDNS0_NSID) Option() uint16 { return EDNS0NSID } // Option returns the option code. 206func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil } 207func (e *EDNS0_NSID) String() string { return e.Nsid } 208func (e *EDNS0_NSID) copy() EDNS0 { return &EDNS0_NSID{e.Code, e.Nsid} } 209 210// EDNS0_SUBNET is the subnet option that is used to give the remote nameserver 211// an idea of where the client lives. See RFC 7871. It can then give back a different 212// answer depending on the location or network topology. 213// Basic use pattern for creating an subnet option: 214// 215// o := new(dns.OPT) 216// o.Hdr.Name = "." 217// o.Hdr.Rrtype = dns.TypeOPT 218// e := new(dns.EDNS0_SUBNET) 219// e.Code = dns.EDNS0SUBNET 220// e.Family = 1 // 1 for IPv4 source address, 2 for IPv6 221// e.SourceNetmask = 32 // 32 for IPV4, 128 for IPv6 222// e.SourceScope = 0 223// e.Address = net.ParseIP("127.0.0.1").To4() // for IPv4 224// // e.Address = net.ParseIP("2001:7b8:32a::2") // for IPV6 225// o.Option = append(o.Option, e) 226// 227// This code will parse all the available bits when unpacking (up to optlen). 228// When packing it will apply SourceNetmask. If you need more advanced logic, 229// patches welcome and good luck. 230type EDNS0_SUBNET struct { 231 Code uint16 // Always EDNS0SUBNET 232 Family uint16 // 1 for IP, 2 for IP6 233 SourceNetmask uint8 234 SourceScope uint8 235 Address net.IP 236} 237 238// Option implements the EDNS0 interface. 239func (e *EDNS0_SUBNET) Option() uint16 { return EDNS0SUBNET } 240 241func (e *EDNS0_SUBNET) pack() ([]byte, error) { 242 b := make([]byte, 4) 243 binary.BigEndian.PutUint16(b[0:], e.Family) 244 b[2] = e.SourceNetmask 245 b[3] = e.SourceScope 246 switch e.Family { 247 case 0: 248 // "dig" sets AddressFamily to 0 if SourceNetmask is also 0 249 // We might don't need to complain either 250 if e.SourceNetmask != 0 { 251 return nil, errors.New("dns: bad address family") 252 } 253 case 1: 254 if e.SourceNetmask > net.IPv4len*8 { 255 return nil, errors.New("dns: bad netmask") 256 } 257 if len(e.Address.To4()) != net.IPv4len { 258 return nil, errors.New("dns: bad address") 259 } 260 ip := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8)) 261 needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up 262 b = append(b, ip[:needLength]...) 263 case 2: 264 if e.SourceNetmask > net.IPv6len*8 { 265 return nil, errors.New("dns: bad netmask") 266 } 267 if len(e.Address) != net.IPv6len { 268 return nil, errors.New("dns: bad address") 269 } 270 ip := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8)) 271 needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up 272 b = append(b, ip[:needLength]...) 273 default: 274 return nil, errors.New("dns: bad address family") 275 } 276 return b, nil 277} 278 279func (e *EDNS0_SUBNET) unpack(b []byte) error { 280 if len(b) < 4 { 281 return ErrBuf 282 } 283 e.Family = binary.BigEndian.Uint16(b) 284 e.SourceNetmask = b[2] 285 e.SourceScope = b[3] 286 switch e.Family { 287 case 0: 288 // "dig" sets AddressFamily to 0 if SourceNetmask is also 0 289 // It's okay to accept such a packet 290 if e.SourceNetmask != 0 { 291 return errors.New("dns: bad address family") 292 } 293 e.Address = net.IPv4(0, 0, 0, 0) 294 case 1: 295 if e.SourceNetmask > net.IPv4len*8 || e.SourceScope > net.IPv4len*8 { 296 return errors.New("dns: bad netmask") 297 } 298 addr := make(net.IP, net.IPv4len) 299 copy(addr, b[4:]) 300 e.Address = addr.To16() 301 case 2: 302 if e.SourceNetmask > net.IPv6len*8 || e.SourceScope > net.IPv6len*8 { 303 return errors.New("dns: bad netmask") 304 } 305 addr := make(net.IP, net.IPv6len) 306 copy(addr, b[4:]) 307 e.Address = addr 308 default: 309 return errors.New("dns: bad address family") 310 } 311 return nil 312} 313 314func (e *EDNS0_SUBNET) String() (s string) { 315 if e.Address == nil { 316 s = "<nil>" 317 } else if e.Address.To4() != nil { 318 s = e.Address.String() 319 } else { 320 s = "[" + e.Address.String() + "]" 321 } 322 s += "/" + strconv.Itoa(int(e.SourceNetmask)) + "/" + strconv.Itoa(int(e.SourceScope)) 323 return 324} 325 326func (e *EDNS0_SUBNET) copy() EDNS0 { 327 return &EDNS0_SUBNET{ 328 e.Code, 329 e.Family, 330 e.SourceNetmask, 331 e.SourceScope, 332 e.Address, 333 } 334} 335 336// The EDNS0_COOKIE option is used to add a DNS Cookie to a message. 337// 338// o := new(dns.OPT) 339// o.Hdr.Name = "." 340// o.Hdr.Rrtype = dns.TypeOPT 341// e := new(dns.EDNS0_COOKIE) 342// e.Code = dns.EDNS0COOKIE 343// e.Cookie = "24a5ac.." 344// o.Option = append(o.Option, e) 345// 346// The Cookie field consists out of a client cookie (RFC 7873 Section 4), that is 347// always 8 bytes. It may then optionally be followed by the server cookie. The server 348// cookie is of variable length, 8 to a maximum of 32 bytes. In other words: 349// 350// cCookie := o.Cookie[:16] 351// sCookie := o.Cookie[16:] 352// 353// There is no guarantee that the Cookie string has a specific length. 354type EDNS0_COOKIE struct { 355 Code uint16 // Always EDNS0COOKIE 356 Cookie string // Hex-encoded cookie data 357} 358 359func (e *EDNS0_COOKIE) pack() ([]byte, error) { 360 h, err := hex.DecodeString(e.Cookie) 361 if err != nil { 362 return nil, err 363 } 364 return h, nil 365} 366 367// Option implements the EDNS0 interface. 368func (e *EDNS0_COOKIE) Option() uint16 { return EDNS0COOKIE } 369func (e *EDNS0_COOKIE) unpack(b []byte) error { e.Cookie = hex.EncodeToString(b); return nil } 370func (e *EDNS0_COOKIE) String() string { return e.Cookie } 371func (e *EDNS0_COOKIE) copy() EDNS0 { return &EDNS0_COOKIE{e.Code, e.Cookie} } 372 373// The EDNS0_UL (Update Lease) (draft RFC) option is used to tell the server to set 374// an expiration on an update RR. This is helpful for clients that cannot clean 375// up after themselves. This is a draft RFC and more information can be found at 376// https://tools.ietf.org/html/draft-sekar-dns-ul-02 377// 378// o := new(dns.OPT) 379// o.Hdr.Name = "." 380// o.Hdr.Rrtype = dns.TypeOPT 381// e := new(dns.EDNS0_UL) 382// e.Code = dns.EDNS0UL 383// e.Lease = 120 // in seconds 384// o.Option = append(o.Option, e) 385type EDNS0_UL struct { 386 Code uint16 // Always EDNS0UL 387 Lease uint32 388 KeyLease uint32 389} 390 391// Option implements the EDNS0 interface. 392func (e *EDNS0_UL) Option() uint16 { return EDNS0UL } 393func (e *EDNS0_UL) String() string { return fmt.Sprintf("%d %d", e.Lease, e.KeyLease) } 394func (e *EDNS0_UL) copy() EDNS0 { return &EDNS0_UL{e.Code, e.Lease, e.KeyLease} } 395 396// Copied: http://golang.org/src/pkg/net/dnsmsg.go 397func (e *EDNS0_UL) pack() ([]byte, error) { 398 var b []byte 399 if e.KeyLease == 0 { 400 b = make([]byte, 4) 401 } else { 402 b = make([]byte, 8) 403 binary.BigEndian.PutUint32(b[4:], e.KeyLease) 404 } 405 binary.BigEndian.PutUint32(b, e.Lease) 406 return b, nil 407} 408 409func (e *EDNS0_UL) unpack(b []byte) error { 410 switch len(b) { 411 case 4: 412 e.KeyLease = 0 413 case 8: 414 e.KeyLease = binary.BigEndian.Uint32(b[4:]) 415 default: 416 return ErrBuf 417 } 418 e.Lease = binary.BigEndian.Uint32(b) 419 return nil 420} 421 422// EDNS0_LLQ stands for Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01 423// Implemented for completeness, as the EDNS0 type code is assigned. 424type EDNS0_LLQ struct { 425 Code uint16 // Always EDNS0LLQ 426 Version uint16 427 Opcode uint16 428 Error uint16 429 Id uint64 430 LeaseLife uint32 431} 432 433// Option implements the EDNS0 interface. 434func (e *EDNS0_LLQ) Option() uint16 { return EDNS0LLQ } 435 436func (e *EDNS0_LLQ) pack() ([]byte, error) { 437 b := make([]byte, 18) 438 binary.BigEndian.PutUint16(b[0:], e.Version) 439 binary.BigEndian.PutUint16(b[2:], e.Opcode) 440 binary.BigEndian.PutUint16(b[4:], e.Error) 441 binary.BigEndian.PutUint64(b[6:], e.Id) 442 binary.BigEndian.PutUint32(b[14:], e.LeaseLife) 443 return b, nil 444} 445 446func (e *EDNS0_LLQ) unpack(b []byte) error { 447 if len(b) < 18 { 448 return ErrBuf 449 } 450 e.Version = binary.BigEndian.Uint16(b[0:]) 451 e.Opcode = binary.BigEndian.Uint16(b[2:]) 452 e.Error = binary.BigEndian.Uint16(b[4:]) 453 e.Id = binary.BigEndian.Uint64(b[6:]) 454 e.LeaseLife = binary.BigEndian.Uint32(b[14:]) 455 return nil 456} 457 458func (e *EDNS0_LLQ) String() string { 459 s := strconv.FormatUint(uint64(e.Version), 10) + " " + strconv.FormatUint(uint64(e.Opcode), 10) + 460 " " + strconv.FormatUint(uint64(e.Error), 10) + " " + strconv.FormatUint(e.Id, 10) + 461 " " + strconv.FormatUint(uint64(e.LeaseLife), 10) 462 return s 463} 464func (e *EDNS0_LLQ) copy() EDNS0 { 465 return &EDNS0_LLQ{e.Code, e.Version, e.Opcode, e.Error, e.Id, e.LeaseLife} 466} 467 468// EDNS0_DUA implements the EDNS0 "DNSSEC Algorithm Understood" option. See RFC 6975. 469type EDNS0_DAU struct { 470 Code uint16 // Always EDNS0DAU 471 AlgCode []uint8 472} 473 474// Option implements the EDNS0 interface. 475func (e *EDNS0_DAU) Option() uint16 { return EDNS0DAU } 476func (e *EDNS0_DAU) pack() ([]byte, error) { return e.AlgCode, nil } 477func (e *EDNS0_DAU) unpack(b []byte) error { e.AlgCode = b; return nil } 478 479func (e *EDNS0_DAU) String() string { 480 s := "" 481 for _, alg := range e.AlgCode { 482 if a, ok := AlgorithmToString[alg]; ok { 483 s += " " + a 484 } else { 485 s += " " + strconv.Itoa(int(alg)) 486 } 487 } 488 return s 489} 490func (e *EDNS0_DAU) copy() EDNS0 { return &EDNS0_DAU{e.Code, e.AlgCode} } 491 492// EDNS0_DHU implements the EDNS0 "DS Hash Understood" option. See RFC 6975. 493type EDNS0_DHU struct { 494 Code uint16 // Always EDNS0DHU 495 AlgCode []uint8 496} 497 498// Option implements the EDNS0 interface. 499func (e *EDNS0_DHU) Option() uint16 { return EDNS0DHU } 500func (e *EDNS0_DHU) pack() ([]byte, error) { return e.AlgCode, nil } 501func (e *EDNS0_DHU) unpack(b []byte) error { e.AlgCode = b; return nil } 502 503func (e *EDNS0_DHU) String() string { 504 s := "" 505 for _, alg := range e.AlgCode { 506 if a, ok := HashToString[alg]; ok { 507 s += " " + a 508 } else { 509 s += " " + strconv.Itoa(int(alg)) 510 } 511 } 512 return s 513} 514func (e *EDNS0_DHU) copy() EDNS0 { return &EDNS0_DHU{e.Code, e.AlgCode} } 515 516// EDNS0_N3U implements the EDNS0 "NSEC3 Hash Understood" option. See RFC 6975. 517type EDNS0_N3U struct { 518 Code uint16 // Always EDNS0N3U 519 AlgCode []uint8 520} 521 522// Option implements the EDNS0 interface. 523func (e *EDNS0_N3U) Option() uint16 { return EDNS0N3U } 524func (e *EDNS0_N3U) pack() ([]byte, error) { return e.AlgCode, nil } 525func (e *EDNS0_N3U) unpack(b []byte) error { e.AlgCode = b; return nil } 526 527func (e *EDNS0_N3U) String() string { 528 // Re-use the hash map 529 s := "" 530 for _, alg := range e.AlgCode { 531 if a, ok := HashToString[alg]; ok { 532 s += " " + a 533 } else { 534 s += " " + strconv.Itoa(int(alg)) 535 } 536 } 537 return s 538} 539func (e *EDNS0_N3U) copy() EDNS0 { return &EDNS0_N3U{e.Code, e.AlgCode} } 540 541// EDNS0_EXPIRE implements the EDNS0 option as described in RFC 7314. 542type EDNS0_EXPIRE struct { 543 Code uint16 // Always EDNS0EXPIRE 544 Expire uint32 545} 546 547// Option implements the EDNS0 interface. 548func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE } 549func (e *EDNS0_EXPIRE) String() string { return strconv.FormatUint(uint64(e.Expire), 10) } 550func (e *EDNS0_EXPIRE) copy() EDNS0 { return &EDNS0_EXPIRE{e.Code, e.Expire} } 551 552func (e *EDNS0_EXPIRE) pack() ([]byte, error) { 553 b := make([]byte, 4) 554 binary.BigEndian.PutUint32(b, e.Expire) 555 return b, nil 556} 557 558func (e *EDNS0_EXPIRE) unpack(b []byte) error { 559 if len(b) == 0 { 560 // zero-length EXPIRE query, see RFC 7314 Section 2 561 return nil 562 } 563 if len(b) < 4 { 564 return ErrBuf 565 } 566 e.Expire = binary.BigEndian.Uint32(b) 567 return nil 568} 569 570// The EDNS0_LOCAL option is used for local/experimental purposes. The option 571// code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND] 572// (RFC6891), although any unassigned code can actually be used. The content of 573// the option is made available in Data, unaltered. 574// Basic use pattern for creating a local option: 575// 576// o := new(dns.OPT) 577// o.Hdr.Name = "." 578// o.Hdr.Rrtype = dns.TypeOPT 579// e := new(dns.EDNS0_LOCAL) 580// e.Code = dns.EDNS0LOCALSTART 581// e.Data = []byte{72, 82, 74} 582// o.Option = append(o.Option, e) 583type EDNS0_LOCAL struct { 584 Code uint16 585 Data []byte 586} 587 588// Option implements the EDNS0 interface. 589func (e *EDNS0_LOCAL) Option() uint16 { return e.Code } 590func (e *EDNS0_LOCAL) String() string { 591 return strconv.FormatInt(int64(e.Code), 10) + ":0x" + hex.EncodeToString(e.Data) 592} 593func (e *EDNS0_LOCAL) copy() EDNS0 { 594 b := make([]byte, len(e.Data)) 595 copy(b, e.Data) 596 return &EDNS0_LOCAL{e.Code, b} 597} 598 599func (e *EDNS0_LOCAL) pack() ([]byte, error) { 600 b := make([]byte, len(e.Data)) 601 copied := copy(b, e.Data) 602 if copied != len(e.Data) { 603 return nil, ErrBuf 604 } 605 return b, nil 606} 607 608func (e *EDNS0_LOCAL) unpack(b []byte) error { 609 e.Data = make([]byte, len(b)) 610 copied := copy(e.Data, b) 611 if copied != len(b) { 612 return ErrBuf 613 } 614 return nil 615} 616 617// EDNS0_TCP_KEEPALIVE is an EDNS0 option that instructs the server to keep 618// the TCP connection alive. See RFC 7828. 619type EDNS0_TCP_KEEPALIVE struct { 620 Code uint16 // Always EDNSTCPKEEPALIVE 621 Length uint16 // the value 0 if the TIMEOUT is omitted, the value 2 if it is present; 622 Timeout uint16 // an idle timeout value for the TCP connection, specified in units of 100 milliseconds, encoded in network byte order. 623} 624 625// Option implements the EDNS0 interface. 626func (e *EDNS0_TCP_KEEPALIVE) Option() uint16 { return EDNS0TCPKEEPALIVE } 627 628func (e *EDNS0_TCP_KEEPALIVE) pack() ([]byte, error) { 629 if e.Timeout != 0 && e.Length != 2 { 630 return nil, errors.New("dns: timeout specified but length is not 2") 631 } 632 if e.Timeout == 0 && e.Length != 0 { 633 return nil, errors.New("dns: timeout not specified but length is not 0") 634 } 635 b := make([]byte, 4+e.Length) 636 binary.BigEndian.PutUint16(b[0:], e.Code) 637 binary.BigEndian.PutUint16(b[2:], e.Length) 638 if e.Length == 2 { 639 binary.BigEndian.PutUint16(b[4:], e.Timeout) 640 } 641 return b, nil 642} 643 644func (e *EDNS0_TCP_KEEPALIVE) unpack(b []byte) error { 645 if len(b) < 4 { 646 return ErrBuf 647 } 648 e.Length = binary.BigEndian.Uint16(b[2:4]) 649 if e.Length != 0 && e.Length != 2 { 650 return errors.New("dns: length mismatch, want 0/2 but got " + strconv.FormatUint(uint64(e.Length), 10)) 651 } 652 if e.Length == 2 { 653 if len(b) < 6 { 654 return ErrBuf 655 } 656 e.Timeout = binary.BigEndian.Uint16(b[4:6]) 657 } 658 return nil 659} 660 661func (e *EDNS0_TCP_KEEPALIVE) String() (s string) { 662 s = "use tcp keep-alive" 663 if e.Length == 0 { 664 s += ", timeout omitted" 665 } else { 666 s += fmt.Sprintf(", timeout %dms", e.Timeout*100) 667 } 668 return 669} 670func (e *EDNS0_TCP_KEEPALIVE) copy() EDNS0 { return &EDNS0_TCP_KEEPALIVE{e.Code, e.Length, e.Timeout} } 671 672// EDNS0_PADDING option is used to add padding to a request/response. The default 673// value of padding SHOULD be 0x0 but other values MAY be used, for instance if 674// compression is applied before encryption which may break signatures. 675type EDNS0_PADDING struct { 676 Padding []byte 677} 678 679// Option implements the EDNS0 interface. 680func (e *EDNS0_PADDING) Option() uint16 { return EDNS0PADDING } 681func (e *EDNS0_PADDING) pack() ([]byte, error) { return e.Padding, nil } 682func (e *EDNS0_PADDING) unpack(b []byte) error { e.Padding = b; return nil } 683func (e *EDNS0_PADDING) String() string { return fmt.Sprintf("%0X", e.Padding) } 684func (e *EDNS0_PADDING) copy() EDNS0 { 685 b := make([]byte, len(e.Padding)) 686 copy(b, e.Padding) 687 return &EDNS0_PADDING{b} 688} 689 690// Extended DNS Error Codes (RFC 8914). 691const ( 692 ExtendedErrorCodeOther uint16 = iota 693 ExtendedErrorCodeUnsupportedDNSKEYAlgorithm 694 ExtendedErrorCodeUnsupportedDSDigestType 695 ExtendedErrorCodeStaleAnswer 696 ExtendedErrorCodeForgedAnswer 697 ExtendedErrorCodeDNSSECIndeterminate 698 ExtendedErrorCodeDNSBogus 699 ExtendedErrorCodeSignatureExpired 700 ExtendedErrorCodeSignatureNotYetValid 701 ExtendedErrorCodeDNSKEYMissing 702 ExtendedErrorCodeRRSIGsMissing 703 ExtendedErrorCodeNoZoneKeyBitSet 704 ExtendedErrorCodeNSECMissing 705 ExtendedErrorCodeCachedError 706 ExtendedErrorCodeNotReady 707 ExtendedErrorCodeBlocked 708 ExtendedErrorCodeCensored 709 ExtendedErrorCodeFiltered 710 ExtendedErrorCodeProhibited 711 ExtendedErrorCodeStaleNXDOMAINAnswer 712 ExtendedErrorCodeNotAuthoritative 713 ExtendedErrorCodeNotSupported 714 ExtendedErrorCodeNoReachableAuthority 715 ExtendedErrorCodeNetworkError 716 ExtendedErrorCodeInvalidData 717) 718 719// ExtendedErrorCodeToString maps extended error info codes to a human readable 720// description. 721var ExtendedErrorCodeToString = map[uint16]string{ 722 ExtendedErrorCodeOther: "Other", 723 ExtendedErrorCodeUnsupportedDNSKEYAlgorithm: "Unsupported DNSKEY Algorithm", 724 ExtendedErrorCodeUnsupportedDSDigestType: "Unsupported DS Digest Type", 725 ExtendedErrorCodeStaleAnswer: "Stale Answer", 726 ExtendedErrorCodeForgedAnswer: "Forged Answer", 727 ExtendedErrorCodeDNSSECIndeterminate: "DNSSEC Indeterminate", 728 ExtendedErrorCodeDNSBogus: "DNSSEC Bogus", 729 ExtendedErrorCodeSignatureExpired: "Signature Expired", 730 ExtendedErrorCodeSignatureNotYetValid: "Signature Not Yet Valid", 731 ExtendedErrorCodeDNSKEYMissing: "DNSKEY Missing", 732 ExtendedErrorCodeRRSIGsMissing: "RRSIGs Missing", 733 ExtendedErrorCodeNoZoneKeyBitSet: "No Zone Key Bit Set", 734 ExtendedErrorCodeNSECMissing: "NSEC Missing", 735 ExtendedErrorCodeCachedError: "Cached Error", 736 ExtendedErrorCodeNotReady: "Not Ready", 737 ExtendedErrorCodeBlocked: "Blocked", 738 ExtendedErrorCodeCensored: "Censored", 739 ExtendedErrorCodeFiltered: "Filtered", 740 ExtendedErrorCodeProhibited: "Prohibited", 741 ExtendedErrorCodeStaleNXDOMAINAnswer: "Stale NXDOMAIN Answer", 742 ExtendedErrorCodeNotAuthoritative: "Not Authoritative", 743 ExtendedErrorCodeNotSupported: "Not Supported", 744 ExtendedErrorCodeNoReachableAuthority: "No Reachable Authority", 745 ExtendedErrorCodeNetworkError: "Network Error", 746 ExtendedErrorCodeInvalidData: "Invalid Data", 747} 748 749// StringToExtendedErrorCode is a map from human readable descriptions to 750// extended error info codes. 751var StringToExtendedErrorCode = reverseInt16(ExtendedErrorCodeToString) 752 753// EDNS0_EDE option is used to return additional information about the cause of 754// DNS errors. 755type EDNS0_EDE struct { 756 InfoCode uint16 757 ExtraText string 758} 759 760// Option implements the EDNS0 interface. 761func (e *EDNS0_EDE) Option() uint16 { return EDNS0EDE } 762func (e *EDNS0_EDE) copy() EDNS0 { return &EDNS0_EDE{e.InfoCode, e.ExtraText} } 763 764func (e *EDNS0_EDE) String() string { 765 info := strconv.FormatUint(uint64(e.InfoCode), 10) 766 if s, ok := ExtendedErrorCodeToString[e.InfoCode]; ok { 767 info += fmt.Sprintf(" (%s)", s) 768 } 769 return fmt.Sprintf("%s: (%s)", info, e.ExtraText) 770} 771 772func (e *EDNS0_EDE) pack() ([]byte, error) { 773 b := make([]byte, 2+len(e.ExtraText)) 774 binary.BigEndian.PutUint16(b[0:], e.InfoCode) 775 copy(b[2:], []byte(e.ExtraText)) 776 return b, nil 777} 778 779func (e *EDNS0_EDE) unpack(b []byte) error { 780 if len(b) < 2 { 781 return ErrBuf 782 } 783 e.InfoCode = binary.BigEndian.Uint16(b[0:]) 784 e.ExtraText = string(b[2:]) 785 return nil 786} 787