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