edns.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. package dns
  2. import (
  3. "encoding/binary"
  4. "encoding/hex"
  5. "errors"
  6. "fmt"
  7. "net"
  8. "strconv"
  9. )
  10. // EDNS0 Option codes.
  11. const (
  12. EDNS0LLQ = 0x1 // long lived queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
  13. EDNS0UL = 0x2 // update lease draft: http://files.dns-sd.org/draft-sekar-dns-ul.txt
  14. EDNS0NSID = 0x3 // nsid (RFC5001)
  15. EDNS0DAU = 0x5 // DNSSEC Algorithm Understood
  16. EDNS0DHU = 0x6 // DS Hash Understood
  17. EDNS0N3U = 0x7 // NSEC3 Hash Understood
  18. EDNS0SUBNET = 0x8 // client-subnet (RFC6891)
  19. EDNS0EXPIRE = 0x9 // EDNS0 expire
  20. EDNS0COOKIE = 0xa // EDNS0 Cookie
  21. EDNS0TCPKEEPALIVE = 0xb // EDNS0 tcp keep alive (RFC7828)
  22. EDNS0SUBNETDRAFT = 0x50fa // Don't use! Use EDNS0SUBNET
  23. EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (RFC6891)
  24. EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (RFC6891)
  25. _DO = 1 << 15 // dnssec ok
  26. )
  27. // OPT is the EDNS0 RR appended to messages to convey extra (meta) information.
  28. // See RFC 6891.
  29. type OPT struct {
  30. Hdr RR_Header
  31. Option []EDNS0 `dns:"opt"`
  32. }
  33. func (rr *OPT) String() string {
  34. s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; "
  35. if rr.Do() {
  36. s += "flags: do; "
  37. } else {
  38. s += "flags: ; "
  39. }
  40. s += "udp: " + strconv.Itoa(int(rr.UDPSize()))
  41. for _, o := range rr.Option {
  42. switch o.(type) {
  43. case *EDNS0_NSID:
  44. s += "\n; NSID: " + o.String()
  45. h, e := o.pack()
  46. var r string
  47. if e == nil {
  48. for _, c := range h {
  49. r += "(" + string(c) + ")"
  50. }
  51. s += " " + r
  52. }
  53. case *EDNS0_SUBNET:
  54. s += "\n; SUBNET: " + o.String()
  55. if o.(*EDNS0_SUBNET).DraftOption {
  56. s += " (draft)"
  57. }
  58. case *EDNS0_COOKIE:
  59. s += "\n; COOKIE: " + o.String()
  60. case *EDNS0_UL:
  61. s += "\n; UPDATE LEASE: " + o.String()
  62. case *EDNS0_LLQ:
  63. s += "\n; LONG LIVED QUERIES: " + o.String()
  64. case *EDNS0_DAU:
  65. s += "\n; DNSSEC ALGORITHM UNDERSTOOD: " + o.String()
  66. case *EDNS0_DHU:
  67. s += "\n; DS HASH UNDERSTOOD: " + o.String()
  68. case *EDNS0_N3U:
  69. s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String()
  70. case *EDNS0_LOCAL:
  71. s += "\n; LOCAL OPT: " + o.String()
  72. }
  73. }
  74. return s
  75. }
  76. func (rr *OPT) len() int {
  77. l := rr.Hdr.len()
  78. for i := 0; i < len(rr.Option); i++ {
  79. l += 4 // Account for 2-byte option code and 2-byte option length.
  80. lo, _ := rr.Option[i].pack()
  81. l += len(lo)
  82. }
  83. return l
  84. }
  85. // return the old value -> delete SetVersion?
  86. // Version returns the EDNS version used. Only zero is defined.
  87. func (rr *OPT) Version() uint8 {
  88. return uint8((rr.Hdr.Ttl & 0x00FF0000) >> 16)
  89. }
  90. // SetVersion sets the version of EDNS. This is usually zero.
  91. func (rr *OPT) SetVersion(v uint8) {
  92. rr.Hdr.Ttl = rr.Hdr.Ttl&0xFF00FFFF | (uint32(v) << 16)
  93. }
  94. // ExtendedRcode returns the EDNS extended RCODE field (the upper 8 bits of the TTL).
  95. func (rr *OPT) ExtendedRcode() int {
  96. return int((rr.Hdr.Ttl&0xFF000000)>>24) + 15
  97. }
  98. // SetExtendedRcode sets the EDNS extended RCODE field.
  99. func (rr *OPT) SetExtendedRcode(v uint8) {
  100. if v < RcodeBadVers { // Smaller than 16.. Use the 4 bits you have!
  101. return
  102. }
  103. rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | (uint32(v-15) << 24)
  104. }
  105. // UDPSize returns the UDP buffer size.
  106. func (rr *OPT) UDPSize() uint16 {
  107. return rr.Hdr.Class
  108. }
  109. // SetUDPSize sets the UDP buffer size.
  110. func (rr *OPT) SetUDPSize(size uint16) {
  111. rr.Hdr.Class = size
  112. }
  113. // Do returns the value of the DO (DNSSEC OK) bit.
  114. func (rr *OPT) Do() bool {
  115. return rr.Hdr.Ttl&_DO == _DO
  116. }
  117. // SetDo sets the DO (DNSSEC OK) bit.
  118. // If we pass an argument, set the DO bit to that value.
  119. // It is possible to pass 2 or more arguments. Any arguments after the 1st is silently ignored.
  120. func (rr *OPT) SetDo(do ...bool) {
  121. if len(do) == 1 {
  122. if do[0] {
  123. rr.Hdr.Ttl |= _DO
  124. } else {
  125. rr.Hdr.Ttl &^= _DO
  126. }
  127. } else {
  128. rr.Hdr.Ttl |= _DO
  129. }
  130. }
  131. // EDNS0 defines an EDNS0 Option. An OPT RR can have multiple options appended to it.
  132. type EDNS0 interface {
  133. // Option returns the option code for the option.
  134. Option() uint16
  135. // pack returns the bytes of the option data.
  136. pack() ([]byte, error)
  137. // unpack sets the data as found in the buffer. Is also sets
  138. // the length of the slice as the length of the option data.
  139. unpack([]byte) error
  140. // String returns the string representation of the option.
  141. String() string
  142. }
  143. // EDNS0_NSID option is used to retrieve a nameserver
  144. // identifier. When sending a request Nsid must be set to the empty string
  145. // The identifier is an opaque string encoded as hex.
  146. // Basic use pattern for creating an nsid option:
  147. //
  148. // o := new(dns.OPT)
  149. // o.Hdr.Name = "."
  150. // o.Hdr.Rrtype = dns.TypeOPT
  151. // e := new(dns.EDNS0_NSID)
  152. // e.Code = dns.EDNS0NSID
  153. // e.Nsid = "AA"
  154. // o.Option = append(o.Option, e)
  155. type EDNS0_NSID struct {
  156. Code uint16 // Always EDNS0NSID
  157. Nsid string // This string needs to be hex encoded
  158. }
  159. func (e *EDNS0_NSID) pack() ([]byte, error) {
  160. h, err := hex.DecodeString(e.Nsid)
  161. if err != nil {
  162. return nil, err
  163. }
  164. return h, nil
  165. }
  166. func (e *EDNS0_NSID) Option() uint16 { return EDNS0NSID }
  167. func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil }
  168. func (e *EDNS0_NSID) String() string { return string(e.Nsid) }
  169. // EDNS0_SUBNET is the subnet option that is used to give the remote nameserver
  170. // an idea of where the client lives. It can then give back a different
  171. // answer depending on the location or network topology.
  172. // Basic use pattern for creating an subnet option:
  173. //
  174. // o := new(dns.OPT)
  175. // o.Hdr.Name = "."
  176. // o.Hdr.Rrtype = dns.TypeOPT
  177. // e := new(dns.EDNS0_SUBNET)
  178. // e.Code = dns.EDNS0SUBNET
  179. // e.Family = 1 // 1 for IPv4 source address, 2 for IPv6
  180. // e.SourceNetmask = 32 // 32 for IPV4, 128 for IPv6
  181. // e.SourceScope = 0
  182. // e.Address = net.ParseIP("127.0.0.1").To4() // for IPv4
  183. // // e.Address = net.ParseIP("2001:7b8:32a::2") // for IPV6
  184. // o.Option = append(o.Option, e)
  185. //
  186. // Note: the spec (draft-ietf-dnsop-edns-client-subnet-00) has some insane logic
  187. // for which netmask applies to the address. This code will parse all the
  188. // available bits when unpacking (up to optlen). When packing it will apply
  189. // SourceNetmask. If you need more advanced logic, patches welcome and good luck.
  190. type EDNS0_SUBNET struct {
  191. Code uint16 // Always EDNS0SUBNET
  192. Family uint16 // 1 for IP, 2 for IP6
  193. SourceNetmask uint8
  194. SourceScope uint8
  195. Address net.IP
  196. DraftOption bool // Set to true if using the old (0x50fa) option code
  197. }
  198. func (e *EDNS0_SUBNET) Option() uint16 {
  199. if e.DraftOption {
  200. return EDNS0SUBNETDRAFT
  201. }
  202. return EDNS0SUBNET
  203. }
  204. func (e *EDNS0_SUBNET) pack() ([]byte, error) {
  205. b := make([]byte, 4)
  206. binary.BigEndian.PutUint16(b[0:], e.Family)
  207. b[2] = e.SourceNetmask
  208. b[3] = e.SourceScope
  209. switch e.Family {
  210. case 1:
  211. if e.SourceNetmask > net.IPv4len*8 {
  212. return nil, errors.New("dns: bad netmask")
  213. }
  214. if len(e.Address.To4()) != net.IPv4len {
  215. return nil, errors.New("dns: bad address")
  216. }
  217. ip := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8))
  218. needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
  219. b = append(b, ip[:needLength]...)
  220. case 2:
  221. if e.SourceNetmask > net.IPv6len*8 {
  222. return nil, errors.New("dns: bad netmask")
  223. }
  224. if len(e.Address) != net.IPv6len {
  225. return nil, errors.New("dns: bad address")
  226. }
  227. ip := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8))
  228. needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
  229. b = append(b, ip[:needLength]...)
  230. default:
  231. return nil, errors.New("dns: bad address family")
  232. }
  233. return b, nil
  234. }
  235. func (e *EDNS0_SUBNET) unpack(b []byte) error {
  236. if len(b) < 4 {
  237. return ErrBuf
  238. }
  239. e.Family = binary.BigEndian.Uint16(b)
  240. e.SourceNetmask = b[2]
  241. e.SourceScope = b[3]
  242. switch e.Family {
  243. case 1:
  244. if e.SourceNetmask > net.IPv4len*8 || e.SourceScope > net.IPv4len*8 {
  245. return errors.New("dns: bad netmask")
  246. }
  247. addr := make([]byte, net.IPv4len)
  248. for i := 0; i < net.IPv4len && 4+i < len(b); i++ {
  249. addr[i] = b[4+i]
  250. }
  251. e.Address = net.IPv4(addr[0], addr[1], addr[2], addr[3])
  252. case 2:
  253. if e.SourceNetmask > net.IPv6len*8 || e.SourceScope > net.IPv6len*8 {
  254. return errors.New("dns: bad netmask")
  255. }
  256. addr := make([]byte, net.IPv6len)
  257. for i := 0; i < net.IPv6len && 4+i < len(b); i++ {
  258. addr[i] = b[4+i]
  259. }
  260. e.Address = net.IP{addr[0], addr[1], addr[2], addr[3], addr[4],
  261. addr[5], addr[6], addr[7], addr[8], addr[9], addr[10],
  262. addr[11], addr[12], addr[13], addr[14], addr[15]}
  263. default:
  264. return errors.New("dns: bad address family")
  265. }
  266. return nil
  267. }
  268. func (e *EDNS0_SUBNET) String() (s string) {
  269. if e.Address == nil {
  270. s = "<nil>"
  271. } else if e.Address.To4() != nil {
  272. s = e.Address.String()
  273. } else {
  274. s = "[" + e.Address.String() + "]"
  275. }
  276. s += "/" + strconv.Itoa(int(e.SourceNetmask)) + "/" + strconv.Itoa(int(e.SourceScope))
  277. return
  278. }
  279. // The EDNS0_COOKIE option is used to add a DNS Cookie to a message.
  280. //
  281. // o := new(dns.OPT)
  282. // o.Hdr.Name = "."
  283. // o.Hdr.Rrtype = dns.TypeOPT
  284. // e := new(dns.EDNS0_COOKIE)
  285. // e.Code = dns.EDNS0COOKIE
  286. // e.Cookie = "24a5ac.."
  287. // o.Option = append(o.Option, e)
  288. //
  289. // The Cookie field consists out of a client cookie (RFC 7873 Section 4), that is
  290. // always 8 bytes. It may then optionally be followed by the server cookie. The server
  291. // cookie is of variable length, 8 to a maximum of 32 bytes. In other words:
  292. //
  293. // cCookie := o.Cookie[:16]
  294. // sCookie := o.Cookie[16:]
  295. //
  296. // There is no guarantee that the Cookie string has a specific length.
  297. type EDNS0_COOKIE struct {
  298. Code uint16 // Always EDNS0COOKIE
  299. Cookie string // Hex-encoded cookie data
  300. }
  301. func (e *EDNS0_COOKIE) pack() ([]byte, error) {
  302. h, err := hex.DecodeString(e.Cookie)
  303. if err != nil {
  304. return nil, err
  305. }
  306. return h, nil
  307. }
  308. func (e *EDNS0_COOKIE) Option() uint16 { return EDNS0COOKIE }
  309. func (e *EDNS0_COOKIE) unpack(b []byte) error { e.Cookie = hex.EncodeToString(b); return nil }
  310. func (e *EDNS0_COOKIE) String() string { return e.Cookie }
  311. // The EDNS0_UL (Update Lease) (draft RFC) option is used to tell the server to set
  312. // an expiration on an update RR. This is helpful for clients that cannot clean
  313. // up after themselves. This is a draft RFC and more information can be found at
  314. // http://files.dns-sd.org/draft-sekar-dns-ul.txt
  315. //
  316. // o := new(dns.OPT)
  317. // o.Hdr.Name = "."
  318. // o.Hdr.Rrtype = dns.TypeOPT
  319. // e := new(dns.EDNS0_UL)
  320. // e.Code = dns.EDNS0UL
  321. // e.Lease = 120 // in seconds
  322. // o.Option = append(o.Option, e)
  323. type EDNS0_UL struct {
  324. Code uint16 // Always EDNS0UL
  325. Lease uint32
  326. }
  327. func (e *EDNS0_UL) Option() uint16 { return EDNS0UL }
  328. func (e *EDNS0_UL) String() string { return strconv.FormatUint(uint64(e.Lease), 10) }
  329. // Copied: http://golang.org/src/pkg/net/dnsmsg.go
  330. func (e *EDNS0_UL) pack() ([]byte, error) {
  331. b := make([]byte, 4)
  332. binary.BigEndian.PutUint32(b, e.Lease)
  333. return b, nil
  334. }
  335. func (e *EDNS0_UL) unpack(b []byte) error {
  336. if len(b) < 4 {
  337. return ErrBuf
  338. }
  339. e.Lease = binary.BigEndian.Uint32(b)
  340. return nil
  341. }
  342. // EDNS0_LLQ stands for Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
  343. // Implemented for completeness, as the EDNS0 type code is assigned.
  344. type EDNS0_LLQ struct {
  345. Code uint16 // Always EDNS0LLQ
  346. Version uint16
  347. Opcode uint16
  348. Error uint16
  349. Id uint64
  350. LeaseLife uint32
  351. }
  352. func (e *EDNS0_LLQ) Option() uint16 { return EDNS0LLQ }
  353. func (e *EDNS0_LLQ) pack() ([]byte, error) {
  354. b := make([]byte, 18)
  355. binary.BigEndian.PutUint16(b[0:], e.Version)
  356. binary.BigEndian.PutUint16(b[2:], e.Opcode)
  357. binary.BigEndian.PutUint16(b[4:], e.Error)
  358. binary.BigEndian.PutUint64(b[6:], e.Id)
  359. binary.BigEndian.PutUint32(b[14:], e.LeaseLife)
  360. return b, nil
  361. }
  362. func (e *EDNS0_LLQ) unpack(b []byte) error {
  363. if len(b) < 18 {
  364. return ErrBuf
  365. }
  366. e.Version = binary.BigEndian.Uint16(b[0:])
  367. e.Opcode = binary.BigEndian.Uint16(b[2:])
  368. e.Error = binary.BigEndian.Uint16(b[4:])
  369. e.Id = binary.BigEndian.Uint64(b[6:])
  370. e.LeaseLife = binary.BigEndian.Uint32(b[14:])
  371. return nil
  372. }
  373. func (e *EDNS0_LLQ) String() string {
  374. s := strconv.FormatUint(uint64(e.Version), 10) + " " + strconv.FormatUint(uint64(e.Opcode), 10) +
  375. " " + strconv.FormatUint(uint64(e.Error), 10) + " " + strconv.FormatUint(uint64(e.Id), 10) +
  376. " " + strconv.FormatUint(uint64(e.LeaseLife), 10)
  377. return s
  378. }
  379. type EDNS0_DAU struct {
  380. Code uint16 // Always EDNS0DAU
  381. AlgCode []uint8
  382. }
  383. func (e *EDNS0_DAU) Option() uint16 { return EDNS0DAU }
  384. func (e *EDNS0_DAU) pack() ([]byte, error) { return e.AlgCode, nil }
  385. func (e *EDNS0_DAU) unpack(b []byte) error { e.AlgCode = b; return nil }
  386. func (e *EDNS0_DAU) String() string {
  387. s := ""
  388. for i := 0; i < len(e.AlgCode); i++ {
  389. if a, ok := AlgorithmToString[e.AlgCode[i]]; ok {
  390. s += " " + a
  391. } else {
  392. s += " " + strconv.Itoa(int(e.AlgCode[i]))
  393. }
  394. }
  395. return s
  396. }
  397. type EDNS0_DHU struct {
  398. Code uint16 // Always EDNS0DHU
  399. AlgCode []uint8
  400. }
  401. func (e *EDNS0_DHU) Option() uint16 { return EDNS0DHU }
  402. func (e *EDNS0_DHU) pack() ([]byte, error) { return e.AlgCode, nil }
  403. func (e *EDNS0_DHU) unpack(b []byte) error { e.AlgCode = b; return nil }
  404. func (e *EDNS0_DHU) String() string {
  405. s := ""
  406. for i := 0; i < len(e.AlgCode); i++ {
  407. if a, ok := HashToString[e.AlgCode[i]]; ok {
  408. s += " " + a
  409. } else {
  410. s += " " + strconv.Itoa(int(e.AlgCode[i]))
  411. }
  412. }
  413. return s
  414. }
  415. type EDNS0_N3U struct {
  416. Code uint16 // Always EDNS0N3U
  417. AlgCode []uint8
  418. }
  419. func (e *EDNS0_N3U) Option() uint16 { return EDNS0N3U }
  420. func (e *EDNS0_N3U) pack() ([]byte, error) { return e.AlgCode, nil }
  421. func (e *EDNS0_N3U) unpack(b []byte) error { e.AlgCode = b; return nil }
  422. func (e *EDNS0_N3U) String() string {
  423. // Re-use the hash map
  424. s := ""
  425. for i := 0; i < len(e.AlgCode); i++ {
  426. if a, ok := HashToString[e.AlgCode[i]]; ok {
  427. s += " " + a
  428. } else {
  429. s += " " + strconv.Itoa(int(e.AlgCode[i]))
  430. }
  431. }
  432. return s
  433. }
  434. type EDNS0_EXPIRE struct {
  435. Code uint16 // Always EDNS0EXPIRE
  436. Expire uint32
  437. }
  438. func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE }
  439. func (e *EDNS0_EXPIRE) String() string { return strconv.FormatUint(uint64(e.Expire), 10) }
  440. func (e *EDNS0_EXPIRE) pack() ([]byte, error) {
  441. b := make([]byte, 4)
  442. b[0] = byte(e.Expire >> 24)
  443. b[1] = byte(e.Expire >> 16)
  444. b[2] = byte(e.Expire >> 8)
  445. b[3] = byte(e.Expire)
  446. return b, nil
  447. }
  448. func (e *EDNS0_EXPIRE) unpack(b []byte) error {
  449. if len(b) < 4 {
  450. return ErrBuf
  451. }
  452. e.Expire = binary.BigEndian.Uint32(b)
  453. return nil
  454. }
  455. // The EDNS0_LOCAL option is used for local/experimental purposes. The option
  456. // code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND]
  457. // (RFC6891), although any unassigned code can actually be used. The content of
  458. // the option is made available in Data, unaltered.
  459. // Basic use pattern for creating a local option:
  460. //
  461. // o := new(dns.OPT)
  462. // o.Hdr.Name = "."
  463. // o.Hdr.Rrtype = dns.TypeOPT
  464. // e := new(dns.EDNS0_LOCAL)
  465. // e.Code = dns.EDNS0LOCALSTART
  466. // e.Data = []byte{72, 82, 74}
  467. // o.Option = append(o.Option, e)
  468. type EDNS0_LOCAL struct {
  469. Code uint16
  470. Data []byte
  471. }
  472. func (e *EDNS0_LOCAL) Option() uint16 { return e.Code }
  473. func (e *EDNS0_LOCAL) String() string {
  474. return strconv.FormatInt(int64(e.Code), 10) + ":0x" + hex.EncodeToString(e.Data)
  475. }
  476. func (e *EDNS0_LOCAL) pack() ([]byte, error) {
  477. b := make([]byte, len(e.Data))
  478. copied := copy(b, e.Data)
  479. if copied != len(e.Data) {
  480. return nil, ErrBuf
  481. }
  482. return b, nil
  483. }
  484. func (e *EDNS0_LOCAL) unpack(b []byte) error {
  485. e.Data = make([]byte, len(b))
  486. copied := copy(e.Data, b)
  487. if copied != len(b) {
  488. return ErrBuf
  489. }
  490. return nil
  491. }
  492. // EDNS0_TCP_KEEPALIVE is an EDNS0 option that instructs the server to keep
  493. // the TCP connection alive. See RFC 7828.
  494. type EDNS0_TCP_KEEPALIVE struct {
  495. Code uint16 // Always EDNSTCPKEEPALIVE
  496. Length uint16 // the value 0 if the TIMEOUT is omitted, the value 2 if it is present;
  497. Timeout uint16 // an idle timeout value for the TCP connection, specified in units of 100 milliseconds, encoded in network byte order.
  498. }
  499. func (e *EDNS0_TCP_KEEPALIVE) Option() uint16 { return EDNS0TCPKEEPALIVE }
  500. func (e *EDNS0_TCP_KEEPALIVE) pack() ([]byte, error) {
  501. if e.Timeout != 0 && e.Length != 2 {
  502. return nil, errors.New("dns: timeout specified but length is not 2")
  503. }
  504. if e.Timeout == 0 && e.Length != 0 {
  505. return nil, errors.New("dns: timeout not specified but length is not 0")
  506. }
  507. b := make([]byte, 4+e.Length)
  508. binary.BigEndian.PutUint16(b[0:], e.Code)
  509. binary.BigEndian.PutUint16(b[2:], e.Length)
  510. if e.Length == 2 {
  511. binary.BigEndian.PutUint16(b[4:], e.Timeout)
  512. }
  513. return b, nil
  514. }
  515. func (e *EDNS0_TCP_KEEPALIVE) unpack(b []byte) error {
  516. if len(b) < 4 {
  517. return ErrBuf
  518. }
  519. e.Length = binary.BigEndian.Uint16(b[2:4])
  520. if e.Length != 0 && e.Length != 2 {
  521. return errors.New("dns: length mismatch, want 0/2 but got " + strconv.FormatUint(uint64(e.Length), 10))
  522. }
  523. if e.Length == 2 {
  524. if len(b) < 6 {
  525. return ErrBuf
  526. }
  527. e.Timeout = binary.BigEndian.Uint16(b[4:6])
  528. }
  529. return nil
  530. }
  531. func (e *EDNS0_TCP_KEEPALIVE) String() (s string) {
  532. s = "use tcp keep-alive"
  533. if e.Length == 0 {
  534. s += ", timeout omitted"
  535. } else {
  536. s += fmt.Sprintf(", timeout %dms", e.Timeout*100)
  537. }
  538. return
  539. }