summaryrefslogtreecommitdiff
path: root/internal/dns/rr_opt.go
blob: 77bc1eebe6b7529078e401daea289ad2b97953c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package dns

import "fmt"

// https://datatracker.ietf.org/doc/html/rfc6891#section-4.1
type Option struct {
	Code uint16
	Data []byte
}

type OPT struct {
	// https://datatracker.ietf.org/doc/html/rfc6891#section-4.3
	UDPSize  uint16
	ExtRCode uint8
	Version  uint8
	DO       bool
	Z        uint16
	Options  []Option
}

func (o *OPT) Type() uint16 { return TypeOPT }

func (o *OPT) Pack(p *packer) error {
	for _, opt := range o.Options {
		p.writeUint16(opt.Code)
		p.writeUint16(uint16(len(opt.Data)))
		p.buf = append(p.buf, opt.Data...)
	}
	return nil
}

func (o *OPT) Unpack(u *unpacker, length uint16) error {
	end := u.off + int(length)
	for u.off < end {
		code, err := u.readUint16()
		if err != nil {
			return err
		}
		optLen, err := u.readUint16()
		if err != nil {
			return err
		}
		if u.off+int(optLen) > end {
			return fmt.Errorf("dns: opt data overflow")
		}
		o.Options = append(o.Options, Option{
			Code: code,
			Data: append([]byte(nil), u.buf[u.off:u.off+int(optLen)]...),
		})
		u.off += int(optLen)
	}
	return nil
}

func (o *OPT) String() string {
	return fmt.Sprintf("OPT udpsize=%d extrcode=%d version=%d do=%t", o.UDPSize, o.ExtRCode, o.Version, o.DO)
}