summaryrefslogtreecommitdiff
path: root/internal/dns/rr_opt.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/dns/rr_opt.go')
-rw-r--r--internal/dns/rr_opt.go57
1 files changed, 57 insertions, 0 deletions
diff --git a/internal/dns/rr_opt.go b/internal/dns/rr_opt.go
new file mode 100644
index 0000000..77bc1ee
--- /dev/null
+++ b/internal/dns/rr_opt.go
@@ -0,0 +1,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)
+}