svcb.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924
  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 := cloneSlice(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{cloneSlice(s.Code)}
  300. }
  301. // SVCBAlpn pair is used to list supported connection protocols.
  302. // The user of this library must ensure that at least one protocol is listed when alpn is present.
  303. // Protocol IDs can be found at:
  304. // https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
  305. // Basic use pattern for creating an alpn option:
  306. //
  307. // h := new(dns.HTTPS)
  308. // h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
  309. // e := new(dns.SVCBAlpn)
  310. // e.Alpn = []string{"h2", "http/1.1"}
  311. // h.Value = append(h.Value, e)
  312. type SVCBAlpn struct {
  313. Alpn []string
  314. }
  315. func (*SVCBAlpn) Key() SVCBKey { return SVCB_ALPN }
  316. func (s *SVCBAlpn) String() string {
  317. // An ALPN value is a comma-separated list of values, each of which can be
  318. // an arbitrary binary value. In order to allow parsing, the comma and
  319. // backslash characters are themselves escaped.
  320. //
  321. // However, this escaping is done in addition to the normal escaping which
  322. // happens in zone files, meaning that these values must be
  323. // double-escaped. This looks terrible, so if you see a never-ending
  324. // sequence of backslash in a zone file this may be why.
  325. //
  326. // https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-08#appendix-A.1
  327. var str strings.Builder
  328. for i, alpn := range s.Alpn {
  329. // 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
  330. str.Grow(4*len(alpn) + 1)
  331. if i > 0 {
  332. str.WriteByte(',')
  333. }
  334. for j := 0; j < len(alpn); j++ {
  335. e := alpn[j]
  336. if ' ' > e || e > '~' {
  337. str.WriteString(escapeByte(e))
  338. continue
  339. }
  340. switch e {
  341. // We escape a few characters which may confuse humans or parsers.
  342. case '"', ';', ' ':
  343. str.WriteByte('\\')
  344. str.WriteByte(e)
  345. // The comma and backslash characters themselves must be
  346. // doubly-escaped. We use `\\` for the first backslash and
  347. // the escaped numeric value for the other value. We especially
  348. // don't want a comma in the output.
  349. case ',':
  350. str.WriteString(`\\\044`)
  351. case '\\':
  352. str.WriteString(`\\\092`)
  353. default:
  354. str.WriteByte(e)
  355. }
  356. }
  357. }
  358. return str.String()
  359. }
  360. func (s *SVCBAlpn) pack() ([]byte, error) {
  361. // Liberally estimate the size of an alpn as 10 octets
  362. b := make([]byte, 0, 10*len(s.Alpn))
  363. for _, e := range s.Alpn {
  364. if e == "" {
  365. return nil, errors.New("dns: svcbalpn: empty alpn-id")
  366. }
  367. if len(e) > 255 {
  368. return nil, errors.New("dns: svcbalpn: alpn-id too long")
  369. }
  370. b = append(b, byte(len(e)))
  371. b = append(b, e...)
  372. }
  373. return b, nil
  374. }
  375. func (s *SVCBAlpn) unpack(b []byte) error {
  376. // Estimate the size of the smallest alpn as 4 bytes
  377. alpn := make([]string, 0, len(b)/4)
  378. for i := 0; i < len(b); {
  379. length := int(b[i])
  380. i++
  381. if i+length > len(b) {
  382. return errors.New("dns: svcbalpn: alpn array overflowing")
  383. }
  384. alpn = append(alpn, string(b[i:i+length]))
  385. i += length
  386. }
  387. s.Alpn = alpn
  388. return nil
  389. }
  390. func (s *SVCBAlpn) parse(b string) error {
  391. if len(b) == 0 {
  392. s.Alpn = []string{}
  393. return nil
  394. }
  395. alpn := []string{}
  396. a := []byte{}
  397. for p := 0; p < len(b); {
  398. c, q := nextByte(b, p)
  399. if q == 0 {
  400. return errors.New("dns: svcbalpn: unterminated escape")
  401. }
  402. p += q
  403. // If we find a comma, we have finished reading an alpn.
  404. if c == ',' {
  405. if len(a) == 0 {
  406. return errors.New("dns: svcbalpn: empty protocol identifier")
  407. }
  408. alpn = append(alpn, string(a))
  409. a = []byte{}
  410. continue
  411. }
  412. // If it's a backslash, we need to handle a comma-separated list.
  413. if c == '\\' {
  414. dc, dq := nextByte(b, p)
  415. if dq == 0 {
  416. return errors.New("dns: svcbalpn: unterminated escape decoding comma-separated list")
  417. }
  418. if dc != '\\' && dc != ',' {
  419. return errors.New("dns: svcbalpn: bad escaped character decoding comma-separated list")
  420. }
  421. p += dq
  422. c = dc
  423. }
  424. a = append(a, c)
  425. }
  426. // Add the final alpn.
  427. if len(a) == 0 {
  428. return errors.New("dns: svcbalpn: last protocol identifier empty")
  429. }
  430. s.Alpn = append(alpn, string(a))
  431. return nil
  432. }
  433. func (s *SVCBAlpn) len() int {
  434. var l int
  435. for _, e := range s.Alpn {
  436. l += 1 + len(e)
  437. }
  438. return l
  439. }
  440. func (s *SVCBAlpn) copy() SVCBKeyValue {
  441. return &SVCBAlpn{cloneSlice(s.Alpn)}
  442. }
  443. // SVCBNoDefaultAlpn pair signifies no support for default connection protocols.
  444. // Should be used in conjunction with alpn.
  445. // Basic use pattern for creating a no-default-alpn option:
  446. //
  447. // s := &dns.SVCB{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}}
  448. // t := new(dns.SVCBAlpn)
  449. // t.Alpn = []string{"xmpp-client"}
  450. // s.Value = append(s.Value, t)
  451. // e := new(dns.SVCBNoDefaultAlpn)
  452. // s.Value = append(s.Value, e)
  453. type SVCBNoDefaultAlpn struct{}
  454. func (*SVCBNoDefaultAlpn) Key() SVCBKey { return SVCB_NO_DEFAULT_ALPN }
  455. func (*SVCBNoDefaultAlpn) copy() SVCBKeyValue { return &SVCBNoDefaultAlpn{} }
  456. func (*SVCBNoDefaultAlpn) pack() ([]byte, error) { return []byte{}, nil }
  457. func (*SVCBNoDefaultAlpn) String() string { return "" }
  458. func (*SVCBNoDefaultAlpn) len() int { return 0 }
  459. func (*SVCBNoDefaultAlpn) unpack(b []byte) error {
  460. if len(b) != 0 {
  461. return errors.New("dns: svcbnodefaultalpn: no-default-alpn must have no value")
  462. }
  463. return nil
  464. }
  465. func (*SVCBNoDefaultAlpn) parse(b string) error {
  466. if b != "" {
  467. return errors.New("dns: svcbnodefaultalpn: no-default-alpn must have no value")
  468. }
  469. return nil
  470. }
  471. // SVCBPort pair defines the port for connection.
  472. // Basic use pattern for creating a port option:
  473. //
  474. // s := &dns.SVCB{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}}
  475. // e := new(dns.SVCBPort)
  476. // e.Port = 80
  477. // s.Value = append(s.Value, e)
  478. type SVCBPort struct {
  479. Port uint16
  480. }
  481. func (*SVCBPort) Key() SVCBKey { return SVCB_PORT }
  482. func (*SVCBPort) len() int { return 2 }
  483. func (s *SVCBPort) String() string { return strconv.FormatUint(uint64(s.Port), 10) }
  484. func (s *SVCBPort) copy() SVCBKeyValue { return &SVCBPort{s.Port} }
  485. func (s *SVCBPort) unpack(b []byte) error {
  486. if len(b) != 2 {
  487. return errors.New("dns: svcbport: port length is not exactly 2 octets")
  488. }
  489. s.Port = binary.BigEndian.Uint16(b)
  490. return nil
  491. }
  492. func (s *SVCBPort) pack() ([]byte, error) {
  493. b := make([]byte, 2)
  494. binary.BigEndian.PutUint16(b, s.Port)
  495. return b, nil
  496. }
  497. func (s *SVCBPort) parse(b string) error {
  498. port, err := strconv.ParseUint(b, 10, 16)
  499. if err != nil {
  500. return errors.New("dns: svcbport: port out of range")
  501. }
  502. s.Port = uint16(port)
  503. return nil
  504. }
  505. // SVCBIPv4Hint pair suggests an IPv4 address which may be used to open connections
  506. // if A and AAAA record responses for SVCB's Target domain haven't been received.
  507. // In that case, optionally, A and AAAA requests can be made, after which the connection
  508. // to the hinted IP address may be terminated and a new connection may be opened.
  509. // Basic use pattern for creating an ipv4hint option:
  510. //
  511. // h := new(dns.HTTPS)
  512. // h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
  513. // e := new(dns.SVCBIPv4Hint)
  514. // e.Hint = []net.IP{net.IPv4(1,1,1,1).To4()}
  515. //
  516. // Or
  517. //
  518. // e.Hint = []net.IP{net.ParseIP("1.1.1.1").To4()}
  519. // h.Value = append(h.Value, e)
  520. type SVCBIPv4Hint struct {
  521. Hint []net.IP
  522. }
  523. func (*SVCBIPv4Hint) Key() SVCBKey { return SVCB_IPV4HINT }
  524. func (s *SVCBIPv4Hint) len() int { return 4 * len(s.Hint) }
  525. func (s *SVCBIPv4Hint) pack() ([]byte, error) {
  526. b := make([]byte, 0, 4*len(s.Hint))
  527. for _, e := range s.Hint {
  528. x := e.To4()
  529. if x == nil {
  530. return nil, errors.New("dns: svcbipv4hint: expected ipv4, hint is ipv6")
  531. }
  532. b = append(b, x...)
  533. }
  534. return b, nil
  535. }
  536. func (s *SVCBIPv4Hint) unpack(b []byte) error {
  537. if len(b) == 0 || len(b)%4 != 0 {
  538. return errors.New("dns: svcbipv4hint: ipv4 address byte array length is not a multiple of 4")
  539. }
  540. b = cloneSlice(b)
  541. x := make([]net.IP, 0, len(b)/4)
  542. for i := 0; i < len(b); i += 4 {
  543. x = append(x, net.IP(b[i:i+4]))
  544. }
  545. s.Hint = x
  546. return nil
  547. }
  548. func (s *SVCBIPv4Hint) String() string {
  549. str := make([]string, len(s.Hint))
  550. for i, e := range s.Hint {
  551. x := e.To4()
  552. if x == nil {
  553. return "<nil>"
  554. }
  555. str[i] = x.String()
  556. }
  557. return strings.Join(str, ",")
  558. }
  559. func (s *SVCBIPv4Hint) parse(b string) error {
  560. if strings.Contains(b, ":") {
  561. return errors.New("dns: svcbipv4hint: expected ipv4, got ipv6")
  562. }
  563. str := strings.Split(b, ",")
  564. dst := make([]net.IP, len(str))
  565. for i, e := range str {
  566. ip := net.ParseIP(e).To4()
  567. if ip == nil {
  568. return errors.New("dns: svcbipv4hint: bad ip")
  569. }
  570. dst[i] = ip
  571. }
  572. s.Hint = dst
  573. return nil
  574. }
  575. func (s *SVCBIPv4Hint) copy() SVCBKeyValue {
  576. hint := make([]net.IP, len(s.Hint))
  577. for i, ip := range s.Hint {
  578. hint[i] = cloneSlice(ip)
  579. }
  580. return &SVCBIPv4Hint{Hint: hint}
  581. }
  582. // SVCBECHConfig pair contains the ECHConfig structure defined in draft-ietf-tls-esni [RFC xxxx].
  583. // Basic use pattern for creating an ech option:
  584. //
  585. // h := new(dns.HTTPS)
  586. // h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
  587. // e := new(dns.SVCBECHConfig)
  588. // e.ECH = []byte{0xfe, 0x08, ...}
  589. // h.Value = append(h.Value, e)
  590. type SVCBECHConfig struct {
  591. ECH []byte // Specifically ECHConfigList including the redundant length prefix
  592. }
  593. func (*SVCBECHConfig) Key() SVCBKey { return SVCB_ECHCONFIG }
  594. func (s *SVCBECHConfig) String() string { return toBase64(s.ECH) }
  595. func (s *SVCBECHConfig) len() int { return len(s.ECH) }
  596. func (s *SVCBECHConfig) pack() ([]byte, error) {
  597. return cloneSlice(s.ECH), nil
  598. }
  599. func (s *SVCBECHConfig) copy() SVCBKeyValue {
  600. return &SVCBECHConfig{cloneSlice(s.ECH)}
  601. }
  602. func (s *SVCBECHConfig) unpack(b []byte) error {
  603. s.ECH = cloneSlice(b)
  604. return nil
  605. }
  606. func (s *SVCBECHConfig) parse(b string) error {
  607. x, err := fromBase64([]byte(b))
  608. if err != nil {
  609. return errors.New("dns: svcbech: bad base64 ech")
  610. }
  611. s.ECH = x
  612. return nil
  613. }
  614. // SVCBIPv6Hint pair suggests an IPv6 address which may be used to open connections
  615. // if A and AAAA record responses for SVCB's Target domain haven't been received.
  616. // In that case, optionally, A and AAAA requests can be made, after which the
  617. // connection to the hinted IP address may be terminated and a new connection may be opened.
  618. // Basic use pattern for creating an ipv6hint option:
  619. //
  620. // h := new(dns.HTTPS)
  621. // h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
  622. // e := new(dns.SVCBIPv6Hint)
  623. // e.Hint = []net.IP{net.ParseIP("2001:db8::1")}
  624. // h.Value = append(h.Value, e)
  625. type SVCBIPv6Hint struct {
  626. Hint []net.IP
  627. }
  628. func (*SVCBIPv6Hint) Key() SVCBKey { return SVCB_IPV6HINT }
  629. func (s *SVCBIPv6Hint) len() int { return 16 * len(s.Hint) }
  630. func (s *SVCBIPv6Hint) pack() ([]byte, error) {
  631. b := make([]byte, 0, 16*len(s.Hint))
  632. for _, e := range s.Hint {
  633. if len(e) != net.IPv6len || e.To4() != nil {
  634. return nil, errors.New("dns: svcbipv6hint: expected ipv6, hint is ipv4")
  635. }
  636. b = append(b, e...)
  637. }
  638. return b, nil
  639. }
  640. func (s *SVCBIPv6Hint) unpack(b []byte) error {
  641. if len(b) == 0 || len(b)%16 != 0 {
  642. return errors.New("dns: svcbipv6hint: ipv6 address byte array length not a multiple of 16")
  643. }
  644. b = cloneSlice(b)
  645. x := make([]net.IP, 0, len(b)/16)
  646. for i := 0; i < len(b); i += 16 {
  647. ip := net.IP(b[i : i+16])
  648. if ip.To4() != nil {
  649. return errors.New("dns: svcbipv6hint: expected ipv6, got ipv4")
  650. }
  651. x = append(x, ip)
  652. }
  653. s.Hint = x
  654. return nil
  655. }
  656. func (s *SVCBIPv6Hint) String() string {
  657. str := make([]string, len(s.Hint))
  658. for i, e := range s.Hint {
  659. if x := e.To4(); x != nil {
  660. return "<nil>"
  661. }
  662. str[i] = e.String()
  663. }
  664. return strings.Join(str, ",")
  665. }
  666. func (s *SVCBIPv6Hint) parse(b string) error {
  667. str := strings.Split(b, ",")
  668. dst := make([]net.IP, len(str))
  669. for i, e := range str {
  670. ip := net.ParseIP(e)
  671. if ip == nil {
  672. return errors.New("dns: svcbipv6hint: bad ip")
  673. }
  674. if ip.To4() != nil {
  675. return errors.New("dns: svcbipv6hint: expected ipv6, got ipv4-mapped-ipv6")
  676. }
  677. dst[i] = ip
  678. }
  679. s.Hint = dst
  680. return nil
  681. }
  682. func (s *SVCBIPv6Hint) copy() SVCBKeyValue {
  683. hint := make([]net.IP, len(s.Hint))
  684. for i, ip := range s.Hint {
  685. hint[i] = cloneSlice(ip)
  686. }
  687. return &SVCBIPv6Hint{Hint: hint}
  688. }
  689. // SVCBDoHPath pair is used to indicate the URI template that the
  690. // clients may use to construct a DNS over HTTPS URI.
  691. //
  692. // See RFC xxxx (https://datatracker.ietf.org/doc/html/draft-ietf-add-svcb-dns-02)
  693. // and RFC yyyy (https://datatracker.ietf.org/doc/html/draft-ietf-add-ddr-06).
  694. //
  695. // A basic example of using the dohpath option together with the alpn
  696. // option to indicate support for DNS over HTTPS on a certain path:
  697. //
  698. // s := new(dns.SVCB)
  699. // s.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}
  700. // e := new(dns.SVCBAlpn)
  701. // e.Alpn = []string{"h2", "h3"}
  702. // p := new(dns.SVCBDoHPath)
  703. // p.Template = "/dns-query{?dns}"
  704. // s.Value = append(s.Value, e, p)
  705. //
  706. // The parsing currently doesn't validate that Template is a valid
  707. // RFC 6570 URI template.
  708. type SVCBDoHPath struct {
  709. Template string
  710. }
  711. func (*SVCBDoHPath) Key() SVCBKey { return SVCB_DOHPATH }
  712. func (s *SVCBDoHPath) String() string { return svcbParamToStr([]byte(s.Template)) }
  713. func (s *SVCBDoHPath) len() int { return len(s.Template) }
  714. func (s *SVCBDoHPath) pack() ([]byte, error) { return []byte(s.Template), nil }
  715. func (s *SVCBDoHPath) unpack(b []byte) error {
  716. s.Template = string(b)
  717. return nil
  718. }
  719. func (s *SVCBDoHPath) parse(b string) error {
  720. template, err := svcbParseParam(b)
  721. if err != nil {
  722. return fmt.Errorf("dns: svcbdohpath: %w", err)
  723. }
  724. s.Template = string(template)
  725. return nil
  726. }
  727. func (s *SVCBDoHPath) copy() SVCBKeyValue {
  728. return &SVCBDoHPath{
  729. Template: s.Template,
  730. }
  731. }
  732. // SVCBLocal pair is intended for experimental/private use. The key is recommended
  733. // to be in the range [SVCB_PRIVATE_LOWER, SVCB_PRIVATE_UPPER].
  734. // Basic use pattern for creating a keyNNNNN option:
  735. //
  736. // h := new(dns.HTTPS)
  737. // h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
  738. // e := new(dns.SVCBLocal)
  739. // e.KeyCode = 65400
  740. // e.Data = []byte("abc")
  741. // h.Value = append(h.Value, e)
  742. type SVCBLocal struct {
  743. KeyCode SVCBKey // Never 65535 or any assigned keys.
  744. Data []byte // All byte sequences are allowed.
  745. }
  746. func (s *SVCBLocal) Key() SVCBKey { return s.KeyCode }
  747. func (s *SVCBLocal) String() string { return svcbParamToStr(s.Data) }
  748. func (s *SVCBLocal) pack() ([]byte, error) { return cloneSlice(s.Data), nil }
  749. func (s *SVCBLocal) len() int { return len(s.Data) }
  750. func (s *SVCBLocal) unpack(b []byte) error {
  751. s.Data = cloneSlice(b)
  752. return nil
  753. }
  754. func (s *SVCBLocal) parse(b string) error {
  755. data, err := svcbParseParam(b)
  756. if err != nil {
  757. return fmt.Errorf("dns: svcblocal: svcb private/experimental key %w", err)
  758. }
  759. s.Data = data
  760. return nil
  761. }
  762. func (s *SVCBLocal) copy() SVCBKeyValue {
  763. return &SVCBLocal{s.KeyCode, cloneSlice(s.Data)}
  764. }
  765. func (rr *SVCB) String() string {
  766. s := rr.Hdr.String() +
  767. strconv.Itoa(int(rr.Priority)) + " " +
  768. sprintName(rr.Target)
  769. for _, e := range rr.Value {
  770. s += " " + e.Key().String() + "=\"" + e.String() + "\""
  771. }
  772. return s
  773. }
  774. // areSVCBPairArraysEqual checks if SVCBKeyValue arrays are equal after sorting their
  775. // copies. arrA and arrB have equal lengths, otherwise zduplicate.go wouldn't call this function.
  776. func areSVCBPairArraysEqual(a []SVCBKeyValue, b []SVCBKeyValue) bool {
  777. a = cloneSlice(a)
  778. b = cloneSlice(b)
  779. sort.Slice(a, func(i, j int) bool { return a[i].Key() < a[j].Key() })
  780. sort.Slice(b, func(i, j int) bool { return b[i].Key() < b[j].Key() })
  781. for i, e := range a {
  782. if e.Key() != b[i].Key() {
  783. return false
  784. }
  785. b1, err1 := e.pack()
  786. b2, err2 := b[i].pack()
  787. if err1 != nil || err2 != nil || !bytes.Equal(b1, b2) {
  788. return false
  789. }
  790. }
  791. return true
  792. }
  793. // svcbParamStr converts the value of an SVCB parameter into a DNS presentation-format string.
  794. func svcbParamToStr(s []byte) string {
  795. var str strings.Builder
  796. str.Grow(4 * len(s))
  797. for _, e := range s {
  798. if ' ' <= e && e <= '~' {
  799. switch e {
  800. case '"', ';', ' ', '\\':
  801. str.WriteByte('\\')
  802. str.WriteByte(e)
  803. default:
  804. str.WriteByte(e)
  805. }
  806. } else {
  807. str.WriteString(escapeByte(e))
  808. }
  809. }
  810. return str.String()
  811. }
  812. // svcbParseParam parses a DNS presentation-format string into an SVCB parameter value.
  813. func svcbParseParam(b string) ([]byte, error) {
  814. data := make([]byte, 0, len(b))
  815. for i := 0; i < len(b); {
  816. if b[i] != '\\' {
  817. data = append(data, b[i])
  818. i++
  819. continue
  820. }
  821. if i+1 == len(b) {
  822. return nil, errors.New("escape unterminated")
  823. }
  824. if isDigit(b[i+1]) {
  825. if i+3 < len(b) && isDigit(b[i+2]) && isDigit(b[i+3]) {
  826. a, err := strconv.ParseUint(b[i+1:i+4], 10, 8)
  827. if err == nil {
  828. i += 4
  829. data = append(data, byte(a))
  830. continue
  831. }
  832. }
  833. return nil, errors.New("bad escaped octet")
  834. } else {
  835. data = append(data, b[i+1])
  836. i += 2
  837. }
  838. }
  839. return data, nil
  840. }