From 08c2616301e68a33ab37e37a091130695a3630ac Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 12 Apr 2022 18:49:30 +0300 Subject: [PATCH] Add SVCB dohpath key (#1359) * Add SVCB dohpath key The parameter is being added in [its own IETF draft][1] and also being used in the [IETF draft about Descovery of Designated Resolvers][2]. Additionally, the mappings of the numeric key values to strings are exported, under names consistent with the already existing exported mappings, to make it easier for the clients of the module to validate and print SVCB keys. Testing was done by sending SVCB queries for the "_dns.resolver.arpa" domain to OpenDNS's 146.112.41.2 server. [1]: https://datatracker.ietf.org/doc/html/draft-ietf-add-svcb-dns-02 [2]: https://datatracker.ietf.org/doc/html/draft-ietf-add-ddr-06.html * Fix template length, docs; reverse some changes * Remove incorrect validations; improve docs --- parse_test.go | 2 ++ svcb.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ svcb_test.go | 1 + 3 files changed, 51 insertions(+) diff --git a/parse_test.go b/parse_test.go index 444ac1e5a..07d254bd6 100644 --- a/parse_test.go +++ b/parse_test.go @@ -1652,6 +1652,8 @@ func TestParseSVCB(t *testing.T) { `example.com. SVCB 16 foo.example.org. alpn=h2,h3-19 mandatory=ipv4hint,alpn ipv4hint=192.0.2.1`: `example.com. 3600 IN SVCB 16 foo.example.org. alpn="h2,h3-19" mandatory="ipv4hint,alpn" ipv4hint="192.0.2.1"`, `example.com. SVCB 16 foo.example.org. alpn="f\\\\oo\\,bar,h2"`: `example.com. 3600 IN SVCB 16 foo.example.org. alpn="f\\\\oo\\,bar,h2"`, `example.com. SVCB 16 foo.example.org. alpn=f\\\092oo\092,bar,h2`: `example.com. 3600 IN SVCB 16 foo.example.org. alpn="f\\\092oo\092,bar,h2"`, + // From draft-ietf-add-ddr-06 + `_dns.example.net. SVCB 1 example.net. alpn=h2 dohpath=/dns-query{?dns}`: `_dns.example.net. 3600 IN SVCB 1 example.net. alpn="h2" dohpath="/dns-query{?dns}"`, } for s, o := range svcbs { rr, err := NewRR(s) diff --git a/svcb.go b/svcb.go index ff5e01086..68075e4b5 100644 --- a/svcb.go +++ b/svcb.go @@ -22,6 +22,7 @@ const ( SVCB_IPV4HINT SVCB_ECHCONFIG SVCB_IPV6HINT + SVCB_DOHPATH // draft-ietf-add-svcb-dns-02 Section 9 svcb_RESERVED SVCBKey = 65535 ) @@ -34,6 +35,7 @@ var svcbKeyToStringMap = map[SVCBKey]string{ SVCB_IPV4HINT: "ipv4hint", SVCB_ECHCONFIG: "ech", SVCB_IPV6HINT: "ipv6hint", + SVCB_DOHPATH: "dohpath", } var svcbStringToKeyMap = reverseSVCBKeyMap(svcbKeyToStringMap) @@ -196,6 +198,8 @@ func makeSVCBKeyValue(key SVCBKey) SVCBKeyValue { return new(SVCBECHConfig) case SVCB_IPV6HINT: return new(SVCBIPv6Hint) + case SVCB_DOHPATH: + return new(SVCBDoHPath) case svcb_RESERVED: return nil default: @@ -669,6 +673,50 @@ func (s *SVCBIPv6Hint) copy() SVCBKeyValue { } } +// SVCBDoHPath pair is used to indicate the URI template that the +// clients may use to construct a DNS over HTTPS URI. +// +// See RFC xxxx (https://datatracker.ietf.org/doc/html/draft-ietf-add-svcb-dns-02) +// and RFC yyyy (https://datatracker.ietf.org/doc/html/draft-ietf-add-ddr-06). +// +// A basic example of using the dohpath option together with the alpn +// option to indicate support for DNS over HTTPS on a certain path: +// +// s := new(dns.SVCB) +// s.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET} +// e := new(dns.SVCBAlpn) +// e.Alpn = []string{"h2", "h3"} +// p := new(dns.SVCBDoHPath) +// p.Template = "/dns-query{?dns}" +// s.Value = append(s.Value, e, p) +// +// The parsing currently doesn't validate that Template is a valid +// RFC 6570 URI template. +type SVCBDoHPath struct { + Template string +} + +func (*SVCBDoHPath) Key() SVCBKey { return SVCB_DOHPATH } +func (s *SVCBDoHPath) String() string { return s.Template } +func (s *SVCBDoHPath) len() int { return len(s.Template) } +func (s *SVCBDoHPath) pack() ([]byte, error) { return []byte(s.Template), nil } + +func (s *SVCBDoHPath) unpack(b []byte) error { + s.Template = string(b) + return nil +} + +func (s *SVCBDoHPath) parse(b string) error { + s.Template = b + return nil +} + +func (s *SVCBDoHPath) copy() SVCBKeyValue { + return &SVCBDoHPath{ + Template: s.Template, + } +} + // SVCBLocal pair is intended for experimental/private use. The key is recommended // to be in the range [SVCB_PRIVATE_LOWER, SVCB_PRIVATE_UPPER]. // Basic use pattern for creating a keyNNNNN option: diff --git a/svcb_test.go b/svcb_test.go index 254949954..0f940e7e5 100644 --- a/svcb_test.go +++ b/svcb_test.go @@ -18,6 +18,7 @@ func TestSVCB(t *testing.T) { {`no-default-alpn`, ``}, {`ipv6hint`, `1::4:4:4:4,1::3:3:3:3`}, {`ech`, `YUdWc2JHOD0=`}, + {`dohpath`, `/dns-query{?dns}`}, {`key65000`, `4\ 3`}, {`key65001`, `\"\ `}, {`key65002`, ``},