summaryrefslogtreecommitdiff
path: root/internal/dns/rr.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/dns/rr.go')
-rw-r--r--internal/dns/rr.go110
1 files changed, 110 insertions, 0 deletions
diff --git a/internal/dns/rr.go b/internal/dns/rr.go
new file mode 100644
index 0000000..38f467c
--- /dev/null
+++ b/internal/dns/rr.go
@@ -0,0 +1,110 @@
+package dns
+
+import "fmt"
+
+type RData interface {
+ Type() uint16
+ Pack(p *packer) error
+ Unpack(u *unpacker, length uint16) error
+ String() string
+}
+
+type RR struct {
+ Name Name
+ Type uint16
+ Class uint16
+ TTL uint32
+ Data RData
+}
+
+func unpackRR(u *unpacker) (RR, error) {
+ var rr RR
+ var err error
+ rr.Name, err = u.readName()
+ if err != nil {
+ return rr, err
+ }
+ rr.Type, err = u.readUint16()
+ if err != nil {
+ return rr, err
+ }
+ rr.Class, err = u.readUint16()
+ if err != nil {
+ return rr, err
+ }
+ rr.TTL, err = u.readUint32()
+ if err != nil {
+ return rr, err
+ }
+ rdlength, err := u.readUint16()
+ if err != nil {
+ return rr, err
+ }
+
+ rdStart := u.off
+ if u.off+int(rdlength) > len(u.buf) {
+ return rr, fmt.Errorf("dns: short rdata")
+ }
+
+ switch rr.Type {
+ case TypeA:
+ rr.Data = &A{}
+ case TypeNS:
+ rr.Data = &NS{}
+ case TypeCNAME:
+ rr.Data = &CNAME{}
+ case TypeSOA:
+ rr.Data = &SOA{}
+ case TypePTR:
+ rr.Data = &PTR{}
+ case TypeMX:
+ rr.Data = &MX{}
+ case TypeTXT:
+ rr.Data = &TXT{}
+ case TypeAAAA:
+ rr.Data = &AAAA{}
+ case TypeOPT:
+ opt := &OPT{
+ UDPSize: rr.Class,
+ }
+ opt.ExtRCode = uint8(rr.TTL >> 24)
+ opt.Version = uint8(rr.TTL >> 16)
+ // https://datatracker.ietf.org/doc/html/rfc3225
+ // https://datatracker.ietf.org/doc/html/rfc4035
+ opt.DO = rr.TTL&0x8000 != 0
+ opt.Z = uint16(rr.TTL & 0x7FFF)
+ rr.Data = opt
+ default:
+ rr.Data = &Unknown{RRType: rr.Type}
+ }
+
+ if err := rr.Data.Unpack(u, rdlength); err != nil {
+ return rr, err
+ }
+ if u.off != rdStart+int(rdlength) {
+ return rr, fmt.Errorf("dns: rdata length mismatch")
+ }
+ return rr, nil
+}
+
+func (rr *RR) pack(p *packer) error {
+ if err := p.writeName(rr.Name); err != nil {
+ return err
+ }
+ p.writeUint16(rr.Type)
+ p.writeUint16(rr.Class)
+ p.writeUint32(rr.TTL)
+
+ rdlenOff := len(p.buf)
+ p.buf = append(p.buf, 0, 0)
+ rdStart := len(p.buf)
+
+ if err := rr.Data.Pack(p); err != nil {
+ return err
+ }
+
+ rdlen := uint16(len(p.buf) - rdStart)
+ p.buf[rdlenOff] = byte(rdlen >> 8)
+ p.buf[rdlenOff+1] = byte(rdlen)
+ return nil
+}