From e9d3659ef41b9b5fd5e7cc7bd04ae3fc07850044 Mon Sep 17 00:00:00 2001 From: radhitya Date: Wed, 24 Jun 2026 18:47:02 +0700 Subject: lot of works, i guess --- internal/dns/header.go | 57 +++++++++++++++++++++++++++++++++++++ internal/dns/name.go | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ internal/dns/question.go | 7 +++++ 3 files changed, 138 insertions(+) create mode 100644 internal/dns/header.go create mode 100644 internal/dns/name.go create mode 100644 internal/dns/question.go (limited to 'internal/dns') diff --git a/internal/dns/header.go b/internal/dns/header.go new file mode 100644 index 0000000..1535500 --- /dev/null +++ b/internal/dns/header.go @@ -0,0 +1,57 @@ +package dns + +// https://datatracker.ietf.org/doc/html/rfc5395 +type Header struct { + ID uint16 + Flags uint16 + QDCount uint16 + ANCount uint16 + NSCount uint16 + ARCount uint16 +} + +// https://datatracker.ietf.org/doc/html/rfc2929#section-2 +// Flags has 16-bit Field. Each hexadecima value below indicates +// which items are active. +// Example 0 0000 0 0 0 0 000 0 0 000, so if only AA is active, then +// Example 1 0000 0 0 0 0 000 0 0 000, is 0x8000 +// Query and Response +func (h *Header) QR() bool { return h.Flags&0x8000 != 0 } + +// Opcode has 4-bit (14 -- 11) +func (h *Header) OpCode() uint8 { return uint8((h.Flags >> 11) & 0xF) } + +// Authoritative Answer +func (h *Header) AA() bool { return h.Flags&0x0400 != 0 } + +// Truncation +func (h *Header) TC() bool { return h.Flags&0x0200 != 0 } + +// Recursion Desired +func (h *Header) RD() bool { return h.Flags&0x0100 != 0 } + +// Recursion Available +func (h *Header) RA() bool { return h.Flags&0x0080 != 0 } + +// Mutator Flags +func (h *Header) SetQR(v bool) { h.set(0x8000, v) } +func (h *Header) SetOpCode(v uint8) { + h.Bits = (h.Bits &^ (0xF << 11)) | + ((uint16(v) & 0xF) << 11) +} +func (h *Header) SetAA(v bool) { h.set(0x0400, v) } +func (h *Header) SetTC(v bool) { h.set(0x0200, v) } +func (h *Header) SetRD(v bool) { h.set(0x0100, v) } +func (h *Header) SetRA(v bool) { h.set(0x0080, v) } +func (h *Header) SetZ(v uint8) { h.Bits = (h.Bits &^ 0xF) | (uint16(v) & 0xF) << 4) } +func (h *Header) SetAD(v bool) { h.set(0x0020, v) } +func (h *Header) SetCD(v bool) { h.set(0x0010, v) } +func (h *Header) SetRCode(v uint8) { h.Bits = (h.Bits &^ 0xF) | (uint16(v) & 0xF) } + +func (h *Header) set(mask uint16, v bool) { + if v { + h.Bits |= mask + } else { + h.Bits &^= mask + } +} diff --git a/internal/dns/name.go b/internal/dns/name.go new file mode 100644 index 0000000..799e53a --- /dev/null +++ b/internal/dns/name.go @@ -0,0 +1,74 @@ +package dns + +import ( + "errors" + "strings" +) + +// https://datatracker.ietf.org/doc/html/rfc9499#section-2-1.16.1.2 +// ex: "www.example.com" "03 77 77 77 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00" +type Name struct { + Data []byte +} + +func Fqdn(s string) string { + if len(s) == 0 { + return "." + } + if s[len(s)-1] == '.' { + return s + } + return s + "." +} + +func NewName(s string) (Name, error) { + if s == "" || s == "." { + return Name{Data: []byte{0}}, nil + } + s = Fqdn(s) + labels := strings.Split(s, ".") + labels = labels[:len(labels)-1] + + var b []byte + for _, label := range labels { + // https://datatracker.ietf.org/doc/html/rfc1034#section-3.1 + if len(label) > 63 { + return Name{}, errors.New("dns: label > 63 octets") + } + b = append(b, byte(len(label))) + b = append(b, label...) + } + b = append(b, 0) + + // https: //datatracker.ietf.org/doc/html/rfc1034#section-3.1 + if len(b) > 255 { + return Name{}, errors.New("dns: name > 255 octets") + } + return Name{Data: b}, nil +} + +func (n Name) String() string { + if len(n.Data) == 1 && n.Data[0] == 0 { + return "." + } + var labels []string + off := 0 + for off < len(n.Data) { + l := int(n.Data[off]) + if l == 0 { + break + } + labels = append(labels, string(n.Data[off+1:off+1+l])) + off += 1 + 1 + } + return strings.Join(labels, ".") + "." +} + +func SplitDomainName(s string) []string { + s = Fqdn(s) + if s == "." { + return nil + } + labels := strings.Split(s, ".") + return labels[:len(labels)-1] +} diff --git a/internal/dns/question.go b/internal/dns/question.go new file mode 100644 index 0000000..101cb0a --- /dev/null +++ b/internal/dns/question.go @@ -0,0 +1,7 @@ +package dns + +type Question struct { + Name Name + Type uint16 + Class uint16 +} -- cgit v1.2.3