The new SVCB/HTTPS record has been added in iOS 14 and macOS 11. It would be handy to be able to parse them. The RFC is still a draft though.

https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-01

Comment From: gopherbot

Change https://golang.org/cl/284852 mentions this issue: dns/dnsmessage: add support for draft-ietf-dnsop-svcb-https-01 RR type

Comment From: ianlancetaylor

CC @iangudger

Comment From: fortuna

The SVCB and HTTPS record types are now in a published RFC: https://datatracker.ietf.org/doc/html/rfc9460

Comment From: phuslu

Any updates? Considering go1.23 supports ECH in crypto/tls, the final piece of the puzzle is supporting LookupSVCB/LookupHTTPS in net resolver.

Comment From: eighthave

I'm working with @sftcd on implementing the TLSv1.3 ECH standard as widely as possible (https://defo.ie). We have implemented it in OpenSSL, and are following the boringssl implementation. Then we also implemented it in projects like curl, lighttpd, nginx, apache, etc.

How can I help make HTTPS RR support in Golang happen? None of the current team are Go coders, so we can't just jump in and implement it ourselves. We can consider paying qualified contractors to implement it. We can also support anyone who wants to take this on.

Cloudflare has enabled ECH by default, so there will be many sites to test with. If you're on Matrix, we can help you interactively with any ECH questions or problems: https://matrix.to/#/#ech-dev:matrix.org

Comment From: phuslu

@eighthave Currently I have my own implemented ECH client, it maybe worth take a look. https://github.com/phuslu/fastdns?tab=readme-ov-file#dns-client

Comment From: fortuna

I have prototypes for macOS/iOS, Linux and Android that queries an arbitrary resource record using the system resolver. It's Go code using cgo.

Some observations: - libresolv doesn't work on Android and iOS because you can't query localhost:53. - libresolv is bad, since it's blocking and doesnt' allow for cancellation. - On Android you can call android_res_nquery from C/C++ - Apple was a pain to figure out due to lack of documentation. I found their source code to be helpful and I have pointers in my code. This repo has example clients as well. - I haven't tried Windows yet, but I was going to try the DnsQueryEx api (example).

Edit (2025-03-26): It looks like Go already has syscall.DnsQuery on windows, which is what is used for the TXT record. It uses DnsQuery_W under the hood.

Comment From: ianlancetaylor

The new API in https://go.dev/cl/284852 is:

    TypeSVCB  Type = 64
    TypeHTTPS Type = 65

// SVCBResource parses a single SVCBResource.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) SVCBResource() (SVCBResource, error)

// HTTPSResource parses a single HTTPSResource.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) HTTPSResource() (HTTPSResource, error)

// SVCBResource adds a single SVCBResource.
func (b *Builder) SVCBResource(h ResourceHeader, r SVCBResource) error

// HTTPSResource adds a single HTTPSResource.
func (b *Builder) HTTPSResource(h ResourceHeader, r HTTPSResource) error

// An SVCBResource is an SVCB Resource record.
type SVCBResource struct {
    Priority uint16
    Target   Name
    Params   []Param
}

type ParamKey uint16

const (
    ParamMandatory     ParamKey = 0
    ParamALPN          ParamKey = 1
    ParamNoDefaultALPN ParamKey = 2
    ParamPort          ParamKey = 3
    ParamIPv4Hint      ParamKey = 4
    ParamECHConfig     ParamKey = 5
    ParamIPv6Hint      ParamKey = 6
)

// String implements fmt.Stringer.String.
func (t ParamKey) String() string

// GoString implements fmt.GoStringer.GoString.
func (t ParamKey) GoString() string 

type Param struct {
    Key   ParamKey
    Value []byte
}

func (p Param) GoString() string

// GoString implements fmt.GoStringer.GoString.
func (r *SVCBResource) GoString() string

type HTTPSResource struct {
    Priority uint16
    Target   Name
    Params   []Param
}

// GoString implements fmt.GoStringer.GoString.
func (r *HTTPSResource) GoString() string

Comment From: neild

Is there a reason for having separate SVCBResource and HTTPSResource types? The HTTPS RR type is "SVCB-compatible" and has an identical representation.

It seems like it would be sufficient to have a TypeHTTPS definition, and then use SVCB methods and types.

Comment From: aclements

This proposal has been added to the active column of the proposals project and will now be reviewed at the weekly proposal review meetings. — aclements for the proposal review group

Comment From: neild

General API looks fine to me, but I suggest a couple small changes:

  1. Remove the HTTPSResource type, and use SVCBResource as the type used by Parser.HTTPSResource and Builder.HTTPSResource. The HTTPS RR type is explicitly "SVCB-compatible", so we don't need two types here.
  2. Rename Param* to SVCParam*.

Comment From: fortuna

@neild the HTTPSResource is explicitly a separate type from SVCBResource, they even have different type IDs (65 vs 64, RFC).

I'd rather follow @ianlancetaylor's proposal that keeps them separate. The HTTPS record could leverage the SVCB parsing though.

I like @neild's proposal of renaming Param to SVCParam, to align with the SvcParam language used in the RFC. In that case we would have to rename Priority to SVCPriority and Target to TargetName, in both SVCBResource and HTTPSResource.

Image

cc @bemasc who created the standard and may have some thoughts.

Comment From: bemasc

When writing DNS software related to SVCB/HTTPS records, there are many cases where wants to perform type-independent processing or generation of these record types, so having a unified type would probably be helpful.

Treating Params as []Param may be sensible for performance reasons, but note that the format is designed to support representations like map[ParamKey][]byte (e.g. duplicate keys are forbidden) and this would be more convenient for most applications.

Comment From: neild

HTTPS RRs have a different RR type than SVCB RRs, but they are "SVCB-compatible" (see RFC 9460 section 6) and use the same RDATA presentation format, wire format, SvcParamKeys registry, etc.

I don't see any reason to use a separate type to represent HTTPS RDATA.

In that case we would have to rename Priority to SVCPriority and Target to TargetName, in both SVCBResource and HTTPSResource

The reason to rename Param to SVCParam is because this is an exported type in the dnsmessage package, and it should be distinguished from any other parameter types that might be added to the package. Fields of the SVCBResource struct are scoped to that struct and don't require additional qualification.

That said, using the same names as RFC 9460 seems reasonable.

Comment From: neild

Treating Params as []Param may be sensible for performance reasons, but note that the format is designed to support representations like map[ParamKey][]byte (e.g. duplicate keys are forbidden) and this would be more convenient for most applications.

map[ParamKey][]byte loses the ability to represent the order of keys. While order is not supposed to be important, it seems unfortunate to choose a form which can't fully represent the encoded form of the data.

Perhaps there should be convenience methods for access by ID?

func (r *SVCBResource) GetParam(key SVCParamKey) (_ []byte, ok bool)
func (r *SVCBResource) SetParam(key SVCParamKey, value []byte)

Comment From: fortuna

Treating Params as []Param may be sensible for performance reasons, but note that the format is designed to support representations like map[ParamKey][]byte (e.g. duplicate keys are forbidden) and this would be more convenient for most applications.

I like the idea of using the map instead of a list of parameters or having a method to look them up. Having to iterate over the list is not user-friendly.

But I don't see a need to preserve the encoded order, since it's meaningless, and the standard requires it to be in increasing order by parameter id.

Image

When writing DNS software related to SVCB/HTTPS records, there are many cases where wants to perform type-independent processing or generation of these record types, so having a unified type would probably be helpful.

This makes sense. I worried that perhaps the param keys would be different across different SVCB-compatible types, so we would have dedicated types like HTTPSSVCParamKey. But the standard is generic, and even the registry is across types. So it should be fine to use the SVCBResource for the HTTPS queries.

Comment From: sftcd

Just checking a thing and suggesting a thing to test. The value associated with a ParamECHConfig can have a list of ECHConfig values, that has more than one ECH public key, so I assume the singular name doesn't mean only one ECH public key is supported. WRT tests, we have a bunch of some good, some oddball, HTTPS RRs with ECH configs published below test.defo.ie - you can see a list of those on this web page.

Comment From: bemasc

I think ParamECHConfig should probably be ParamECH to match the parameter's registered display name (which changed from "echconfig" to "ech" before publication).

@sftcd This API treats the SvcParamValue as opaque wire-format bytes, so that distinction is not meaningful here.

Comment From: sftcd

@sftcd This API treats the SvcParamValue as opaque wire-format bytes, so that distinction is not meaningful here.

Sure, I was just wondering if someone's checking end-to-end that this all lines up with with the ECH implementation in golang. I assume that's been done (or will be) but the singular name jumped out and made me ask:--) I also forget if the golang ECH code required a binary ECHConfigList input or if it needed base64. (Again just saying so someone checks, rather than finds out late.)

