package dnsmessage
import (
"slices"
)
type SVCBResource struct {
Priority uint16
Target Name
Params []SVCParam
}
func (r *SVCBResource ) realType () Type {
return TypeSVCB
}
func (r *SVCBResource ) GoString () string {
b := []byte ("dnsmessage.SVCBResource{" +
"Priority: " + printUint16 (r .Priority ) + ", " +
"Target: " + r .Target .GoString () + ", " +
"Params: []dnsmessage.SVCParam{" )
if len (r .Params ) > 0 {
b = append (b , r .Params [0 ].GoString ()...)
for _ , p := range r .Params [1 :] {
b = append (b , ", " +p .GoString ()...)
}
}
b = append (b , "}}" ...)
return string (b )
}
type HTTPSResource struct {
SVCBResource
}
func (r *HTTPSResource ) realType () Type {
return TypeHTTPS
}
func (r *HTTPSResource ) GoString () string {
return "dnsmessage.HTTPSResource{SVCBResource: " + r .SVCBResource .GoString () + "}"
}
func (r *SVCBResource ) GetParam (key SVCParamKey ) (value []byte , ok bool ) {
for i := range r .Params {
if r .Params [i ].Key == key {
return r .Params [i ].Value , true
}
if r .Params [i ].Key > key {
break
}
}
return nil , false
}
func (r *SVCBResource ) SetParam (key SVCParamKey , value []byte ) {
i := 0
for i < len (r .Params ) {
if r .Params [i ].Key >= key {
break
}
i ++
}
if i < len (r .Params ) && r .Params [i ].Key == key {
r .Params [i ].Value = value
return
}
r .Params = slices .Insert (r .Params , i , SVCParam {Key : key , Value : value })
}
func (r *SVCBResource ) DeleteParam (key SVCParamKey ) bool {
for i := range r .Params {
if r .Params [i ].Key == key {
r .Params = slices .Delete (r .Params , i , i +1 )
return true
}
if r .Params [i ].Key > key {
break
}
}
return false
}
type SVCParam struct {
Key SVCParamKey
Value []byte
}
func (p SVCParam ) GoString () string {
return "dnsmessage.SVCParam{" +
"Key: " + p .Key .GoString () + ", " +
"Value: []byte{" + printByteSlice (p .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 (k SVCParamKey ) String () string {
if n , ok := svcParamKeyNames [k ]; ok {
return n
}
return printUint16 (uint16 (k ))
}
func (k SVCParamKey ) GoString () string {
if n , ok := svcParamKeyNames [k ]; ok {
return "dnsmessage.SVCParam" + n
}
return printUint16 (uint16 (k ))
}
func (r *SVCBResource ) pack (msg []byte , _ map [string ]uint16 , _ int ) ([]byte , error ) {
oldMsg := msg
msg = packUint16 (msg , r .Priority )
msg , err := r .Target .pack (msg , nil , 0 )
if err != nil {
return oldMsg , &nestedError {"SVCBResource.Target" , err }
}
var previousKey SVCParamKey
for i , param := range r .Params {
if i > 0 && param .Key <= previousKey {
return oldMsg , &nestedError {"SVCBResource.Params" , errParamOutOfOrder }
}
if len (param .Value ) > (1 <<16 )-1 {
return oldMsg , &nestedError {"SVCBResource.Params" , errTooLongSVCBValue }
}
msg = packUint16 (msg , uint16 (param .Key ))
msg = packUint16 (msg , uint16 (len (param .Value )))
msg = append (msg , param .Value ...)
}
return msg , nil
}
func unpackSVCBResource(msg []byte , off int , length uint16 ) (SVCBResource , error ) {
r := SVCBResource {}
paramsOff := off
bodyEnd := off + int (length )
var err error
if r .Priority , paramsOff , err = unpackUint16 (msg , paramsOff ); err != nil {
return SVCBResource {}, &nestedError {"Priority" , err }
}
if paramsOff , err = r .Target .unpack (msg , paramsOff ); err != nil {
return SVCBResource {}, &nestedError {"Target" , err }
}
n := 0
var totalValueLen uint16
off = paramsOff
var previousKey uint16
for off < bodyEnd {
var key , len uint16
if key , off , err = unpackUint16 (msg , off ); err != nil {
return SVCBResource {}, &nestedError {"Params key" , err }
}
if n > 0 && key <= previousKey {
return SVCBResource {}, &nestedError {"Params" , errParamOutOfOrder }
}
if len , off , err = unpackUint16 (msg , off ); err != nil {
return SVCBResource {}, &nestedError {"Params value length" , err }
}
if off +int (len ) > bodyEnd {
return SVCBResource {}, errResourceLen
}
totalValueLen += len
off += int (len )
n ++
}
if off != bodyEnd {
return SVCBResource {}, errResourceLen
}
r .Params = make ([]SVCParam , n )
valuesBuf := make ([]byte , totalValueLen )
off = paramsOff
for i := 0 ; i < n ; i ++ {
p := &r .Params [i ]
var key , len uint16
if key , off , err = unpackUint16 (msg , off ); err != nil {
return SVCBResource {}, &nestedError {"param key" , err }
}
p .Key = SVCParamKey (key )
if len , off , err = unpackUint16 (msg , off ); err != nil {
return SVCBResource {}, &nestedError {"param length" , err }
}
if copy (valuesBuf , msg [off :off +int (len )]) != int (len ) {
return SVCBResource {}, &nestedError {"param value" , errCalcLen }
}
p .Value = valuesBuf [:len :len ]
valuesBuf = valuesBuf [len :]
off += int (len )
}
return r , nil
}
func (p *Parser ) genericSVCBResource (svcbType Type ) (SVCBResource , error ) {
if !p .resHeaderValid || p .resHeaderType != svcbType {
return SVCBResource {}, ErrNotStarted
}
r , err := unpackSVCBResource (p .msg , p .off , p .resHeaderLength )
if err != nil {
return SVCBResource {}, err
}
p .off += int (p .resHeaderLength )
p .resHeaderValid = false
p .index ++
return r , nil
}
func (p *Parser ) SVCBResource () (SVCBResource , error ) {
return p .genericSVCBResource (TypeSVCB )
}
func (p *Parser ) HTTPSResource () (HTTPSResource , error ) {
svcb , err := p .genericSVCBResource (TypeHTTPS )
if err != nil {
return HTTPSResource {}, err
}
return HTTPSResource {svcb }, nil
}
func (b *Builder ) genericSVCBResource (h ResourceHeader , r SVCBResource ) error {
if err := b .checkResourceSection (); err != nil {
return err
}
msg , lenOff , err := h .pack (b .msg , b .compression , b .start )
if err != nil {
return &nestedError {"ResourceHeader" , err }
}
preLen := len (msg )
if msg , err = r .pack (msg , b .compression , b .start ); err != nil {
return &nestedError {"ResourceBody" , err }
}
if err := h .fixLen (msg , lenOff , preLen ); err != nil {
return err
}
if err := b .incrementSectionCount (); err != nil {
return err
}
b .msg = msg
return nil
}
func (b *Builder ) SVCBResource (h ResourceHeader , r SVCBResource ) error {
h .Type = r .realType ()
return b .genericSVCBResource (h , r )
}
func (b *Builder ) HTTPSResource (h ResourceHeader , r HTTPSResource ) error {
h .Type = r .realType ()
return b .genericSVCBResource (h , r .SVCBResource )
}
The pages are generated with Golds v0.8.3-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .