package dnsmessage
import (
)
type SVCBResource struct {
Priority uint16
Target Name
Params []SVCParam
}
func ( *SVCBResource) () Type {
return TypeSVCB
}
func ( *SVCBResource) () string {
:= []byte("dnsmessage.SVCBResource{" +
"Priority: " + printUint16(.Priority) + ", " +
"Target: " + .Target.GoString() + ", " +
"Params: []dnsmessage.SVCParam{")
if len(.Params) > 0 {
= append(, .Params[0].GoString()...)
for , := range .Params[1:] {
= append(, ", "+.GoString()...)
}
}
= append(, "}}"...)
return string()
}
type HTTPSResource struct {
SVCBResource
}
func ( *HTTPSResource) () Type {
return TypeHTTPS
}
func ( *HTTPSResource) () string {
return "dnsmessage.HTTPSResource{SVCBResource: " + .SVCBResource.GoString() + "}"
}
func ( *SVCBResource) ( SVCParamKey) ( []byte, bool) {
for := range .Params {
if .Params[].Key == {
return .Params[].Value, true
}
if .Params[].Key > {
break
}
}
return nil, false
}
func ( *SVCBResource) ( SVCParamKey, []byte) {
:= 0
for < len(.Params) {
if .Params[].Key >= {
break
}
++
}
if < len(.Params) && .Params[].Key == {
.Params[].Value =
return
}
.Params = slices.Insert(.Params, , SVCParam{Key: , Value: })
}
func ( *SVCBResource) ( SVCParamKey) bool {
for := range .Params {
if .Params[].Key == {
.Params = slices.Delete(.Params, , +1)
return true
}
if .Params[].Key > {
break
}
}
return false
}
type SVCParam struct {
Key SVCParamKey
Value []byte
}
func ( SVCParam) () string {
return "dnsmessage.SVCParam{" +
"Key: " + .Key.GoString() + ", " +
"Value: []byte{" + printByteSlice(.Value) + "}}"
}
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
)
var svcParamKeyNames = map[SVCParamKey]string{
SVCParamMandatory: "Mandatory",
SVCParamALPN: "ALPN",
SVCParamNoDefaultALPN: "NoDefaultALPN",
SVCParamPort: "Port",
SVCParamIPv4Hint: "IPv4Hint",
SVCParamECH: "ECH",
SVCParamIPv6Hint: "IPv6Hint",
SVCParamDOHPath: "DOHPath",
SVCParamOHTTP: "OHTTP",
SVCParamTLSSupportedGroups: "TLSSupportedGroups",
}
func ( SVCParamKey) () string {
if , := svcParamKeyNames[]; {
return
}
return printUint16(uint16())
}
func ( SVCParamKey) () string {
if , := svcParamKeyNames[]; {
return "dnsmessage.SVCParam" +
}
return printUint16(uint16())
}
func ( *SVCBResource) ( []byte, map[string]uint16, int) ([]byte, error) {
:=
= packUint16(, .Priority)
, := .Target.pack(, nil, 0)
if != nil {
return , &nestedError{"SVCBResource.Target", }
}
var SVCParamKey
for , := range .Params {
if > 0 && .Key <= {
return , &nestedError{"SVCBResource.Params", errParamOutOfOrder}
}
if len(.Value) > (1<<16)-1 {
return , &nestedError{"SVCBResource.Params", errTooLongSVCBValue}
}
= packUint16(, uint16(.Key))
= packUint16(, uint16(len(.Value)))
= append(, .Value...)
}
return , nil
}
func ( []byte, int, uint16) (SVCBResource, error) {
:= SVCBResource{}
:=
:= + int()
var error
if .Priority, , = unpackUint16(, ); != nil {
return SVCBResource{}, &nestedError{"Priority", }
}
if , = .Target.unpack(, ); != nil {
return SVCBResource{}, &nestedError{"Target", }
}
:= 0
var uint16
=
var uint16
for < {
var , uint16
if , , = unpackUint16(, ); != nil {
return SVCBResource{}, &nestedError{"Params key", }
}
if > 0 && <= {
return SVCBResource{}, &nestedError{"Params", errParamOutOfOrder}
}
if , , = unpackUint16(, ); != nil {
return SVCBResource{}, &nestedError{"Params value length", }
}
if +int() > {
return SVCBResource{}, errResourceLen
}
+=
+= int()
++
}
if != {
return SVCBResource{}, errResourceLen
}
.Params = make([]SVCParam, )
:= make([]byte, )
=
for := 0; < ; ++ {
:= &.Params[]
var , uint16
if , , = unpackUint16(, ); != nil {
return SVCBResource{}, &nestedError{"param key", }
}
.Key = SVCParamKey()
if , , = unpackUint16(, ); != nil {
return SVCBResource{}, &nestedError{"param length", }
}
if copy(, [:+int()]) != int() {
return SVCBResource{}, &nestedError{"param value", errCalcLen}
}
.Value = [::]
= [:]
+= int()
}
return , nil
}
func ( *Parser) ( Type) (SVCBResource, error) {
if !.resHeaderValid || .resHeaderType != {
return SVCBResource{}, ErrNotStarted
}
, := unpackSVCBResource(.msg, .off, .resHeaderLength)
if != nil {
return SVCBResource{},
}
.off += int(.resHeaderLength)
.resHeaderValid = false
.index++
return , nil
}
func ( *Parser) () (SVCBResource, error) {
return .genericSVCBResource(TypeSVCB)
}
func ( *Parser) () (HTTPSResource, error) {
, := .genericSVCBResource(TypeHTTPS)
if != nil {
return HTTPSResource{},
}
return HTTPSResource{}, nil
}
func ( *Builder) ( ResourceHeader, SVCBResource) error {
if := .checkResourceSection(); != nil {
return
}
, , := .pack(.msg, .compression, .start)
if != nil {
return &nestedError{"ResourceHeader", }
}
:= len()
if , = .pack(, .compression, .start); != nil {
return &nestedError{"ResourceBody", }
}
if := .fixLen(, , ); != nil {
return
}
if := .incrementSectionCount(); != nil {
return
}
.msg =
return nil
}
func ( *Builder) ( ResourceHeader, SVCBResource) error {
.Type = .realType()
return .genericSVCBResource(, )
}
func ( *Builder) ( ResourceHeader, HTTPSResource) error {
.Type = .realType()
return .genericSVCBResource(, .SVCBResource)
}