ParamECH would indeed be a better name also.

Comment From: aclements

Could someone post the API that's being proposed? Thanks.

Comment From: neild

Does this look right?

A few points that have changed from https://go.dev/cl/284852:

  • I dropped the HTTPSResource method from Parser and Builder. Just use SVCBResource for the HTTPS RR type.
  • I renamed ParamKey to SVCParamKey.
  • SVCBResource.Params is now a map.

Making Params a map means we can't represent the order of params, but the SVCB RDATA wire format requires params to appear in strictly increasing numeric order so perhaps that doesn't matter. I'm a little bit uncomfortable about using a map here, since it's going to be a bit less efficient (we'll always need to copy and sort the keys on encoding), but I think the consensus above was tending in this direction.

const (
    TypeSVCB  Type = 64
    TypeHTTPS Type = 65
)

// SVCBResource parses a single SVCBResource.
// The resource type may be TypeSVCB or TypeHTTPS.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) SVCBResource() (SVCBResource, error)

// SVCBResource adds a single SVCBResource.
// The resource type may be TypeSVCB or TypeHTTPS.
func (b *Builder) SVCBResource(h ResourceHeader, r SVCBResource) error

// An SVCBResource is an SVCB Resource record.
type SVCBResource struct {
    Priority uint16
    Target   Name
    Params   map[SVCParamKey][]byte
}

func (r *SVCBResource) GoString() string

type SVCParamKey uint16

const (
    SVCParamMandatory     SVCParamKey = 0
    SVCParamALPN          SVCParamKey = 1
    SVCParamNoDefaultALPN SVCParamKey = 2
    SVCParamPort          SVCParamKey = 3
    SVCParamIPv4Hint      SVCParamKey = 4
    SVCParamECHConfig     SVCParamKey = 5
    SVCParamIPv6Hint      SVCParamKey = 6
)

func (t SVCParamKey) String() string

func (t SVCParamKey) GoString() string 

Comment From: mateusz834

FYI the current API sets implicitly the type for the user:

https://github.com/golang/net/blob/b8d88774daf2a7cf137dad5173fc9bb981fc18fb/dns/dnsmessage/message.go#L1375

What is the (b *Builder) SVCBResource() going to do for the zero value of Type? Return an error? We will cause a inconsistency here.

Also will cause an issue here:

https://github.com/golang/net/blob/b8d88774daf2a7cf137dad5173fc9bb981fc18fb/dns/dnsmessage/message.go#L510

Comment From: mateusz834

Personally i would just share a struct, but duplicate methods for SVCB/HTTPS in Builder and the Parser.

EDIT: not going to help here https://github.com/golang/net/blob/b8d88774daf2a7cf137dad5173fc9bb981fc18fb/dns/dnsmessage/message.go#L510 though.

Comment From: mateusz834

I'm a little bit uncomfortable about using a map here, since it's going to be a bit less efficient (we'll always need to copy and sort the keys on encoding), but I think the consensus above was tending in this direction.

I like the idea of using the map instead of a list of parameters or having a method to look them up. Having to iterate over the list is not user-friendly.

I would vote for a slice in a DNS parser, we could expose a map in the net package. dnsmessage package is not really user-friendly, so i do not buy this argument.

Comment From: neild

Okay, adding the HTTPSResource methods back in:

// HTTPSResource parses a single HTTPS resource as a SVCBResource.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) HTTPSResource() (SVCBResource, error)

// HTTPSResource adds a single SVCBResource as an HTTPS resource.
func (b *Builder) HTTPSResource(h ResourceHeader, r SVCBResource) error

Comment From: mateusz834

@neild I have added an EDIT just as you commented:

https://github.com/golang/go/issues/43790#issuecomment-2790593894

It is not going to help entirely.

Comment From: bemasc

I'm a little bit uncomfortable about using a map here, since it's going to be a bit less efficient (we'll always need to copy and sort the keys on encoding), but I think the consensus above was tending in this direction.

...

I would vote for a slice in a DNS parser, we could expose a map in the net package. dnsmessage package is not really user-friendly, so i do not buy this argument.

I'm happy enough with a map or slice, but note that mis-ordered and duplicate parameters are considered invalid, so someone will have to make sure that they are in-order. If Params is a slice, then the options I see are:

  1. Sort the input before packing (and reject inputs with duplicate SVCParamKeys). (This probably requires a copy; mutating the SVCBResource in SVCBResource.pack() would be unexpected.)
  2. Reject unsorted inputs (and inputs with duplicate SvcParamKeys) in SVCBResource.pack()
  3. Allow the user to serialize invalid RDATA

Option 1 seems no more efficient than a map. Option 3 is fastest but seems error-prone. I would favor slice option 2 or a map.

Comment From: rs

I’d vote for option 2 as it matches the general direction of the library.

Comment From: neild

If Params is a slice, then perhaps sort it when packing, but only if it is not sorted already?

I agree, duplicate entries should be an error.

Comment From: bemasc

@neild Could you clarify: are you proposing that pack() would sort SVCBRecord.Params in-place, or sort a copy?

Comment From: neild

Sort a copy, but don't make a copy if the params are already sorted. I don't think writing a resource should modify it.

Comment From: aclements

It clearly has to reject the slice if it contains duplicates, so I'd lean toward also rejecting it if it's not in order, but I don't feel strongly about that.

Minor clarification: SVCBResource will implement ResourceBody, right? (It's a bit unfortunate that you really can't tell from the godoc what implements ResourceBody.)

Comment From: mateusz834

It seems like my EDIT (https://github.com/golang/go/issues/43790#issuecomment-2790593894) was not yet addresses, so i will mention it again.

If we have only one struct (SVCBResource), like mentioned here (https://github.com/golang/go/issues/43790#issuecomment-2790613868), we are not going to make the Message API work: https://github.com/golang/net/blob/b8d88774daf2a7cf137dad5173fc9bb981fc18fb/dns/dnsmessage/message.go#L510 (or it would have to be inconsistent with other RRs).

Comment From: aclements

If we have only one struct (SVCBResource), like mentioned here (https://github.com/golang/go/issues/43790#issuecomment-2790613868), we are not going to make the Message API work: https://github.com/golang/net/blob/b8d88774daf2a7cf137dad5173fc9bb981fc18fb/dns/dnsmessage/message.go#L510 (or it would have to be inconsistent with other RRs).

Am I understanding correctly that currently all Resource types can return a constant from realType()? So that means we either need two split SVCBResource into two different types solely so they can return different values of Type from realType, or we need to add a field to SVCBResource that specifies its Type?

Comment From: mateusz834

Am I understanding correctly that currently all Resource types can return a constant from realType()? So that means we either need two split SVCBResource into two different types solely so they can return different values of Type from realType, or we need to add a field to SVCBResource that specifies its Type?

Yes, also we could (i think) take the Type from the ResourceHeader instead.

or we need to add a field to SVCBResource that specifies its Type?

Surprisingly https://pkg.go.dev/golang.org/x/net/dns/dnsmessage#UnknownResource uses this approach.

Possibly it could make sense to go with this approach, but i don't see a real reason to avoid adding a separate struct/methods.

Comment From: bemasc

Possibly it could make sense to go with this approach, but i don't see a real reason to avoid adding a separate struct/methods.

If we do have separate structs, I would like them to wrap a shared public struct type like "SVCBCompatibleData" to enable RRType-independent processing code.

Comment From: aclements

I think this is where we are.

I've split SVCBResource and HTTPSResource into two types so they can encode their kind. I used the same underlying type so they can easily be converted back and forth if necessary. This makes it easy to read it as one kind, convert it, then write it back as the other kind and I don't know if that's a good thing or a bad thing.

Params is now a list instead of a map. I pulled it out into its own type so it can have Get/Set convenience methods.

I renamed SVCParamECHConfig to SVCParamECH as mentioned above.

const (
    TypeSVCB  Type = 64
    TypeHTTPS Type = 65
)

// SVCBResource parses a single SVCBResource.
// The resource type must be TypeSVCB.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) SVCBResource() (SVCBResource, error)

// SVCBResource adds a single SVCBResource.
// The resource type may be TypeSVCB or TypeHTTPS.
func (b *Builder) SVCBResource(h ResourceHeader, r SVCBResource) error

// HTTPSResource parses a single HTTPS resource.
// The resource type must be TypeHTTPS.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) HTTPSResource() (HTTPSResource, error)

// HTTPSResource adds a single HTTPSResource.
func (b *Builder) HTTPSResource(h ResourceHeader, r HTTPSResource) error

// An SVCBResource is an SVCB Resource record.
type SVCBResource struct {
    Priority uint16
    Target   Name
    Params   SVCParams // must be in increasing order without duplicates
}

func (r *SVCBResource) GoString() string

// An HTTPSResource is an HTTPS Resource record.
// It is SVCB-compatible and has the same layout, but a
// different type code.
type HTTPSResource SVCBResource

func (r *HTTPSResource) GoString() string

type SVCParams []SVCParam

func (p SVCParams) GetParam(key SVCParamKey) (value []byte, ok bool)
func (p SVCParams) SetParam(key SVCParamKey, value []byte)

type SVCParam struct {
    Key   SVCParamKey
    Value []byte
}

func (p SVCParam) GoString() string

type SVCParamKey uint16

const (
    SVCParamMandatory     SVCParamKey = 0
    SVCParamALPN          SVCParamKey = 1
    SVCParamNoDefaultALPN SVCParamKey = 2
    SVCParamPort          SVCParamKey = 3
    SVCParamIPv4Hint      SVCParamKey = 4
    SVCParamECH           SVCParamKey = 5
    SVCParamIPv6Hint      SVCParamKey = 6
)

func (t SVCParamKey) String() string

func (t SVCParamKey) GoString() string 

Comment From: mateusz834

This needs to have a pointer receiver (to append and reorder (if needed)).

func (p SVCParams) SetParam(key SVCParamKey, value []byte)

Comment From: mateusz834

I used the same underlying type so they can easily be converted back and forth if necessary

Is there a reason not to use struct embeding instead? I wonder what pros/cons are there between both variants.

type HTTPSResource struct { SVCBResource }

Comment From: bemasc

BTW, there are now 3 more registered SvcParamKeys that should go in the const ().

Comment From: aclements

Can someone explain why it's desirable to be able to convert between an SVCB resource and an HTTPS resource? IIUC, HTTPS resource records are a subset of SVCB resource records. Is it a foot-gun to allow easy conversion back and forth?

Comment From: bemasc

Can someone explain why it's desirable to be able to convert between an SVCB resource and an HTTPS resource?

Sure. There are various operations that make sense for SVCB and HTTPS records (and potentially also future SVCB-derived record types like DELEG). Some examples:

func IsAliasMode(record SVCBResource) bool {
  return record.Priority == 0
}

func GetExpandedTarget(record SVCBresource, owner Name) Name {
  if record.Target != "." {
    return record.Target
  }
  return owner
}

func PrioritySort(rrset []SVCBResource) {
  sort.Slice(rrset, func(i, j int) bool { return rrset[i].Priority < rrset[j].Priority })
}

func SVCBLint(rrset []SVCBResource, owner Name) error {
  // Check that the RRSet meets various criteria, e.g.:
  //  - If there is an AliasMode record, len(rrset) == 1
  //  - AliasMode's expanded Target must not match the owner name.
  //  - No duplicated records.
  //  - The SVCParams of each record are internally consistent in various ways.
}

func GetCompatibleRecords(rrset []SVCBResource, autoMandatory []SVCParamKey, supportedKeys []SVCParamKey) []SVCBResource {
  // Skip any records whose SVCParams render it incompatible with this client based on
  // the "automatically mandatory" and supported keys.
}

func DialTLSWithSVCB(dialer *tls.Dialer, rrset []SVCBResource) *tls.Conn {
  // Sort `rrset` in priority order, skip incompatible records, and try each in turn,
  // using the Target and (optionally) SVCParamIPv(4|6)Hint with `dialer.NetDialer`, and
  // the other SVCParams to adjust `dialer.Config`
}

A good API would avoid excessive boilerplate when sharing this kind of functionality across both types.

IIUC, HTTPS resource records are a subset of SVCB resource records. Is it a foot-gun to allow easy conversion back and forth?

I don't think one would ever literally "convert one to the other". However, there are some utilities that don't care about the distinction.

Comment From: aclements

Thanks.

and potentially also future SVCB-derived record types like DELEG

This raises an interesting question of the scalability of the two API approaches. Having different Go types seems reasonable for just one SVCB-derived record type, but IMO it scales somewhat poorly past that. On the other hand, having one Go type with a "Type" field to distinguish different SVCB-derived record types would be trivial to extend to more SVCB-derived record types.

Having a single Go type with a Type field also makes it easier to write the generic SVCB-ish APIs you described, since no Go type conversion is required at all. But it makes it less statically safe to write APIs that must operate only on one type of SVCB record.

I don't think one would ever literally "convert one to the other".

Sorry, by "conversion back and forth", I meant in the Go "explicit type conversion" sense, not in the sense of "receive one on the wire and then intentionally send the other back out."

Comment From: bemasc

Having a single Go type with a Type field also makes it easier to write the generic SVCB-ish APIs you described, since no Go type conversion is required at all. But it makes it less statically safe to write APIs that must operate only on one type of SVCB record.

I agree with your assessment, but an explicit Type field strikes me as undesirable. In ordinary use, it would have to be set every time a SVCBResource or HTTPSResource is created. This seems verbose and error-prone.

For the use cases I've drawn up, separate types seem to be easily tolerated with generics and/or a helper function like

func GetSVCBResources([]HTTPSResource) []SVCBResource

and while I might wish for a way to do that without making a copy, these sorts of operations are generally not performance-sensitive.

Comment From: mateusz834

Aren't we complicating this? This is a parser, in the net package we would certainly make this the same struct type. I don't expect to see much code to use HTTPSResource/SVCBResource directly.

Comment From: aclements

I agree with your assessment, but an explicit Type field strikes me as undesirable.

Okay, it seems like people prefer having separate types.

Aren't we complicating this? This is a parser, in the net package we would certainly make this the same struct type.

We brainstormed on what the net API would look like in proposal review and you're probably right that there would be a single type. net.Resolver doesn't have the Message problem, so it can use one type.

Is there a reason not to use struct embeding instead? I wonder what pros/cons are there between both variants.

We hashed this out in proposal review, and concluded that embedding is actually better. It makes it clearer that HTTPSResource is really a type of SVCBResource. It's still easy to move between the two types, but makes it clear that SVCBResource is the canonical common type. It lets us move the GetParam/SetParam methods up to SVCBResource, where they will be inherited by HTTPSResource. That in turn lets us simplify things by eliminating the SVCParams type.

Putting all that together lands at:

const (
    TypeSVCB  Type = 64
    TypeHTTPS Type = 65
)

// SVCBResource parses a single SVCBResource.
// The resource type must be TypeSVCB.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) SVCBResource() (SVCBResource, error)

// SVCBResource adds a single SVCBResource.
// The resource type may be TypeSVCB or TypeHTTPS.
func (b *Builder) SVCBResource(h ResourceHeader, r SVCBResource) error

// HTTPSResource parses a single HTTPS resource.
// The resource type must be TypeHTTPS.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) HTTPSResource() (HTTPSResource, error)

// HTTPSResource adds a single HTTPSResource.
func (b *Builder) HTTPSResource(h ResourceHeader, r HTTPSResource) error

// An SVCBResource is an SVCB Resource record.
type SVCBResource struct {
    Priority uint16
    Target   Name
    Params   []SVCParam // must be in increasing order without duplicates
}

func (r *SVCBResource) GoString() string
func (r *SVCBResource) GetParam(key SVCParamKey) (value []byte, ok bool)
func (r *SVCBResource) SetParam(key SVCParamKey, value []byte)

// An HTTPSResource is an HTTPS Resource record.
// It is SVCB-compatible and has the same layout, but a
// different type code.
type HTTPSResource struct {
    SVCBResource
}

func (r *HTTPSResource) GoString() string

type SVCParam struct {
    Key   SVCParamKey
    Value []byte
}

func (p SVCParam) GoString() string

type SVCParamKey uint16

const (
    SVCParamMandatory     SVCParamKey = 0
    SVCParamALPN          SVCParamKey = 1
    SVCParamNoDefaultALPN SVCParamKey = 2
    SVCParamPort          SVCParamKey = 3
    SVCParamIPv4Hint      SVCParamKey = 4
    SVCParamECH           SVCParamKey = 5
    SVCParamIPv6Hint      SVCParamKey = 6
    SVCDOHPath            SVCParamKey = 7
    SVCOHTTP              SVCParamKey = 8
    SVCTLSSupportedGroups SVCParamKey = 9
)

func (t SVCParamKey) String() string

func (t SVCParamKey) GoString() string 

Comment From: aclements

Based on the discussion above, this proposal seems like a likely accept. — aclements for the proposal review group

The proposal is to add support for SVCB and HTTPS records to package x/net/dns/dnsmessage with the following API:

const (
    TypeSVCB  Type = 64
    TypeHTTPS Type = 65
)

// SVCBResource parses a single SVCBResource.
// The resource type must be TypeSVCB.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) SVCBResource() (SVCBResource, error)

// SVCBResource adds a single SVCBResource.
// The resource type may be TypeSVCB or TypeHTTPS.
func (b *Builder) SVCBResource(h ResourceHeader, r SVCBResource) error

// HTTPSResource parses a single HTTPS resource.
// The resource type must be TypeHTTPS.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) HTTPSResource() (HTTPSResource, error)

// HTTPSResource adds a single HTTPSResource.
func (b *Builder) HTTPSResource(h ResourceHeader, r HTTPSResource) error

// An SVCBResource is an SVCB Resource record.
type SVCBResource struct {
    Priority uint16
    Target   Name
    Params   []SVCParam // must be in increasing order without duplicates
}

func (r *SVCBResource) GoString() string
func (r *SVCBResource) GetParam(key SVCParamKey) (value []byte, ok bool)
func (r *SVCBResource) SetParam(key SVCParamKey, value []byte)

// An HTTPSResource is an HTTPS Resource record.
// It is SVCB-compatible and has the same layout, but a
// different type code.
type HTTPSResource struct {
    SVCBResource
}

func (r *HTTPSResource) GoString() string

type SVCParam struct {
    Key   SVCParamKey
    Value []byte
}

func (p SVCParam) GoString() string

type SVCParamKey uint16

const (
    SVCParamMandatory          SVCParamKey = 0
    SVCParamALPN               SVCParamKey = 1
    SVCParamNoDefaultALPN      SVCParamKey = 2
    SVCParamPort               SVCParamKey = 3
    SVCParamIPv4Hint           SVCParamKey = 4
    SVCParamECH                SVCParamKey = 5
    SVCParamIPv6Hint           SVCParamKey = 6
    SVCParamDOHPath            SVCParamKey = 7
    SVCParamOHTTP              SVCParamKey = 8
    SVCParamTLSSupportedGroups SVCParamKey = 9
)

func (t SVCParamKey) String() string

func (t SVCParamKey) GoString() string

Comment From: aclements

No change in consensus, so accepted. šŸŽ‰ This issue now tracks the work of implementing the proposal. — aclements for the proposal review group

The proposal is to add support for SVCB and HTTPS records to package x/net/dns/dnsmessage with the following API:

const (
    TypeSVCB  Type = 64
    TypeHTTPS Type = 65
)

// SVCBResource parses a single SVCBResource.
// The resource type must be TypeSVCB.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) SVCBResource() (SVCBResource, error)

// SVCBResource adds a single SVCBResource.
// The resource type may be TypeSVCB or TypeHTTPS.
func (b *Builder) SVCBResource(h ResourceHeader, r SVCBResource) error

// HTTPSResource parses a single HTTPS resource.
// The resource type must be TypeHTTPS.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) HTTPSResource() (HTTPSResource, error)

// HTTPSResource adds a single HTTPSResource.
func (b *Builder) HTTPSResource(h ResourceHeader, r HTTPSResource) error

// An SVCBResource is an SVCB Resource record.
type SVCBResource struct {
    Priority uint16
    Target   Name
    Params   []SVCParam // must be in increasing order without duplicates
}

func (r *SVCBResource) GoString() string
func (r *SVCBResource) GetParam(key SVCParamKey) (value []byte, ok bool)
func (r *SVCBResource) SetParam(key SVCParamKey, value []byte)

// An HTTPSResource is an HTTPS Resource record.
// It is SVCB-compatible and has the same layout, but a
// different type code.
type HTTPSResource struct {
    SVCBResource
}

func (r *HTTPSResource) GoString() string

type SVCParam struct {
    Key   SVCParamKey
    Value []byte
}

func (p SVCParam) GoString() string

type SVCParamKey uint16

const (
    SVCParamMandatory          SVCParamKey = 0
    SVCParamALPN               SVCParamKey = 1
    SVCParamNoDefaultALPN      SVCParamKey = 2
    SVCParamPort               SVCParamKey = 3
    SVCParamIPv4Hint           SVCParamKey = 4
    SVCParamECH                SVCParamKey = 5
    SVCParamIPv6Hint           SVCParamKey = 6
    SVCParamDOHPath            SVCParamKey = 7
    SVCParamOHTTP              SVCParamKey = 8
    SVCParamTLSSupportedGroups SVCParamKey = 9
)

func (t SVCParamKey) String() string

func (t SVCParamKey) GoString() string