1
2
3
4
5 package dnsmessage
6
7 import (
8 "slices"
9 )
10
11
12 type SVCBResource struct {
13 Priority uint16
14 Target Name
15 Params []SVCParam
16 }
17
18 func (r *SVCBResource) realType() Type {
19 return TypeSVCB
20 }
21
22
23 func (r *SVCBResource) GoString() string {
24 b := []byte("dnsmessage.SVCBResource{" +
25 "Priority: " + printUint16(r.Priority) + ", " +
26 "Target: " + r.Target.GoString() + ", " +
27 "Params: []dnsmessage.SVCParam{")
28 if len(r.Params) > 0 {
29 b = append(b, r.Params[0].GoString()...)
30 for _, p := range r.Params[1:] {
31 b = append(b, ", "+p.GoString()...)
32 }
33 }
34 b = append(b, "}}"...)
35 return string(b)
36 }
37
38
39
40 type HTTPSResource struct {
41
42 SVCBResource
43 }
44
45 func (r *HTTPSResource) realType() Type {
46 return TypeHTTPS
47 }
48
49
50 func (r *HTTPSResource) GoString() string {
51 return "dnsmessage.HTTPSResource{SVCBResource: " + r.SVCBResource.GoString() + "}"
52 }
53
54
55 func (r *SVCBResource) GetParam(key SVCParamKey) (value []byte, ok bool) {
56 for i := range r.Params {
57 if r.Params[i].Key == key {
58 return r.Params[i].Value, true
59 }
60 if r.Params[i].Key > key {
61 break
62 }
63 }
64 return nil, false
65 }
66
67
68
69 func (r *SVCBResource) SetParam(key SVCParamKey, value []byte) {
70 i := 0
71 for i < len(r.Params) {
72 if r.Params[i].Key >= key {
73 break
74 }
75 i++
76 }
77
78 if i < len(r.Params) && r.Params[i].Key == key {
79 r.Params[i].Value = value
80 return
81 }
82
83 r.Params = slices.Insert(r.Params, i, SVCParam{Key: key, Value: value})
84 }
85
86
87
88 func (r *SVCBResource) DeleteParam(key SVCParamKey) bool {
89 for i := range r.Params {
90 if r.Params[i].Key == key {
91 r.Params = slices.Delete(r.Params, i, i+1)
92 return true
93 }
94 if r.Params[i].Key > key {
95 break
96 }
97 }
98 return false
99 }
100
101
102 type SVCParam struct {
103 Key SVCParamKey
104 Value []byte
105 }
106
107
108 func (p SVCParam) GoString() string {
109 return "dnsmessage.SVCParam{" +
110 "Key: " + p.Key.GoString() + ", " +
111 "Value: []byte{" + printByteSlice(p.Value) + "}}"
112 }
113
114
115 type SVCParamKey uint16
116
117
118 const (
119 SVCParamMandatory SVCParamKey = 0
120 SVCParamALPN SVCParamKey = 1
121 SVCParamNoDefaultALPN SVCParamKey = 2
122 SVCParamPort SVCParamKey = 3
123 SVCParamIPv4Hint SVCParamKey = 4
124 SVCParamECH SVCParamKey = 5
125 SVCParamIPv6Hint SVCParamKey = 6
126 SVCParamDOHPath SVCParamKey = 7
127 SVCParamOHTTP SVCParamKey = 8
128 SVCParamTLSSupportedGroups SVCParamKey = 9
129 )
130
131 var svcParamKeyNames = map[SVCParamKey]string{
132 SVCParamMandatory: "Mandatory",
133 SVCParamALPN: "ALPN",
134 SVCParamNoDefaultALPN: "NoDefaultALPN",
135 SVCParamPort: "Port",
136 SVCParamIPv4Hint: "IPv4Hint",
137 SVCParamECH: "ECH",
138 SVCParamIPv6Hint: "IPv6Hint",
139 SVCParamDOHPath: "DOHPath",
140 SVCParamOHTTP: "OHTTP",
141 SVCParamTLSSupportedGroups: "TLSSupportedGroups",
142 }
143
144
145 func (k SVCParamKey) String() string {
146 if n, ok := svcParamKeyNames[k]; ok {
147 return n
148 }
149 return printUint16(uint16(k))
150 }
151
152
153 func (k SVCParamKey) GoString() string {
154 if n, ok := svcParamKeyNames[k]; ok {
155 return "dnsmessage.SVCParam" + n
156 }
157 return printUint16(uint16(k))
158 }
159
160 func (r *SVCBResource) pack(msg []byte, _ map[string]uint16, _ int) ([]byte, error) {
161 oldMsg := msg
162 msg = packUint16(msg, r.Priority)
163
164
165
166
167 msg, err := r.Target.pack(msg, nil, 0)
168 if err != nil {
169 return oldMsg, &nestedError{"SVCBResource.Target", err}
170 }
171 var previousKey SVCParamKey
172 for i, param := range r.Params {
173 if i > 0 && param.Key <= previousKey {
174 return oldMsg, &nestedError{"SVCBResource.Params", errParamOutOfOrder}
175 }
176 if len(param.Value) > (1<<16)-1 {
177 return oldMsg, &nestedError{"SVCBResource.Params", errTooLongSVCBValue}
178 }
179 msg = packUint16(msg, uint16(param.Key))
180 msg = packUint16(msg, uint16(len(param.Value)))
181 msg = append(msg, param.Value...)
182 }
183 return msg, nil
184 }
185
186 func unpackSVCBResource(msg []byte, off int, length uint16) (SVCBResource, error) {
187
188 r := SVCBResource{}
189 paramsOff := off
190 bodyEnd := off + int(length)
191
192 var err error
193 if r.Priority, paramsOff, err = unpackUint16(msg, paramsOff); err != nil {
194 return SVCBResource{}, &nestedError{"Priority", err}
195 }
196
197 if paramsOff, err = r.Target.unpack(msg, paramsOff); err != nil {
198 return SVCBResource{}, &nestedError{"Target", err}
199 }
200
201
202
203 n := 0
204 var totalValueLen uint16
205 off = paramsOff
206 var previousKey uint16
207 for off < bodyEnd {
208 var key, len uint16
209 if key, off, err = unpackUint16(msg, off); err != nil {
210 return SVCBResource{}, &nestedError{"Params key", err}
211 }
212 if n > 0 && key <= previousKey {
213
214
215 return SVCBResource{}, &nestedError{"Params", errParamOutOfOrder}
216 }
217 if len, off, err = unpackUint16(msg, off); err != nil {
218 return SVCBResource{}, &nestedError{"Params value length", err}
219 }
220 if off+int(len) > bodyEnd {
221 return SVCBResource{}, errResourceLen
222 }
223 totalValueLen += len
224 off += int(len)
225 n++
226 }
227 if off != bodyEnd {
228 return SVCBResource{}, errResourceLen
229 }
230
231
232 r.Params = make([]SVCParam, n)
233
234
235 valuesBuf := make([]byte, totalValueLen)
236 off = paramsOff
237 for i := 0; i < n; i++ {
238 p := &r.Params[i]
239 var key, len uint16
240 if key, off, err = unpackUint16(msg, off); err != nil {
241 return SVCBResource{}, &nestedError{"param key", err}
242 }
243 p.Key = SVCParamKey(key)
244 if len, off, err = unpackUint16(msg, off); err != nil {
245 return SVCBResource{}, &nestedError{"param length", err}
246 }
247 if copy(valuesBuf, msg[off:off+int(len)]) != int(len) {
248 return SVCBResource{}, &nestedError{"param value", errCalcLen}
249 }
250 p.Value = valuesBuf[:len:len]
251 valuesBuf = valuesBuf[len:]
252 off += int(len)
253 }
254
255 return r, nil
256 }
257
258
259 func (p *Parser) genericSVCBResource(svcbType Type) (SVCBResource, error) {
260 if !p.resHeaderValid || p.resHeaderType != svcbType {
261 return SVCBResource{}, ErrNotStarted
262 }
263 r, err := unpackSVCBResource(p.msg, p.off, p.resHeaderLength)
264 if err != nil {
265 return SVCBResource{}, err
266 }
267 p.off += int(p.resHeaderLength)
268 p.resHeaderValid = false
269 p.index++
270 return r, nil
271 }
272
273
274
275
276
277 func (p *Parser) SVCBResource() (SVCBResource, error) {
278 return p.genericSVCBResource(TypeSVCB)
279 }
280
281
282
283
284
285 func (p *Parser) HTTPSResource() (HTTPSResource, error) {
286 svcb, err := p.genericSVCBResource(TypeHTTPS)
287 if err != nil {
288 return HTTPSResource{}, err
289 }
290 return HTTPSResource{svcb}, nil
291 }
292
293
294 func (b *Builder) genericSVCBResource(h ResourceHeader, r SVCBResource) error {
295 if err := b.checkResourceSection(); err != nil {
296 return err
297 }
298 msg, lenOff, err := h.pack(b.msg, b.compression, b.start)
299 if err != nil {
300 return &nestedError{"ResourceHeader", err}
301 }
302 preLen := len(msg)
303 if msg, err = r.pack(msg, b.compression, b.start); err != nil {
304 return &nestedError{"ResourceBody", err}
305 }
306 if err := h.fixLen(msg, lenOff, preLen); err != nil {
307 return err
308 }
309 if err := b.incrementSectionCount(); err != nil {
310 return err
311 }
312 b.msg = msg
313 return nil
314 }
315
316
317 func (b *Builder) SVCBResource(h ResourceHeader, r SVCBResource) error {
318 h.Type = r.realType()
319 return b.genericSVCBResource(h, r)
320 }
321
322
323 func (b *Builder) HTTPSResource(h ResourceHeader, r HTTPSResource) error {
324 h.Type = r.realType()
325 return b.genericSVCBResource(h, r.SVCBResource)
326 }
327
View as plain text