1package magna
2
3import (
4 "encoding/binary"
5 "fmt"
6 "net"
7 "strings"
8)
9
10func (a *A) Decode(buf []byte, offset int, rdlength int) (int, error) {
11 bytes, offset, err := getSlice(buf, offset, rdlength)
12 if err != nil {
13 return offset, fmt.Errorf("A record: failed to read address data: %w", err)
14 }
15
16 a.Address = net.IP(bytes)
17 if a.Address.To4() == nil {
18 return offset, fmt.Errorf("A record: decoded data is not a valid IPv4 address: %v", bytes)
19 }
20 return offset, nil
21}
22
23func (a *A) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
24 ipv4 := a.Address.To4()
25 if ipv4 == nil {
26 return nil, fmt.Errorf("A record: cannot encode non-IPv4 address %s", a.Address.String())
27 }
28
29 return append(bytes, ipv4...), nil
30}
31
32func (a A) String() string {
33 return a.Address.String()
34}
35
36func (ns *NS) Decode(buf []byte, offset int, rdlength int) (int, error) {
37 var err error
38 ns.NSDName, offset, err = decodeDomain(buf, offset)
39 if err != nil {
40 return offset, fmt.Errorf("NS record: failed to decode NSDName: %w", err)
41 }
42
43 return offset, nil
44}
45
46func (ns *NS) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
47 var err error
48 bytes, err = encodeDomain(bytes, ns.NSDName, offsets)
49 if err != nil {
50 return nil, fmt.Errorf("NS record: failed to encode NSDName %s: %w", ns.NSDName, err)
51 }
52
53 return bytes, nil
54}
55
56func (ns NS) String() string {
57 return ns.NSDName
58}
59
60func (md *MD) Decode(buf []byte, offset int, rdlength int) (int, error) {
61 var err error
62 md.MADName, offset, err = decodeDomain(buf, offset)
63 if err != nil {
64 return offset, fmt.Errorf("MD record: failed to decode MADName %s: %w", md.MADName, err)
65 }
66
67 return offset, nil
68}
69
70func (md *MD) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
71 var err error
72 bytes, err = encodeDomain(bytes, md.MADName, offsets)
73 if err != nil {
74 return nil, fmt.Errorf("MD record: failed to encode MADName %s: %w", md.MADName, err)
75 }
76
77 return bytes, nil
78}
79
80func (md MD) String() string {
81 return md.MADName
82}
83
84func (mf *MF) Decode(buf []byte, offset int, rdlength int) (int, error) {
85 var err error
86 mf.MADName, offset, err = decodeDomain(buf, offset)
87 if err != nil {
88 return offset, fmt.Errorf("MF record: failed to decode MADName: %w", err)
89 }
90
91 return offset, nil
92}
93
94func (mf *MF) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
95 var err error
96 bytes, err = encodeDomain(bytes, mf.MADName, offsets)
97 if err != nil {
98 return nil, fmt.Errorf("MF record: failed to encode MADName %s: %w", mf.MADName, err)
99 }
100
101 return bytes, nil
102}
103
104func (mf MF) String() string {
105 return mf.MADName
106}
107
108func (c *CNAME) Decode(buf []byte, offset int, rdlength int) (int, error) {
109 var err error
110 c.CName, offset, err = decodeDomain(buf, offset)
111 if err != nil {
112 return offset, fmt.Errorf("CNAME record: failed to decode CNAME: %w", err)
113 }
114
115 return offset, nil
116}
117
118func (c *CNAME) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
119 var err error
120 bytes, err = encodeDomain(bytes, c.CName, offsets)
121 if err != nil {
122 return nil, fmt.Errorf("CNAME record: failed to encode CNAME %s: %w", c.CName, err)
123 }
124
125 return bytes, nil
126}
127
128func (c CNAME) String() string {
129 return c.CName
130}
131
132func (soa *SOA) Decode(buf []byte, offset int, rdlength int) (int, error) {
133 var err error
134 soa.MName, offset, err = decodeDomain(buf, offset)
135 if err != nil {
136 return offset, fmt.Errorf("SOA record: failed to decode MName: %w", err)
137 }
138
139 soa.RName, offset, err = decodeDomain(buf, offset)
140 if err != nil {
141 return offset, fmt.Errorf("SOA record: failed to decode RName: %w", err)
142 }
143
144 soa.Serial, offset, err = getU32(buf, offset)
145 if err != nil {
146 return offset, fmt.Errorf("SOA record: failed to decode Serial: %w", err)
147 }
148
149 soa.Refresh, offset, err = getU32(buf, offset)
150 if err != nil {
151 return offset, fmt.Errorf("SOA record: failed to decode Refresh: %w", err)
152 }
153
154 soa.Retry, offset, err = getU32(buf, offset)
155 if err != nil {
156 return offset, fmt.Errorf("SOA record: failed to decode Retry: %w", err)
157 }
158
159 soa.Expire, offset, err = getU32(buf, offset)
160 if err != nil {
161 return offset, fmt.Errorf("SOA record: failed to decode Expire: %w", err)
162 }
163
164 soa.Minimum, offset, err = getU32(buf, offset)
165 if err != nil {
166 return offset, fmt.Errorf("SOA record: failed to decode Minimum: %w", err)
167 }
168
169 return offset, nil
170}
171
172func (soa *SOA) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
173 var err error
174 bytes, err = encodeDomain(bytes, soa.MName, offsets)
175 if err != nil {
176 return nil, fmt.Errorf("SOA record: failed to encode MName %s: %w", soa.MName, err)
177 }
178
179 bytes, err = encodeDomain(bytes, soa.RName, offsets)
180 if err != nil {
181 return nil, fmt.Errorf("SOA record: failed to encode RName %s: %w", soa.RName, err)
182 }
183
184 bytes = binary.BigEndian.AppendUint32(bytes, soa.Serial)
185 bytes = binary.BigEndian.AppendUint32(bytes, soa.Refresh)
186 bytes = binary.BigEndian.AppendUint32(bytes, soa.Retry)
187 bytes = binary.BigEndian.AppendUint32(bytes, soa.Expire)
188 bytes = binary.BigEndian.AppendUint32(bytes, soa.Minimum)
189
190 return bytes, nil
191}
192
193func (soa SOA) String() string {
194 return fmt.Sprintf("%s %s %d %d %d %d %d", soa.MName, soa.RName, soa.Serial, soa.Refresh, soa.Retry, soa.Expire, soa.Minimum)
195}
196
197func (mb *MB) Decode(buf []byte, offset int, rdlength int) (int, error) {
198 madname, offset, err := decodeDomain(buf, offset)
199 if err != nil {
200 return offset, fmt.Errorf("MB record: failed to decode MADName: %w", err)
201 }
202
203 mb.MADName = string(madname)
204 return offset, nil
205}
206
207func (mb *MB) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
208 var err error
209 bytes, err = encodeDomain(bytes, mb.MADName, offsets)
210 if err != nil {
211 return nil, fmt.Errorf("MB record: failed to encode MADName %s: %w", mb.MADName, err)
212 }
213
214 return bytes, nil
215}
216
217func (mb MB) String() string {
218 return mb.MADName
219}
220
221func (mg *MG) Decode(buf []byte, offset int, rdlength int) (int, error) {
222 var err error
223 mg.MGMName, offset, err = decodeDomain(buf, offset)
224 if err != nil {
225 return offset, fmt.Errorf("MG record: failed to decode MGMName: %w", err)
226 }
227
228 return offset, nil
229}
230
231func (mg *MG) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
232 var err error
233 bytes, err = encodeDomain(bytes, mg.MGMName, offsets)
234 if err != nil {
235 return nil, fmt.Errorf("MG record: failed to encode MGMName %s: %w", mg.MGMName, err)
236 }
237 return bytes, nil
238}
239
240func (mg MG) String() string {
241 return mg.MGMName
242}
243
244func (mr *MR) Decode(buf []byte, offset int, rdlength int) (int, error) {
245 var err error
246 mr.NEWName, offset, err = decodeDomain(buf, offset)
247 if err != nil {
248 return offset, fmt.Errorf("MR record: failed to decode NEWName: %w", err)
249 }
250
251 return offset, nil
252}
253
254func (mr *MR) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
255 var err error
256 bytes, err = encodeDomain(bytes, mr.NEWName, offsets)
257 if err != nil {
258 return nil, fmt.Errorf("MR record: failed to encode NEWName: %w", err)
259 }
260
261 return bytes, nil
262}
263
264func (mr MR) String() string {
265 return mr.NEWName
266}
267
268func (null *NULL) Decode(buf []byte, offset int, rdlength int) (int, error) {
269 var err error
270 null.Anything, offset, err = getSlice(buf, offset, int(rdlength))
271 if err != nil {
272 return offset, fmt.Errorf("NULL record: failed to read data: %w", err)
273 }
274
275 return offset, nil
276}
277
278func (null *NULL) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
279 return append(bytes, null.Anything...), nil
280}
281
282func (null NULL) String() string {
283 return string(null.Anything)
284}
285
286func (wks *WKS) Decode(buf []byte, offset int, rdlength int) (int, error) {
287 if rdlength < 5 {
288 return len(buf), fmt.Errorf("WKS record: RDLENGTH %d is too short, minimum 5 required", rdlength)
289 }
290
291 addressBytes, nextOffset, err := getSlice(buf, offset, 4)
292 if err != nil {
293 return len(buf), fmt.Errorf("WKS record: failed to read address: %w", err)
294 }
295 offset = nextOffset
296 wks.Address = net.IP(addressBytes)
297
298 protocol, nextOffset, err := getU8(buf, offset)
299 if err != nil {
300 return len(buf), fmt.Errorf("WKS record: failed to read protocol: %w", err)
301 }
302 offset = nextOffset
303 wks.Protocol = protocol
304
305 bitmapLength := rdlength - 5
306 wks.BitMap, nextOffset, err = getSlice(buf, offset, bitmapLength)
307 if err != nil {
308 return len(buf), fmt.Errorf("WKS record: failed to read bitmap: %w", err)
309 }
310 offset = nextOffset
311
312 return offset, nil
313}
314
315func (wks *WKS) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
316 bytes = append(bytes, wks.Address.To4()...)
317 bytes = append(bytes, wks.Protocol)
318 bytes = append(bytes, wks.BitMap...)
319
320 return bytes, nil
321}
322
323func (wks WKS) String() string {
324 return fmt.Sprintf("%s %d %x", wks.Address.String(), wks.Protocol, wks.BitMap)
325}
326
327func (ptr *PTR) Decode(buf []byte, offset int, rdlength int) (int, error) {
328 var err error
329 ptr.PTRDName, offset, err = decodeDomain(buf, offset)
330 if err != nil {
331 return offset, fmt.Errorf("PTR record: failed to decode PTRDName: %w", err)
332 }
333
334 return offset, nil
335}
336
337func (ptr *PTR) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
338 var err error
339 bytes, err = encodeDomain(bytes, ptr.PTRDName, offsets)
340 if err != nil {
341 return nil, fmt.Errorf("PTR record: failed to encode PTRD %s: %w", ptr.PTRDName, err)
342 }
343
344 return bytes, nil
345}
346
347func (ptr PTR) String() string {
348 return ptr.PTRDName
349}
350
351func (hinfo *HINFO) Decode(buf []byte, offset int, rdlength int) (int, error) {
352 startOffset := offset
353 endOffset := offset + rdlength
354 if endOffset > len(buf) {
355 return len(buf), &BufferOverflowError{Length: len(buf), Offset: endOffset}
356 }
357
358 currentOffset := offset
359 var err error
360
361 cpuLen, nextOffset, err := getU8(buf, currentOffset)
362 if err != nil {
363 return len(buf), fmt.Errorf("HINFO record: failed to read CPU length: %w", err)
364 }
365 currentOffset = nextOffset
366 if currentOffset+int(cpuLen) > endOffset {
367 return len(buf), &BufferOverflowError{Length: len(buf), Offset: currentOffset + int(cpuLen)}
368 }
369 cpuBytes, nextOffset, err := getSlice(buf, currentOffset, int(cpuLen))
370 if err != nil {
371 return len(buf), fmt.Errorf("HINFO record: failed to read CPU data: %w", err)
372 }
373 currentOffset = nextOffset
374 hinfo.CPU = string(cpuBytes)
375
376 osLen, nextOffset, err := getU8(buf, currentOffset)
377 if err != nil {
378 if currentOffset == endOffset {
379 return len(buf), fmt.Errorf("HINFO record: missing OS length byte at offset %d (expected end: %d)", currentOffset, endOffset)
380 }
381 return len(buf), fmt.Errorf("HINFO record: failed to read OS length: %w", err)
382 }
383 currentOffset = nextOffset
384 if currentOffset+int(osLen) > endOffset {
385 return len(buf), &BufferOverflowError{Length: len(buf), Offset: currentOffset + int(osLen)}
386 }
387 osBytes, nextOffset, err := getSlice(buf, currentOffset, int(osLen))
388 if err != nil {
389 return len(buf), fmt.Errorf("HINFO record: failed to read OS data: %w", err)
390 }
391 currentOffset = nextOffset
392 hinfo.OS = string(osBytes)
393
394 if currentOffset != endOffset {
395 return len(buf), fmt.Errorf("HINFO record: RDATA length mismatch, consumed %d bytes, expected %d", currentOffset-startOffset, rdlength)
396 }
397
398 return currentOffset, nil
399}
400
401func (hinfo *HINFO) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
402 if len(hinfo.CPU) > 255 {
403 return nil, fmt.Errorf("HINFO record: CPU string length %d exceeds maximum 255", len(hinfo.CPU))
404 }
405 if len(hinfo.OS) > 255 {
406 return nil, fmt.Errorf("HINFO record: OS string length %d exceeds maximum 255", len(hinfo.OS))
407 }
408
409 bytes = append(bytes, byte(len(hinfo.CPU)))
410 bytes = append(bytes, []byte(hinfo.CPU)...)
411 bytes = append(bytes, byte(len(hinfo.OS)))
412 bytes = append(bytes, []byte(hinfo.OS)...)
413 return bytes, nil
414}
415
416func (hinfo HINFO) String() string {
417 return fmt.Sprintf("%q %q", hinfo.CPU, hinfo.OS)
418}
419
420func (minfo *MINFO) Decode(buf []byte, offset int, rdlength int) (int, error) {
421 var err error
422
423 minfo.RMailBx, offset, err = decodeDomain(buf, offset)
424 if err != nil {
425 return offset, fmt.Errorf("MINFO record: failed to decode RMailBx: %w", err)
426 }
427
428 minfo.EMailBx, offset, err = decodeDomain(buf, offset)
429 if err != nil {
430 return offset, fmt.Errorf("MINFO record: failed to decode EMailBx: %w", err)
431 }
432
433 return offset, nil
434}
435
436func (minfo *MINFO) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
437 var err error
438 bytes, err = encodeDomain(bytes, minfo.RMailBx, offsets)
439 if err != nil {
440 return nil, fmt.Errorf("MINFO record: failed to encode RMailBx %s: %w", minfo.RMailBx, err)
441 }
442
443 bytes, err = encodeDomain(bytes, minfo.EMailBx, offsets)
444 if err != nil {
445 return nil, fmt.Errorf("MINFO record: failed to encode EMailBx %s: %w", minfo.EMailBx, err)
446 }
447
448 return bytes, nil
449}
450
451func (minfo MINFO) String() string {
452 return minfo.RMailBx + " " + minfo.EMailBx
453}
454
455func (mx *MX) Decode(buf []byte, offset int, rdlength int) (int, error) {
456 var err error
457 mx.Preference, offset, err = getU16(buf, offset)
458 if err != nil {
459 return offset, fmt.Errorf("MX record: failed to decode Preference: %w", err)
460 }
461
462 mx.Exchange, offset, err = decodeDomain(buf, offset)
463 if err != nil {
464 return offset, fmt.Errorf("MX record: failed to decode Exchange: %w", err)
465 }
466
467 return offset, nil
468}
469
470func (mx *MX) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
471 var err error
472 bytes = binary.BigEndian.AppendUint16(bytes, mx.Preference)
473 bytes, err = encodeDomain(bytes, mx.Exchange, offsets)
474 if err != nil {
475 return nil, fmt.Errorf("MX record: failed to encode Exchange %s: %w", mx.Exchange, err)
476 }
477
478 return bytes, nil
479}
480
481func (mx MX) String() string {
482 return fmt.Sprintf("%d %s", mx.Preference, mx.Exchange)
483}
484
485func (txt *TXT) Decode(buf []byte, offset int, rdlength int) (int, error) {
486 txt.TxtData = make([]string, 0, 1)
487 endOffset := offset + rdlength
488 if endOffset > len(buf) {
489 return len(buf), &BufferOverflowError{Length: len(buf), Offset: endOffset}
490 }
491
492 currentOffset := offset
493 for currentOffset < endOffset {
494 strLen, nextOffsetAfterLen, err := getU8(buf, currentOffset)
495 if err != nil {
496 return len(buf), fmt.Errorf("TXT record: failed to read string length byte: %w", err)
497 }
498
499 nextOffsetAfterData := nextOffsetAfterLen + int(strLen)
500 if nextOffsetAfterData > endOffset {
501 return len(buf), fmt.Errorf("TXT record: string segment length %d exceeds RDLENGTH boundary %d", strLen, endOffset)
502 }
503
504 strBytes, actualNextOffsetAfterData, err := getSlice(buf, nextOffsetAfterLen, int(strLen))
505 if err != nil {
506 return len(buf), fmt.Errorf("TXT record: failed to read string data (length %d): %w", strLen, err)
507 }
508
509 txt.TxtData = append(txt.TxtData, string(strBytes))
510 currentOffset = actualNextOffsetAfterData
511 }
512
513 if currentOffset != endOffset {
514 return len(buf), fmt.Errorf("TXT record: RDATA parsing finished at offset %d, but expected end at %d", currentOffset, endOffset)
515 }
516
517 return currentOffset, nil
518}
519
520func (txt *TXT) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
521 for _, s := range txt.TxtData {
522 if len(s) > 255 {
523 return nil, fmt.Errorf("TXT record: string segment length %d exceeds maximum 255", len(s))
524 }
525 bytes = append(bytes, byte(len(s)))
526 bytes = append(bytes, []byte(s)...)
527 }
528 return bytes, nil
529}
530
531func (txt TXT) String() string {
532 quoted := make([]string, len(txt.TxtData))
533 for i, s := range txt.TxtData {
534 quoted[i] = fmt.Sprintf("%q", s)
535 }
536 return strings.Join(quoted, " ")
537}
538
539func (rp *RP) Decode(buf []byte, offset int, rdlength int) (int, error) {
540 var err error
541 rp.MBoxDName, offset, err = decodeDomain(buf, offset)
542 if err != nil {
543 return offset, fmt.Errorf("RP record: failed to decode mbox-dname: %w", err)
544 }
545
546 rp.TXTDName, offset, err = decodeDomain(buf, offset)
547 if err != nil {
548 return offset, fmt.Errorf("RP record: failed to decode txt-dname: %w", err)
549 }
550
551 return offset, nil
552}
553
554func (rp *RP) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
555 var err error
556 bytes, err = encodeDomain(bytes, rp.MBoxDName, offsets)
557 if err != nil {
558 return nil, fmt.Errorf("RP record: failed to encode mbox-dname %s: %w", rp.MBoxDName, err)
559 }
560
561 bytes, err = encodeDomain(bytes, rp.TXTDName, offsets)
562 if err != nil {
563 return nil, fmt.Errorf("RP record: failed to encode txt-dname %s: %w", rp.TXTDName, err)
564 }
565
566 return bytes, nil
567}
568
569func (rp RP) String() string {
570 return fmt.Sprintf("%s %s", rp.MBoxDName, rp.TXTDName)
571}
572
573func (a *AFSDB) Decode(buf []byte, offset int, rdlength int) (int, error) {
574 var err error
575 a.Subtype, offset, err = getU16(buf, offset)
576 if err != nil || !(a.Subtype == 1 || a.Subtype == 2) {
577 return offset, fmt.Errorf("AFSDB record: failed to decode Subtype: %w", err)
578 }
579
580 a.Hostname, offset, err = decodeDomain(buf, offset)
581 if err != nil {
582 return offset, fmt.Errorf("AFSDB record: failed to decode Hostname: %w", err)
583 }
584
585 return offset, nil
586}
587
588func (a *AFSDB) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
589 var err error
590 bytes = binary.BigEndian.AppendUint16(bytes, a.Subtype)
591 bytes, err = encodeDomain(bytes, a.Hostname, offsets)
592 if err != nil {
593 return nil, fmt.Errorf("AFSDB record: failed to encode Domain %s: %w", a.Hostname, err)
594 }
595
596 return bytes, nil
597}
598
599func (a AFSDB) String() string {
600 return fmt.Sprintf("%d %s", a.Subtype, a.Hostname)
601}
602
603func (x *X25) Decode(buf []byte, offset int, rdlength int) (int, error) {
604 var err error
605 endOffset := offset + rdlength
606 if endOffset > len(buf) {
607 return len(buf), &BufferOverflowError{Length: len(buf), Offset: endOffset}
608 }
609
610 strLen, nextOffsetAfterLen, err := getU8(buf, offset)
611 if err != nil {
612 return len(buf), fmt.Errorf("x25 record: failed to read string length byte: %w", err)
613 }
614
615 nextOffsetAfterData := nextOffsetAfterLen + int(strLen)
616 if nextOffsetAfterData > endOffset {
617 return len(buf), fmt.Errorf("x25 record: string segment length %d exceeds RDLENGTH boundary %d", strLen, endOffset)
618 }
619
620 strBytes, offset, err := getSlice(buf, nextOffsetAfterLen, int(strLen))
621 if err != nil {
622 return len(buf), fmt.Errorf("x25 record: failed to read string data (length %d): %w", strLen, err)
623 }
624
625 x.PSDNAddress = string(strBytes)
626 for _, c := range x.PSDNAddress {
627 if c < '0' || c > '9' {
628 return offset, fmt.Errorf("X25 record: PSDN address contains non-digit character: %c", c)
629 }
630 }
631
632 return offset, nil
633}
634
635func (x *X25) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
636 for _, r := range x.PSDNAddress {
637 if r < '0' || r > '9' {
638 return nil, fmt.Errorf("X25 record: PSDN address contains non-digit character: %c", r)
639 }
640 }
641
642 bytes = append(bytes, byte(len(x.PSDNAddress)))
643 bytes = append(bytes, []byte(x.PSDNAddress)...)
644
645 return bytes, nil
646}
647
648func (x X25) String() string {
649 return x.PSDNAddress
650}
651
652func (isdn *ISDN) Decode(buf []byte, offset int, rdlength int) (int, error) {
653 var err error
654 endOffset := offset + rdlength
655 if endOffset > len(buf) {
656 return len(buf), &BufferOverflowError{Length: len(buf), Offset: endOffset}
657 }
658
659 strLen, nextOffsetAfterLen, err := getU8(buf, offset)
660 if err != nil {
661 return len(buf), fmt.Errorf("ISDN record: failed to read string length byte: %w", err)
662 }
663
664 nextOffsetAfterData := nextOffsetAfterLen + int(strLen)
665 if nextOffsetAfterData > endOffset {
666 return len(buf), fmt.Errorf("ISDN record: string segment length %d exceeds RDLENGTH boundary %d", strLen, endOffset)
667 }
668
669 strBytes, offset, err := getSlice(buf, nextOffsetAfterLen, int(strLen))
670 if err != nil {
671 return len(buf), fmt.Errorf("ISDN record: failed to read string data (length %d): %w", strLen, err)
672 }
673
674 isdn.ISDNAddress = string(strBytes)
675 for _, c := range isdn.ISDNAddress {
676 if c < '0' || c > '9' {
677 return offset, fmt.Errorf("ISDN record: ISDN address contains non-digit character: %c", c)
678 }
679 }
680
681 // the subaddress is an optional field
682 if offset < endOffset {
683 subAddrLen, nextOffsetAfterSubAddrLen, err := getU8(buf, offset)
684 if err != nil {
685 return offset, fmt.Errorf("ISDN record: failed to read subaddress length: %w", err)
686 }
687 offset = nextOffsetAfterSubAddrLen
688
689 if offset+int(subAddrLen) > endOffset {
690 return offset, fmt.Errorf("ISDN record: subaddress data length %d exceeds RDLENGTH boundary (available: %d bytes from offset %d up to %d)", subAddrLen, endOffset-offset, offset, endOffset)
691 }
692
693 subAddrBytes, nextOffsetAfterSubAddrData, err := getSlice(buf, offset, int(subAddrLen))
694 if err != nil {
695 return offset, fmt.Errorf("ISDN record: failed to read subaddress data (length %d): %w", subAddrLen, err)
696 }
697 offset = nextOffsetAfterSubAddrData
698 isdn.Subaddress = string(subAddrBytes)
699 } else {
700 isdn.Subaddress = ""
701 }
702
703 return offset, nil
704}
705
706func (isdn *ISDN) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
707 bytes = append(bytes, byte(len(isdn.ISDNAddress)))
708 bytes = append(bytes, []byte(isdn.ISDNAddress)...)
709
710 if isdn.Subaddress != "" {
711 bytes = append(bytes, byte(len(isdn.Subaddress)))
712 bytes = append(bytes, []byte(isdn.Subaddress)...)
713 }
714 return bytes, nil
715}
716
717func (isdn ISDN) String() string {
718 if isdn.Subaddress != "" {
719 return fmt.Sprintf("%q %q", isdn.ISDNAddress, isdn.Subaddress)
720 }
721 return fmt.Sprintf("%q", isdn.ISDNAddress)
722}
723
724func (rt *RT) Decode(buf []byte, offset int, rdlength int) (int, error) {
725 var err error
726 rt.Preference, offset, err = getU16(buf, offset)
727 if err != nil {
728 return offset, fmt.Errorf("RT record: failed to decode Preference: %w", err)
729 }
730
731 rt.IntermediateHost, offset, err = decodeDomain(buf, offset)
732 if err != nil {
733 return offset, fmt.Errorf("RT record: failed to decode Exchange: %w", err)
734 }
735
736 return offset, nil
737}
738
739func (rt *RT) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
740 var err error
741 bytes = binary.BigEndian.AppendUint16(bytes, rt.Preference)
742 bytes, err = encodeDomain(bytes, rt.IntermediateHost, offsets)
743 if err != nil {
744 return nil, fmt.Errorf("RT record: failed to encode Intermediate Host %s: %w", rt.IntermediateHost, err)
745 }
746
747 return bytes, nil
748}
749
750func (rt RT) String() string {
751 return fmt.Sprintf("%d %s", rt.Preference, rt.IntermediateHost)
752}
753
754func (a *AAAA) Decode(buf []byte, offset int, rdlength int) (int, error) {
755 bytes, offset, err := getSlice(buf, offset, rdlength)
756 if err != nil {
757 return offset, fmt.Errorf("AAAA record: failed to read address data: %w", err)
758 }
759
760 a.Address = net.IP(bytes)
761 if a.Address.To16() == nil {
762 return offset, fmt.Errorf("AAAA record: decoded data is not a valid IPv6 address: %v", bytes)
763 }
764 return offset, nil
765}
766
767func (a *AAAA) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
768 ipv6 := a.Address.To16()
769 // XXX: ipv6 encodes ipv4 so need to check its not ipv4
770 if a.Address.To4() != nil || ipv6 == nil {
771 return nil, fmt.Errorf("AAAA record: cannot encode non-IPv6 address %s", a.Address.String())
772 }
773
774 return append(bytes, ipv6...), nil
775}
776
777func (a AAAA) String() string {
778 return a.Address.String()
779}
780
781func (opt *OPT) Decode(buf []byte, offset int, rdlength int) (int, error) {
782 // s := offset
783 opt.Options = make([]EDNSOption, 0)
784
785 if rdlength == 0 {
786 return offset, nil
787 }
788
789 endOffset := offset + rdlength
790 curOffset := offset
791 for curOffset < endOffset {
792 // need 4 bytes for both code and length
793 if offset+4 > endOffset {
794 return offset, fmt.Errorf("OPT record: truncated option header at offset: %d", offset)
795 }
796
797 optCode, offset, err := getU16(buf, offset)
798 if err != nil {
799 return offset, fmt.Errorf("OPT Record: failed to read option code: %w", err)
800 }
801
802 optLength, offset, err := getU16(buf, offset)
803 if err != nil {
804 return offset, fmt.Errorf("OPT Record: failed to read option length: %w", err)
805 }
806
807 if offset+int(optLength) > endOffset {
808 return offset, fmt.Errorf("OPT Record: failed to read option data of length: %d", offset)
809 }
810
811 optData, offset, err := getSlice(buf, offset, int(optLength))
812 if err != nil {
813 return offset, fmt.Errorf("OPT Record: failed to read option data: %w", err)
814 }
815
816 opt.Options = append(opt.Options, EDNSOption{
817 Code: optCode,
818 Data: optData,
819 })
820
821 curOffset = offset
822 }
823
824 return offset, nil
825}
826
827func (opt *OPT) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
828 for _, opt := range opt.Options {
829 bytes = binary.BigEndian.AppendUint16(bytes, opt.Code)
830 bytes = binary.BigEndian.AppendUint16(bytes, uint16(len(opt.Data)))
831 bytes = append(bytes, opt.Data...)
832 }
833
834 return bytes, nil
835}
836
837func (opt OPT) String() string {
838 var result strings.Builder
839 result.WriteString("OPT [")
840 for i, o := range opt.Options {
841 if i < len(opt.Options)-1 {
842 result.WriteString(fmt.Sprintf("%d <%x>,", o.Code, o.Data))
843 } else {
844 result.WriteString(fmt.Sprintf("%d <%x>,", o.Code, o.Data))
845 }
846 }
847 result.WriteString("]")
848
849 return result.String()
850}
851
852func (r *Reserved) Decode(buf []byte, offset int, rdlength int) (int, error) {
853 var err error
854 r.Bytes, offset, err = getSlice(buf, offset, int(rdlength))
855 if err != nil {
856 return offset, fmt.Errorf("reserved record: failed to read data: %w", err)
857 }
858
859 return offset, err
860}
861
862func (r *Reserved) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
863 return append(bytes, r.Bytes...), nil
864}
865
866func (r Reserved) String() string {
867 return fmt.Sprintf("[Reserved Data: %x]", r.Bytes)
868}
869
870// Decode decodes a resource record from buf at the offset.
871func (r *ResourceRecord) Decode(buf []byte, offset int) (int, error) {
872 var err error
873 r.Name, offset, err = decodeDomain(buf, offset)
874 if err != nil {
875 return offset, fmt.Errorf("rr decode: failed to decode record name: %w", err)
876 }
877
878 var rtype uint16
879 rtype, offset, err = getU16(buf, offset)
880 if err != nil {
881 return offset, fmt.Errorf("rr decode: failed to decode RType for %s: %w", r.Name, err)
882 }
883 r.RType = DNSType(rtype)
884
885 var rclass uint16
886 rclass, offset, err = getU16(buf, offset)
887 if err != nil {
888 return offset, fmt.Errorf("rr decode: failed to decode RClass for %s: %w", r.Name, err)
889 }
890 r.RClass = DNSClass(rclass)
891
892 r.TTL, offset, err = getU32(buf, offset)
893 if err != nil {
894 return offset, fmt.Errorf("rr decode: failed to decode TTL for %s: %w", r.Name, err)
895 }
896
897 r.RDLength, offset, err = getU16(buf, offset)
898 if err != nil {
899 return offset, fmt.Errorf("rr decode: failed to decode RDLength for %s: %w", r.Name, err)
900 }
901
902 switch r.RType {
903 case 1:
904 r.RData = &A{}
905 case 2:
906 r.RData = &NS{}
907 case 3:
908 r.RData = &MD{}
909 case 4:
910 r.RData = &MF{}
911 case 5:
912 r.RData = &CNAME{}
913 case 6:
914 r.RData = &SOA{}
915 case 7:
916 r.RData = &MB{}
917 case 8:
918 r.RData = &MG{}
919 case 9:
920 r.RData = &MR{}
921 case 10:
922 r.RData = &NULL{}
923 case 11:
924 r.RData = &WKS{}
925 case 12:
926 r.RData = &PTR{}
927 case 13:
928 r.RData = &HINFO{}
929 case 14:
930 r.RData = &MINFO{}
931 case 15:
932 r.RData = &MX{}
933 case 16:
934 r.RData = &TXT{}
935 case 17:
936 r.RData = &RP{}
937 case 18:
938 r.RData = &AFSDB{}
939 case 19:
940 r.RData = &X25{}
941 case 20:
942 r.RData = &ISDN{}
943 case 21:
944 r.RData = &RT{}
945 case 28:
946 r.RData = &AAAA{}
947 case 41:
948 r.RData = &OPT{}
949 default:
950 r.RData = &Reserved{}
951 }
952
953 if r.RData != nil {
954 offset, err = r.RData.Decode(buf, offset, int(r.RDLength))
955 if err != nil {
956 return offset, fmt.Errorf("rr decode: failed to decode RData for %s (%s): %w", r.Name, r.RType.String(), err)
957 }
958 }
959
960 return offset, nil
961}
962
963// Encode encdoes a resource record and returns the input bytes appened.
964func (r *ResourceRecord) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) {
965 var err error
966 bytes, err = encodeDomain(bytes, r.Name, offsets)
967 if err != nil {
968 return nil, fmt.Errorf("rr encode: failed to encode record name %s: %w", r.Name, err)
969 }
970
971 bytes = binary.BigEndian.AppendUint16(bytes, uint16(r.RType))
972 bytes = binary.BigEndian.AppendUint16(bytes, uint16(r.RClass))
973 bytes = binary.BigEndian.AppendUint32(bytes, r.TTL)
974
975 rdataStart := len(bytes)
976 bytes = binary.BigEndian.AppendUint16(bytes, 0)
977 bytes, err = r.RData.Encode(bytes, offsets)
978 if err != nil {
979 return nil, fmt.Errorf("rr encode: failed to encode RData for %s (%s): %w", r.Name, r.RType.String(), err)
980 }
981
982 rdataLength := uint16(len(bytes) - rdataStart - 2)
983 binary.BigEndian.PutUint16(bytes[rdataStart:rdataStart+2], rdataLength)
984
985 return bytes, nil
986}