svcb.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935
  1. package dns
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "net"
  8. "sort"
  9. "strconv"
  10. "strings"
  11. )
  12. // SVCBKey is the type of the keys used in the SVCB RR.
  13. type SVCBKey uint16
  14. // Keys defined in draft-ietf-dnsop-svcb-https-08 Section 14.3.2.
  15. const (
  16. SVCB_MANDATORY SVCBKey = iota
  17. SVCB_ALPN
  18. SVCB_NO_DEFAULT_ALPN
  19. SVCB_PORT
  20. SVCB_IPV4HINT
  21. SVCB_ECHCONFIG
  22. SVCB_IPV6HINT
  23. SVCB_DOHPATH // draft-ietf-add-svcb-dns-02 Section 9
  24. svcb_RESERVED SVCBKey = 65535
  25. )
  26. var svcbKeyToStringMap = map[SVCBKey]string{
  27. SVCB_MANDATORY: "mandatory",
  28. SVCB_ALPN: "alpn",
  29. SVCB_NO_DEFAULT_ALPN: "no-default-alpn",
  30. SVCB_PORT: "port",
  31. SVCB_IPV4HINT: "ipv4hint",
  32. SVCB_ECHCONFIG: "ech",
  33. SVCB_IPV6HINT: "ipv6hint",
  34. SVCB_DOHPATH: "dohpath",
  35. }
  36. var svcbStringToKeyMap = reverseSVCBKeyMap(svcbKeyToStringMap)
  37. func reverseSVCBKeyMap(m map[SVCBKey]string) map[string]SVCBKey {
  38. n := make(map[string]SVCBKey, len(m))
  39. for u, s := range m {
  40. n[s] = u
  41. }
  42. return n
  43. }
  44. // String takes the numerical code of an SVCB key and returns its name.
  45. // Returns an empty string for reserved keys.
  46. // Accepts unassigned keys as well as experimental/private keys.
  47. func (key SVCBKey) String() string {
  48. if x := svcbKeyToStringMap[key]; x != "" {
  49. return x
  50. }
  51. if key == svcb_RESERVED {
  52. return ""
  53. }
  54. return "key" + strconv.FormatUint(uint64(key), 10)
  55. }
  56. // svcbStringToKey returns the numerical code of an SVCB key.
  57. // Returns svcb_RESERVED for reserved/invalid keys.
  58. // Accepts unassigned keys as well as experimental/private keys.
  59. func svcbStringToKey(s string) SVCBKey {
  60. if strings.HasPrefix(s, "key") {
  61. a, err := strconv.ParseUint(s[3:], 10, 16)
  62. // no leading zeros
  63. // key shouldn't be registered
  64. if err != nil || a == 65535 || s[3] == '0' || svcbKeyToStringMap[SVCBKey(a)] != "" {
  65. return svcb_RESERVED
  66. }
  67. return SVCBKey(a)
  68. }
  69. if key, ok := svcbStringToKeyMap[s]; ok {
  70. return key
  71. }
  72. return svcb_RESERVED
  73. }
  74. func (rr *SVCB) parse(c *zlexer, o string) *ParseError {
  75. l, _ := c.Next()
  76. i, e := strconv.ParseUint(l.token, 10, 16)
  77. if e != nil || l.err {
  78. return &ParseError{l.token, "bad SVCB priority", l}
  79. }
  80. rr.Priority = uint16(i)
  81. c.Next() // zBlank
  82. l, _ = c.Next() // zString
  83. rr.Target = l.token
  84. name, nameOk := toAbsoluteName(l.token, o)
  85. if l.err || !nameOk {
  86. return &ParseError{l.token, "bad SVCB Target", l}
  87. }
  88. rr.Target = name
  89. // Values (if any)
  90. l, _ = c.Next()
  91. var xs []SVCBKeyValue
  92. // Helps require whitespace between pairs.
  93. // Prevents key1000="a"key1001=...
  94. canHaveNextKey := true
  95. for l.value != zNewline && l.value != zEOF {
  96. switch l.value {
  97. case zString:
  98. if !canHaveNextKey {
  99. // The key we can now read was probably meant to be
  100. // a part of the last value.
  101. return &ParseError{l.token, "bad SVCB value quotation", l}
  102. }
  103. // In key=value pairs, value does not have to be quoted unless value
  104. // contains whitespace. And keys don't need to have values.
  105. // Similarly, keys with an equality signs after them don't need values.
  106. // l.token includes at least up to the first equality sign.
  107. idx := strings.IndexByte(l.token, '=')
  108. var key, value string
  109. if idx < 0 {
  110. // Key with no value and no equality sign
  111. key = l.token
  112. } else if idx == 0 {
  113. return &ParseError{l.token, "bad SVCB key", l}
  114. } else {
  115. key, value = l.token[:idx], l.token[idx+1:]
  116. if value == "" {
  117. // We have a key and an equality sign. Maybe we have nothing
  118. // after "=" or we have a double quote.
  119. l, _ = c.Next()
  120. if l.value == zQuote {
  121. // Only needed when value ends with double quotes.
  122. // Any value starting with zQuote ends with it.
  123. canHaveNextKey = false
  124. l, _ = c.Next()
  125. switch l.value {
  126. case zString:
  127. // We have a value in double quotes.
  128. value = l.token
  129. l, _ = c.Next()
  130. if l.value != zQuote {
  131. return &ParseError{l.token, "SVCB unterminated value", l}
  132. }
  133. case zQuote:
  134. // There's nothing in double quotes.
  135. default:
  136. return &ParseError{l.token, "bad SVCB value", l}
  137. }
  138. }
  139. }
  140. }
  141. kv := makeSVCBKeyValue(svcbStringToKey(key))
  142. if kv == nil {
  143. return &ParseError{l.token, "bad SVCB key", l}
  144. }
  145. if err := kv.parse(value); err != nil {
  146. return &ParseError{l.token, err.Error(), l}
  147. }
  148. xs = append(xs, kv)
  149. case zQuote:
  150. return &ParseError{l.token, "SVCB key can't contain double quotes", l}
  151. case zBlank:
  152. canHaveNextKey = true
  153. default:
  154. return &ParseError{l.token, "bad SVCB values", l}
  155. }
  156. l, _ = c.Next()
  157. }
  158. // "In AliasMode, records SHOULD NOT include any SvcParams, and recipients MUST
  159. // ignore any SvcParams that are present."
  160. // However, we don't check rr.Priority == 0 && len(xs) > 0 here
  161. // It is the responsibility of the user of the library to check this.
  162. // This is to encourage the fixing of the source of this error.
  163. rr.Value = xs
  164. return nil
  165. }
  166. // makeSVCBKeyValue returns an SVCBKeyValue struct with the key or nil for reserved keys.
  167. func makeSVCBKeyValue(key SVCBKey) SVCBKeyValue {
  168. switch key {
  169. case SVCB_MANDATORY:
  170. return new(SVCBMandatory)
  171. case SVCB_ALPN:
  172. return new(SVCBAlpn)
  173. case SVCB_NO_DEFAULT_ALPN:
  174. return new(SVCBNoDefaultAlpn)
  175. case SVCB_PORT:
  176. return new(SVCBPort)
  177. case SVCB_IPV4HINT:
  178. return new(SVCBIPv4Hint)
  179. case SVCB_ECHCONFIG:
  180. return new(SVCBECHConfig)
  181. case SVCB_IPV6HINT:
  182. return new(SVCBIPv6Hint)
  183. case SVCB_DOHPATH:
  184. return new(SVCBDoHPath)
  185. case svcb_RESERVED:
  186. return nil
  187. default:
  188. e := new(SVCBLocal)
  189. e.KeyCode = key
  190. return e
  191. }
  192. }
  193. // SVCB RR. See RFC xxxx (https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-08).
  194. //
  195. // NOTE: The HTTPS/SVCB RFCs are in the draft stage.
  196. // The API, including constants and types related to SVCBKeyValues, may
  197. // change in future versions in accordance with the latest drafts.
  198. type SVCB struct {
  199. Hdr RR_Header
  200. Priority uint16 // If zero, Value must be empty or discarded by the user of this library
  201. Target string `dns:"domain-name"`
  202. Value []SVCBKeyValue `dns:"pairs"`
  203. }
  204. // HTTPS RR. Everything valid for SVCB applies to HTTPS as well.
  205. // Except that the HTTPS record is intended for use with the HTTP and HTTPS protocols.
  206. //
  207. // NOTE: The HTTPS/SVCB RFCs are in the draft stage.
  208. // The API, including constants and types related to SVCBKeyValues, may
  209. // change in future versions in accordance with the latest drafts.
  210. type HTTPS struct {
  211. SVCB
  212. }
  213. func (rr *HTTPS) String() string {
  214. return rr.SVCB.String()
  215. }
  216. func (rr *HTTPS) parse(c *zlexer, o string) *ParseError {
  217. return rr.SVCB.parse(c, o)
  218. }
  219. // SVCBKeyValue defines a key=value pair for the SVCB RR type.
  220. // An SVCB RR can have multiple SVCBKeyValues appended to it.
  221. type SVCBKeyValue interface {
  222. Key() SVCBKey // Key returns the numerical key code.
  223. pack() ([]byte, error) // pack returns the encoded value.
  224. unpack([]byte) error // unpack sets the value.
  225. String() string // String returns the string representation of the value.
  226. parse(string) error // parse sets the value to the given string representation of the value.
  227. copy() SVCBKeyValue // copy returns a deep-copy of the pair.
  228. len() int // len returns the length of value in the wire format.
  229. }
  230. // SVCBMandatory pair adds to required keys that must be interpreted for the RR
  231. // to be functional. If ignored, the whole RRSet must be ignored.
  232. // "port" and "no-default-alpn" are mandatory by default if present,
  233. // so they shouldn't be included here.
  234. //
  235. // It is incumbent upon the user of this library to reject the RRSet if
  236. // or avoid constructing such an RRSet that:
  237. // - "mandatory" is included as one of the keys of mandatory
  238. // - no key is listed multiple times in mandatory
  239. // - all keys listed in mandatory are present
  240. // - escape sequences are not used in mandatory
  241. // - mandatory, when present, lists at least one key
  242. //
  243. // Basic use pattern for creating a mandatory option:
  244. //
  245. // s := &dns.SVCB{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}}
  246. // e := new(dns.SVCBMandatory)
  247. // e.Code = []uint16{dns.SVCB_ALPN}
  248. // s.Value = append(s.Value, e)
  249. // t := new(dns.SVCBAlpn)
  250. // t.Alpn = []string{"xmpp-client"}
  251. // s.Value = append(s.Value, t)
  252. type SVCBMandatory struct {
  253. Code []SVCBKey
  254. }
  255. func (*SVCBMandatory) Key() SVCBKey { return SVCB_MANDATORY }
  256. func (s *SVCBMandatory) String() string {
  257. str := make([]string, len(s.Code))
  258. for i, e := range s.Code {
  259. str[i] = e.String()
  260. }
  261. return strings.Join(str, ",")
  262. }
  263. func (s *SVCBMandatory) pack() ([]byte, error) {
  264. codes := append([]SVCBKey(nil), s.Code...)
  265. sort.Slice(codes, func(i, j int) bool {
  266. return codes[i] < codes[j]
  267. })
  268. b := make([]byte, 2*len(codes))
  269. for i, e := range codes {
  270. binary.BigEndian.PutUint16(b[2*i:], uint16(e))
  271. }
  272. return b, nil
  273. }
  274. func (s *SVCBMandatory) unpack(b []byte) error {
  275. if len(b)%2 != 0 {
  276. return errors.New("dns: svcbmandatory: value length is not a multiple of 2")
  277. }
  278. codes := make([]SVCBKey, 0, len(b)/2)
  279. for i := 0; i < len(b); i += 2 {
  280. // We assume strictly increasing order.
  281. codes = append(codes, SVCBKey(binary.BigEndian.Uint16(b[i:])))
  282. }
  283. s.Code = codes
  284. return nil
  285. }
  286. func (s *SVCBMandatory) parse(b string) error {
  287. str := strings.Split(b, ",")
  288. codes := make([]SVCBKey, 0, len(str))
  289. for _, e := range str {
  290. codes = append(codes, svcbStringToKey(e))
  291. }
  292. s.Code = codes
  293. return nil
  294. }
  295. func (s *SVCBMandatory) len() int {
  296. return 2 * len(s.Code)
  297. }
  298. func (s *SVCBMandatory) copy() SVCBKeyValue {
  299. return &SVCBMandatory{
  300. append([]SVCBKey(nil), s.Code...),
  301. }
  302. }
  303. // SVCBAlpn pair is used to list supported connection protocols.
  304. // The user of this library must ensure that at least one protocol is listed when alpn is present.
  305. // Protocol IDs can be found at:
  306. // https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
  307. // Basic use pattern for creating an alpn option:
  308. //
  309. // h := new(dns.HTTPS)
  310. // h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
  311. // e := new(dns.SVCBAlpn)
  312. // e.Alpn = []string{"h2", "http/1.1"}
  313. // h.Value = append(h.Value, e)
  314. type SVCBAlpn struct {
  315. Alpn []string
  316. }
  317. func (*SVCBAlpn) Key() SVCBKey { return SVCB_ALPN }
  318. func (s *SVCBAlpn) String() string {
  319. // An ALPN value is a comma-separated list of values, each of which can be
  320. // an arbitrary binary value. In order to allow parsing, the comma and
  321. // backslash characters are themselves excaped.
  322. //
  323. // However, this escaping is done in addition to the normal escaping which
  324. // happens in zone files, meaning that these values must be
  325. // double-escaped. This looks terrible, so if you see a never-ending
  326. // sequence of backslash in a zone file this may be why.
  327. //
  328. // https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-08#appendix-A.1
  329. var str strings.Builder
  330. for i, alpn := range s.Alpn {
  331. // 4*len(alpn) is the worst case where we escape every character in the alpn as \123, plus 1 byte for the ',' separating the alpn from others
  332. str.Grow(4*len(alpn) + 1)
  333. if i > 0 {
  334. str.WriteByte(',')
  335. }
  336. for j := 0; j < len(alpn); j++ {
  337. e := alpn[j]
  338. if ' ' > e || e > '~' {
  339. str.WriteString(escapeByte(e))
  340. continue
  341. }
  342. switch e {
  343. // We escape a few characters which may confuse humans or parsers.
  344. case '"', ';', ' ':
  345. str.WriteByte('\\')
  346. str.WriteByte(e)
  347. // The comma and backslash characters themselves must be
  348. // doubly-escaped. We use `\\` for the first backslash and
  349. // the escaped numeric value for the other value. We especially
  350. // don't want a comma in the output.
  351. case ',':
  352. str.WriteString(`\\\044`)
  353. case '\\':
  354. str.WriteString(`\\\092`)
  355. default:
  356. str.WriteByte(e)
  357. }
  358. }
  359. }
  360. return str.String()
  361. }
  362. func (s *SVCBAlpn) pack() ([]byte, error) {
  363. // Liberally estimate the size of an alpn as 10 octets
  364. b := make([]byte, 0, 10*len(s.Alpn))
  365. for _, e := range s.Alpn {
  366. if e == "" {
  367. return nil, errors.New("dns: svcbalpn: empty alpn-id")
  368. }
  369. if len(e) > 255 {
  370. return nil, errors.New("dns: svcbalpn: alpn-id too long")
  371. }
  372. b = append(b, byte(len(e)))
  373. b = append(b, e...)
  374. }
  375. return b, nil
  376. }
  377. func (s *SVCBAlpn) unpack(b []byte) error {
  378. // Estimate the size of the smallest alpn as 4 bytes
  379. alpn := make([]string, 0, len(b)/4)
  380. for i := 0; i < len(b); {
  381. length := int(b[i])
  382. i++
  383. if i+length > len(b) {
  384. return errors.New("dns: svcbalpn: alpn array overflowing")
  385. }
  386. alpn = append(alpn, string(b[i:i+length]))
  387. i += length
  388. }
  389. s.Alpn = alpn
  390. return nil
  391. }
  392. func (s *SVCBAlpn) parse(b string) error {
  393. if len(b) == 0 {
  394. s.Alpn = []string{}
  395. return nil
  396. }
  397. alpn := []string{}
  398. a := []byte{}
  399. for p := 0; p < len(b); {
  400. c, q := nextByte(b, p)
  401. if q == 0 {
  402. return errors.New("dns: svcbalpn: unterminated escape")
  403. }
  404. p += q
  405. // If we find a comma, we have finished reading an alpn.
  406. if c == ',' {
  407. if len(a) == 0 {
  408. return errors.New("dns: svcbalpn: empty protocol identifier")
  409. }
  410. alpn = append(alpn, string(a))
  411. a = []byte{}
  412. continue
  413. }
  414. // If it's a backslash, we need to handle a comma-separated list.
  415. if c == '\\' {
  416. dc, dq := nextByte(b, p)
  417. if dq == 0 {
  418. return errors.New("dns: svcbalpn: unterminated escape decoding comma-separated list")
  419. }
  420. if dc != '\\' && dc != ',' {
  421. return errors.New("dns: svcbalpn: bad escaped character decoding comma-separated list")
  422. }
  423. p += dq
  424. c = dc
  425. }
  426. a = append(a, c)
  427. }
  428. // Add the final alpn.
  429. if len(a) == 0 {
  430. return errors.New("dns: svcbalpn: last protocol identifier empty")
  431. }
  432. s.Alpn = append(alpn, string(a))
  433. return nil
  434. }
  435. func (s *SVCBAlpn) len() int {
  436. var l int
  437. for _, e := range s.Alpn {
  438. l += 1 + len(e)
  439. }
  440. return l
  441. }
  442. func (s *SVCBAlpn) copy() SVCBKeyValue {
  443. return &SVCBAlpn{
  444. append([]string(nil), s.Alpn...),
  445. }
  446. }
  447. // SVCBNoDefaultAlpn pair signifies no support for default connection protocols.
  448. // Should be used in conjunction with alpn.
  449. // Basic use pattern for creating a no-default-alpn option:
  450. //
  451. // s := &dns.SVCB{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}}
  452. // t := new(dns.SVCBAlpn)
  453. // t.Alpn = []string{"xmpp-client"}
  454. // s.Value = append(s.Value, t)
  455. // e := new(dns.SVCBNoDefaultAlpn)
  456. // s.Value = append(s.Value, e)
  457. type SVCBNoDefaultAlpn struct{}
  458. func (*SVCBNoDefaultAlpn) Key() SVCBKey { return SVCB_NO_DEFAULT_ALPN }
  459. func (*SVCBNoDefaultAlpn) copy() SVCBKeyValue { return &SVCBNoDefaultAlpn{} }
  460. func (*SVCBNoDefaultAlpn) pack() ([]byte, error) { return []byte{}, nil }
  461. func (*SVCBNoDefaultAlpn) String() string { return "" }
  462. func (*SVCBNoDefaultAlpn) len() int { return 0 }
  463. func (*SVCBNoDefaultAlpn) unpack(b []byte) error {
  464. if len(b) != 0 {
  465. return errors.New("dns: svcbnodefaultalpn: no-default-alpn must have no value")
  466. }
  467. return nil
  468. }
  469. func (*SVCBNoDefaultAlpn) parse(b string) error {
  470. if b != "" {
  471. return errors.New("dns: svcbnodefaultalpn: no-default-alpn must have no value")
  472. }
  473. return nil
  474. }
  475. // SVCBPort pair defines the port for connection.
  476. // Basic use pattern for creating a port option:
  477. //
  478. // s := &dns.SVCB{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}}
  479. // e := new(dns.SVCBPort)
  480. // e.Port = 80
  481. // s.Value = append(s.Value, e)
  482. type SVCBPort struct {
  483. Port uint16
  484. }
  485. func (*SVCBPort) Key() SVCBKey { return SVCB_PORT }
  486. func (*SVCBPort) len() int { return 2 }
  487. func (s *SVCBPort) String() string { return strconv.FormatUint(uint64(s.Port), 10) }
  488. func (s *SVCBPort) copy() SVCBKeyValue { return &SVCBPort{s.Port} }
  489. func (s *SVCBPort) unpack(b []byte) error {
  490. if len(b) != 2 {
  491. return errors.New("dns: svcbport: port length is not exactly 2 octets")
  492. }
  493. s.Port = binary.BigEndian.Uint16(b)
  494. return nil
  495. }
  496. func (s *SVCBPort) pack() ([]byte, error) {
  497. b := make([]byte, 2)
  498. binary.BigEndian.PutUint16(b, s.Port)
  499. return b, nil
  500. }
  501. func (s *SVCBPort) parse(b string) error {
  502. port, err := strconv.ParseUint(b, 10, 16)
  503. if err != nil {
  504. return errors.New("dns: svcbport: port out of range")
  505. }
  506. s.Port = uint16(port)
  507. return nil
  508. }
  509. // SVCBIPv4Hint pair suggests an IPv4 address which may be used to open connections
  510. // if A and AAAA record responses for SVCB's Target domain haven't been received.
  511. // In that case, optionally, A and AAAA requests can be made, after which the connection
  512. // to the hinted IP address may be terminated and a new connection may be opened.
  513. // Basic use pattern for creating an ipv4hint option:
  514. //
  515. // h := new(dns.HTTPS)
  516. // h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
  517. // e := new(dns.SVCBIPv4Hint)
  518. // e.Hint = []net.IP{net.IPv4(1,1,1,1).To4()}
  519. //
  520. // Or
  521. //
  522. // e.Hint = []net.IP{net.ParseIP("1.1.1.1").To4()}
  523. // h.Value = append(h.Value, e)
  524. type SVCBIPv4Hint struct {
  525. Hint []net.IP
  526. }
  527. func (*SVCBIPv4Hint) Key() SVCBKey { return SVCB_IPV4HINT }
  528. func (s *SVCBIPv4Hint) len() int { return 4 * len(s.Hint) }
  529. func (s *SVCBIPv4Hint) pack() ([]byte, error) {
  530. b := make([]byte, 0, 4*len(s.Hint))
  531. for _, e := range s.Hint {
  532. x := e.To4()
  533. if x == nil {
  534. return nil, errors.New("dns: svcbipv4hint: expected ipv4, hint is ipv6")
  535. }
  536. b = append(b, x...)
  537. }
  538. return b, nil
  539. }
  540. func (s *SVCBIPv4Hint) unpack(b []byte) error {
  541. if len(b) == 0 || len(b)%4 != 0 {
  542. return errors.New("dns: svcbipv4hint: ipv4 address byte array length is not a multiple of 4")
  543. }
  544. x := make([]net.IP, 0, len(b)/4)
  545. for i := 0; i < len(b); i += 4 {
  546. x = append(x, net.IP(b[i:i+4]))
  547. }
  548. s.Hint = x
  549. return nil
  550. }
  551. func (s *SVCBIPv4Hint) String() string {
  552. str := make([]string, len(s.Hint))
  553. for i, e := range s.Hint {
  554. x := e.To4()
  555. if x == nil {
  556. return "<nil>"
  557. }
  558. str[i] = x.String()
  559. }
  560. return strings.Join(str, ",")
  561. }
  562. func (s *SVCBIPv4Hint) parse(b string) error {
  563. if strings.Contains(b, ":") {
  564. return errors.New("dns: svcbipv4hint: expected ipv4, got ipv6")
  565. }
  566. str := strings.Split(b, ",")
  567. dst := make([]net.IP, len(str))
  568. for i, e := range str {
  569. ip := net.ParseIP(e).To4()
  570. if ip == nil {
  571. return errors.New("dns: svcbipv4hint: bad ip")
  572. }
  573. dst[i] = ip
  574. }
  575. s.Hint = dst
  576. return nil
  577. }
  578. func (s *SVCBIPv4Hint) copy() SVCBKeyValue {
  579. hint := make([]net.IP, len(s.Hint))
  580. for i, ip := range s.Hint {
  581. hint[i] = copyIP(ip)
  582. }
  583. return &SVCBIPv4Hint{
  584. Hint: hint,
  585. }
  586. }
  587. // SVCBECHConfig pair contains the ECHConfig structure defined in draft-ietf-tls-esni [RFC xxxx].
  588. // Basic use pattern for creating an ech option:
  589. //
  590. // h := new(dns.HTTPS)
  591. // h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
  592. // e := new(dns.SVCBECHConfig)
  593. // e.ECH = []byte{0xfe, 0x08, ...}
  594. // h.Value = append(h.Value, e)
  595. type SVCBECHConfig struct {
  596. ECH []byte // Specifically ECHConfigList including the redundant length prefix
  597. }
  598. func (*SVCBECHConfig) Key() SVCBKey { return SVCB_ECHCONFIG }
  599. func (s *SVCBECHConfig) String() string { return toBase64(s.ECH) }
  600. func (s *SVCBECHConfig) len() int { return len(s.ECH) }
  601. func (s *SVCBECHConfig) pack() ([]byte, error) {
  602. return append([]byte(nil), s.ECH...), nil
  603. }
  604. func (s *SVCBECHConfig) copy() SVCBKeyValue {
  605. return &SVCBECHConfig{
  606. append([]byte(nil), s.ECH...),
  607. }
  608. }
  609. func (s *SVCBECHConfig) unpack(b []byte) error {
  610. s.ECH = append([]byte(nil), b...)
  611. return nil
  612. }
  613. func (s *SVCBECHConfig) parse(b string) error {
  614. x, err := fromBase64([]byte(b))
  615. if err != nil {
  616. return errors.New("dns: svcbech: bad base64 ech")
  617. }
  618. s.ECH = x
  619. return nil
  620. }
  621. // SVCBIPv6Hint pair suggests an IPv6 address which may be used to open connections
  622. // if A and AAAA record responses for SVCB's Target domain haven't been received.
  623. // In that case, optionally, A and AAAA requests can be made, after which the
  624. // connection to the hinted IP address may be terminated and a new connection may be opened.
  625. // Basic use pattern for creating an ipv6hint option:
  626. //
  627. // h := new(dns.HTTPS)
  628. // h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
  629. // e := new(dns.SVCBIPv6Hint)
  630. // e.Hint = []net.IP{net.ParseIP("2001:db8::1")}
  631. // h.Value = append(h.Value, e)
  632. type SVCBIPv6Hint struct {
  633. Hint []net.IP
  634. }
  635. func (*SVCBIPv6Hint) Key() SVCBKey { return SVCB_IPV6HINT }
  636. func (s *SVCBIPv6Hint) len() int { return 16 * len(s.Hint) }
  637. func (s *SVCBIPv6Hint) pack() ([]byte, error) {
  638. b := make([]byte, 0, 16*len(s.Hint))
  639. for _, e := range s.Hint {
  640. if len(e) != net.IPv6len || e.To4() != nil {
  641. return nil, errors.New("dns: svcbipv6hint: expected ipv6, hint is ipv4")
  642. }
  643. b = append(b, e...)
  644. }
  645. return b, nil
  646. }
  647. func (s *SVCBIPv6Hint) unpack(b []byte) error {
  648. if len(b) == 0 || len(b)%16 != 0 {
  649. return errors.New("dns: svcbipv6hint: ipv6 address byte array length not a multiple of 16")
  650. }
  651. x := make([]net.IP, 0, len(b)/16)
  652. for i := 0; i < len(b); i += 16 {
  653. ip := net.IP(b[i : i+16])
  654. if ip.To4() != nil {
  655. return errors.New("dns: svcbipv6hint: expected ipv6, got ipv4")
  656. }
  657. x = append(x, ip)
  658. }
  659. s.Hint = x
  660. return nil
  661. }
  662. func (s *SVCBIPv6Hint) String() string {
  663. str := make([]string, len(s.Hint))
  664. for i, e := range s.Hint {
  665. if x := e.To4(); x != nil {
  666. return "<nil>"
  667. }
  668. str[i] = e.String()
  669. }
  670. return strings.Join(str, ",")
  671. }
  672. func (s *SVCBIPv6Hint) parse(b string) error {
  673. str := strings.Split(b, ",")
  674. dst := make([]net.IP, len(str))
  675. for i, e := range str {
  676. ip := net.ParseIP(e)
  677. if ip == nil {
  678. return errors.New("dns: svcbipv6hint: bad ip")
  679. }
  680. if ip.To4() != nil {
  681. return errors.New("dns: svcbipv6hint: expected ipv6, got ipv4-mapped-ipv6")
  682. }
  683. dst[i] = ip
  684. }
  685. s.Hint = dst
  686. return nil
  687. }
  688. func (s *SVCBIPv6Hint) copy() SVCBKeyValue {
  689. hint := make([]net.IP, len(s.Hint))
  690. for i, ip := range s.Hint {
  691. hint[i] = copyIP(ip)
  692. }
  693. return &SVCBIPv6Hint{
  694. Hint: hint,
  695. }
  696. }
  697. // SVCBDoHPath pair is used to indicate the URI template that the
  698. // clients may use to construct a DNS over HTTPS URI.
  699. //
  700. // See RFC xxxx (https://datatracker.ietf.org/doc/html/draft-ietf-add-svcb-dns-02)
  701. // and RFC yyyy (https://datatracker.ietf.org/doc/html/draft-ietf-add-ddr-06).
  702. //
  703. // A basic example of using the dohpath option together with the alpn
  704. // option to indicate support for DNS over HTTPS on a certain path:
  705. //
  706. // s := new(dns.SVCB)
  707. // s.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}
  708. // e := new(dns.SVCBAlpn)
  709. // e.Alpn = []string{"h2", "h3"}
  710. // p := new(dns.SVCBDoHPath)
  711. // p.Template = "/dns-query{?dns}"
  712. // s.Value = append(s.Value, e, p)
  713. //
  714. // The parsing currently doesn't validate that Template is a valid
  715. // RFC 6570 URI template.
  716. type SVCBDoHPath struct {
  717. Template string
  718. }
  719. func (*SVCBDoHPath) Key() SVCBKey { return SVCB_DOHPATH }
  720. func (s *SVCBDoHPath) String() string { return svcbParamToStr([]byte(s.Template)) }
  721. func (s *SVCBDoHPath) len() int { return len(s.Template) }
  722. func (s *SVCBDoHPath) pack() ([]byte, error) { return []byte(s.Template), nil }
  723. func (s *SVCBDoHPath) unpack(b []byte) error {
  724. s.Template = string(b)
  725. return nil
  726. }
  727. func (s *SVCBDoHPath) parse(b string) error {
  728. template, err := svcbParseParam(b)
  729. if err != nil {
  730. return fmt.Errorf("dns: svcbdohpath: %w", err)
  731. }
  732. s.Template = string(template)
  733. return nil
  734. }
  735. func (s *SVCBDoHPath) copy() SVCBKeyValue {
  736. return &SVCBDoHPath{
  737. Template: s.Template,
  738. }
  739. }
  740. // SVCBLocal pair is intended for experimental/private use. The key is recommended
  741. // to be in the range [SVCB_PRIVATE_LOWER, SVCB_PRIVATE_UPPER].
  742. // Basic use pattern for creating a keyNNNNN option:
  743. //
  744. // h := new(dns.HTTPS)
  745. // h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
  746. // e := new(dns.SVCBLocal)
  747. // e.KeyCode = 65400
  748. // e.Data = []byte("abc")
  749. // h.Value = append(h.Value, e)
  750. type SVCBLocal struct {
  751. KeyCode SVCBKey // Never 65535 or any assigned keys.
  752. Data []byte // All byte sequences are allowed.
  753. }
  754. func (s *SVCBLocal) Key() SVCBKey { return s.KeyCode }
  755. func (s *SVCBLocal) String() string { return svcbParamToStr(s.Data) }
  756. func (s *SVCBLocal) pack() ([]byte, error) { return append([]byte(nil), s.Data...), nil }
  757. func (s *SVCBLocal) len() int { return len(s.Data) }
  758. func (s *SVCBLocal) unpack(b []byte) error {
  759. s.Data = append([]byte(nil), b...)
  760. return nil
  761. }
  762. func (s *SVCBLocal) parse(b string) error {
  763. data, err := svcbParseParam(b)
  764. if err != nil {
  765. return fmt.Errorf("dns: svcblocal: svcb private/experimental key %w", err)
  766. }
  767. s.Data = data
  768. return nil
  769. }
  770. func (s *SVCBLocal) copy() SVCBKeyValue {
  771. return &SVCBLocal{s.KeyCode,
  772. append([]byte(nil), s.Data...),
  773. }
  774. }
  775. func (rr *SVCB) String() string {
  776. s := rr.Hdr.String() +
  777. strconv.Itoa(int(rr.Priority)) + " " +
  778. sprintName(rr.Target)
  779. for _, e := range rr.Value {
  780. s += " " + e.Key().String() + "=\"" + e.String() + "\""
  781. }
  782. return s
  783. }
  784. // areSVCBPairArraysEqual checks if SVCBKeyValue arrays are equal after sorting their
  785. // copies. arrA and arrB have equal lengths, otherwise zduplicate.go wouldn't call this function.
  786. func areSVCBPairArraysEqual(a []SVCBKeyValue, b []SVCBKeyValue) bool {
  787. a = append([]SVCBKeyValue(nil), a...)
  788. b = append([]SVCBKeyValue(nil), b...)
  789. sort.Slice(a, func(i, j int) bool { return a[i].Key() < a[j].Key() })
  790. sort.Slice(b, func(i, j int) bool { return b[i].Key() < b[j].Key() })
  791. for i, e := range a {
  792. if e.Key() != b[i].Key() {
  793. return false
  794. }
  795. b1, err1 := e.pack()
  796. b2, err2 := b[i].pack()
  797. if err1 != nil || err2 != nil || !bytes.Equal(b1, b2) {
  798. return false
  799. }
  800. }
  801. return true
  802. }
  803. // svcbParamStr converts the value of an SVCB parameter into a DNS presentation-format string.
  804. func svcbParamToStr(s []byte) string {
  805. var str strings.Builder
  806. str.Grow(4 * len(s))
  807. for _, e := range s {
  808. if ' ' <= e && e <= '~' {
  809. switch e {
  810. case '"', ';', ' ', '\\':
  811. str.WriteByte('\\')
  812. str.WriteByte(e)
  813. default:
  814. str.WriteByte(e)
  815. }
  816. } else {
  817. str.WriteString(escapeByte(e))
  818. }
  819. }
  820. return str.String()
  821. }
  822. // svcbParseParam parses a DNS presentation-format string into an SVCB parameter value.
  823. func svcbParseParam(b string) ([]byte, error) {
  824. data := make([]byte, 0, len(b))
  825. for i := 0; i < len(b); {
  826. if b[i] != '\\' {
  827. data = append(data, b[i])
  828. i++
  829. continue
  830. }
  831. if i+1 == len(b) {
  832. return nil, errors.New("escape unterminated")
  833. }
  834. if isDigit(b[i+1]) {
  835. if i+3 < len(b) && isDigit(b[i+2]) && isDigit(b[i+3]) {
  836. a, err := strconv.ParseUint(b[i+1:i+4], 10, 8)
  837. if err == nil {
  838. i += 4
  839. data = append(data, byte(a))
  840. continue
  841. }
  842. }
  843. return nil, errors.New("bad escaped octet")
  844. } else {
  845. data = append(data, b[i+1])
  846. i += 2
  847. }
  848. }
  849. return data, nil
  850. }