diff options
| author | radhitya <alif@radhitya.org> | 2026-07-04 14:29:02 +0700 |
|---|---|---|
| committer | radhitya <alif@radhitya.org> | 2026-07-04 14:29:02 +0700 |
| commit | 52a0d3845ead07f840e9e99cb4a8c3507c84ab30 (patch) | |
| tree | b9a08117bdcb35a1a0e61543b0859db8f4aa6bfd /internal/dns/rr.go | |
| parent | e9d3659ef41b9b5fd5e7cc7bd04ae3fc07850044 (diff) | |
fiuh
Diffstat (limited to 'internal/dns/rr.go')
| -rw-r--r-- | internal/dns/rr.go | 110 |
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 +} |
