2018-07-29 23:44:23 +08:00
|
|
|
package dns
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/binary"
|
|
|
|
"errors"
|
2020-04-20 12:41:53 +08:00
|
|
|
"io"
|
2018-07-29 23:44:23 +08:00
|
|
|
"math/rand"
|
2022-01-29 21:10:09 +08:00
|
|
|
"net/netip"
|
2018-07-29 23:44:23 +08:00
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
// UDPMaxLen is the max size of udp dns request.
|
2024-08-05 23:31:19 +08:00
|
|
|
// https://www.dnsflagday.net/2020/
|
|
|
|
const UDPMaxLen = 1232
|
2018-07-29 23:44:23 +08:00
|
|
|
|
2019-03-12 23:32:23 +08:00
|
|
|
// HeaderLen is the length of dns msg header.
|
2018-07-29 23:44:23 +08:00
|
|
|
const HeaderLen = 12
|
|
|
|
|
2022-01-22 23:33:08 +08:00
|
|
|
// MsgType is the dns Message type.
|
|
|
|
type MsgType byte
|
|
|
|
|
2020-05-06 20:10:18 +08:00
|
|
|
// Message types.
|
2018-07-29 23:44:23 +08:00
|
|
|
const (
|
2022-01-22 23:33:08 +08:00
|
|
|
QueryMsg MsgType = 0
|
|
|
|
ResponseMsg MsgType = 1
|
2018-07-29 23:44:23 +08:00
|
|
|
)
|
|
|
|
|
2020-05-06 20:10:18 +08:00
|
|
|
// Query types.
|
2018-07-29 23:44:23 +08:00
|
|
|
const (
|
|
|
|
QTypeA uint16 = 1 //ipv4
|
|
|
|
QTypeAAAA uint16 = 28 ///ipv6
|
|
|
|
)
|
|
|
|
|
2018-08-02 00:11:22 +08:00
|
|
|
// ClassINET .
|
|
|
|
const ClassINET uint16 = 1
|
2018-08-01 00:09:55 +08:00
|
|
|
|
2020-05-06 20:10:18 +08:00
|
|
|
// Message format:
|
2021-08-04 19:13:22 +08:00
|
|
|
// https://www.rfc-editor.org/rfc/rfc1035#section-4.1
|
2018-07-29 23:44:23 +08:00
|
|
|
// All communications inside of the domain protocol are carried in a single
|
|
|
|
// format called a message. The top level format of message is divided
|
|
|
|
// into 5 sections (some of which are empty in certain cases) shown below:
|
|
|
|
//
|
2023-11-28 18:26:33 +08:00
|
|
|
// +---------------------+
|
|
|
|
// | Header |
|
|
|
|
// +---------------------+
|
|
|
|
// | Question | the question for the name server
|
|
|
|
// +---------------------+
|
|
|
|
// | Answer | RRs answering the question
|
|
|
|
// +---------------------+
|
|
|
|
// | Authority | RRs pointing toward an authority
|
|
|
|
// +---------------------+
|
|
|
|
// | Additional | RRs holding additional information
|
2018-07-29 23:44:23 +08:00
|
|
|
type Message struct {
|
2018-08-02 00:11:22 +08:00
|
|
|
Header
|
2018-07-29 23:44:23 +08:00
|
|
|
// most dns implementation only support 1 question
|
|
|
|
Question *Question
|
|
|
|
Answers []*RR
|
|
|
|
Authority []*RR
|
|
|
|
Additional []*RR
|
|
|
|
|
|
|
|
// used in UnmarshalMessage
|
|
|
|
unMarshaled []byte
|
|
|
|
}
|
|
|
|
|
2019-03-12 23:32:23 +08:00
|
|
|
// NewMessage returns a new message.
|
2022-01-22 23:33:08 +08:00
|
|
|
func NewMessage(id uint16, msgType MsgType) *Message {
|
2018-08-01 00:09:55 +08:00
|
|
|
if id == 0 {
|
|
|
|
id = uint16(rand.Uint32())
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
2018-08-01 00:09:55 +08:00
|
|
|
|
2018-08-02 00:11:22 +08:00
|
|
|
m := &Message{Header: Header{ID: id}}
|
|
|
|
m.SetMsgType(msgType)
|
2018-08-01 00:09:55 +08:00
|
|
|
|
2018-08-02 00:11:22 +08:00
|
|
|
return m
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
|
|
|
|
2019-03-12 23:32:23 +08:00
|
|
|
// SetQuestion sets a question to dns message.
|
2018-07-29 23:44:23 +08:00
|
|
|
func (m *Message) SetQuestion(q *Question) error {
|
|
|
|
m.Question = q
|
|
|
|
m.Header.SetQdcount(1)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-03-12 23:32:23 +08:00
|
|
|
// AddAnswer adds an answer to dns message.
|
2018-07-29 23:44:23 +08:00
|
|
|
func (m *Message) AddAnswer(rr *RR) error {
|
|
|
|
m.Answers = append(m.Answers, rr)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-03-12 23:32:23 +08:00
|
|
|
// Marshal marshals message struct to []byte.
|
2018-07-29 23:44:23 +08:00
|
|
|
func (m *Message) Marshal() ([]byte, error) {
|
2020-04-20 12:41:53 +08:00
|
|
|
buf := &bytes.Buffer{}
|
2022-03-06 12:58:20 +08:00
|
|
|
if _, err := m.MarshalTo(buf); err != nil {
|
2020-08-23 23:23:30 +08:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return buf.Bytes(), nil
|
|
|
|
}
|
2018-07-29 23:44:23 +08:00
|
|
|
|
2020-08-23 23:23:30 +08:00
|
|
|
// MarshalTo marshals message struct to []byte and write to w.
|
|
|
|
func (m *Message) MarshalTo(w io.Writer) (n int, err error) {
|
2018-07-29 23:44:23 +08:00
|
|
|
m.Header.SetQdcount(1)
|
|
|
|
m.Header.SetAncount(len(m.Answers))
|
|
|
|
|
2020-08-23 23:23:30 +08:00
|
|
|
nn := 0
|
|
|
|
nn, err = m.Header.MarshalTo(w)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
n += nn
|
|
|
|
|
|
|
|
nn, err = m.Question.MarshalTo(w)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
n += nn
|
2018-07-29 23:44:23 +08:00
|
|
|
|
2018-07-31 00:03:36 +08:00
|
|
|
for _, answer := range m.Answers {
|
2020-08-23 23:23:30 +08:00
|
|
|
nn, err = answer.MarshalTo(w)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
n += nn
|
2018-07-31 00:03:36 +08:00
|
|
|
}
|
2018-07-29 23:44:23 +08:00
|
|
|
|
2020-08-23 23:23:30 +08:00
|
|
|
return
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
|
|
|
|
2019-03-12 23:32:23 +08:00
|
|
|
// UnmarshalMessage unmarshals []bytes to Message.
|
2018-07-30 01:05:08 +08:00
|
|
|
func UnmarshalMessage(b []byte) (*Message, error) {
|
2018-08-06 08:41:54 +08:00
|
|
|
if len(b) < HeaderLen {
|
2018-08-06 08:03:07 +08:00
|
|
|
return nil, errors.New("UnmarshalMessage: not enough data")
|
|
|
|
}
|
|
|
|
|
2018-08-02 00:11:22 +08:00
|
|
|
m := &Message{unMarshaled: b}
|
2022-03-06 12:58:20 +08:00
|
|
|
if err := UnmarshalHeader(b[:HeaderLen], &m.Header); err != nil {
|
2018-07-30 01:05:08 +08:00
|
|
|
return nil, err
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
q := &Question{}
|
2018-08-02 00:11:22 +08:00
|
|
|
qLen, err := m.UnmarshalQuestion(b[HeaderLen:], q)
|
2018-07-29 23:44:23 +08:00
|
|
|
if err != nil {
|
2018-07-30 01:05:08 +08:00
|
|
|
return nil, err
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
2018-08-02 00:11:22 +08:00
|
|
|
m.SetQuestion(q)
|
2018-07-29 23:44:23 +08:00
|
|
|
|
|
|
|
// resp answers
|
2018-08-02 00:11:22 +08:00
|
|
|
rrIdx := HeaderLen + qLen
|
|
|
|
for i := 0; i < int(m.Header.ANCOUNT); i++ {
|
2018-07-29 23:44:23 +08:00
|
|
|
rr := &RR{}
|
2018-08-02 00:11:22 +08:00
|
|
|
rrLen, err := m.UnmarshalRR(rrIdx, rr)
|
2018-07-29 23:44:23 +08:00
|
|
|
if err != nil {
|
2018-07-30 01:05:08 +08:00
|
|
|
return nil, err
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
2018-08-02 00:11:22 +08:00
|
|
|
m.AddAnswer(rr)
|
2018-07-30 00:18:10 +08:00
|
|
|
|
2018-08-02 00:11:22 +08:00
|
|
|
rrIdx += rrLen
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
|
|
|
|
2018-08-02 00:11:22 +08:00
|
|
|
m.Header.SetAncount(len(m.Answers))
|
2018-07-29 23:44:23 +08:00
|
|
|
|
2018-08-02 00:11:22 +08:00
|
|
|
return m, nil
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
|
|
|
|
2020-05-06 20:10:18 +08:00
|
|
|
// Header format:
|
2021-08-04 19:13:22 +08:00
|
|
|
// https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1
|
2018-07-29 23:44:23 +08:00
|
|
|
// The header contains the following fields:
|
|
|
|
//
|
2023-11-28 18:26:33 +08:00
|
|
|
// 1 1 1 1 1 1
|
|
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | ID |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | QDCOUNT |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | ANCOUNT |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | NSCOUNT |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | ARCOUNT |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
2018-07-29 23:44:23 +08:00
|
|
|
type Header struct {
|
|
|
|
ID uint16
|
|
|
|
Bits uint16
|
|
|
|
QDCOUNT uint16
|
|
|
|
ANCOUNT uint16
|
|
|
|
NSCOUNT uint16
|
|
|
|
ARCOUNT uint16
|
|
|
|
}
|
|
|
|
|
2019-03-12 23:32:23 +08:00
|
|
|
// SetMsgType sets the message type.
|
2022-01-22 23:33:08 +08:00
|
|
|
func (h *Header) SetMsgType(qr MsgType) {
|
2018-07-29 23:44:23 +08:00
|
|
|
h.Bits |= uint16(qr) << 15
|
|
|
|
}
|
|
|
|
|
2019-03-12 23:32:23 +08:00
|
|
|
// SetTC sets the tc flag.
|
2018-07-31 00:03:36 +08:00
|
|
|
func (h *Header) SetTC(tc int) {
|
|
|
|
h.Bits |= uint16(tc) << 9
|
|
|
|
}
|
|
|
|
|
2019-03-12 23:32:23 +08:00
|
|
|
// SetQdcount sets query count, most dns servers only support 1 query per request.
|
2018-07-29 23:44:23 +08:00
|
|
|
func (h *Header) SetQdcount(qdcount int) {
|
|
|
|
h.QDCOUNT = uint16(qdcount)
|
|
|
|
}
|
|
|
|
|
2019-03-12 23:32:23 +08:00
|
|
|
// SetAncount sets answers count.
|
2018-07-29 23:44:23 +08:00
|
|
|
func (h *Header) SetAncount(ancount int) {
|
|
|
|
h.ANCOUNT = uint16(ancount)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *Header) setFlag(QR uint16, Opcode uint16, AA uint16,
|
|
|
|
TC uint16, RD uint16, RA uint16, RCODE uint16) {
|
|
|
|
h.Bits = QR<<15 + Opcode<<11 + AA<<10 + TC<<9 + RD<<8 + RA<<7 + RCODE
|
|
|
|
}
|
|
|
|
|
2020-04-20 12:41:53 +08:00
|
|
|
// MarshalTo marshals header struct to []byte and write to w.
|
|
|
|
func (h *Header) MarshalTo(w io.Writer) (int, error) {
|
|
|
|
return HeaderLen, binary.Write(w, binary.BigEndian, h)
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
|
|
|
|
2019-03-12 23:32:23 +08:00
|
|
|
// UnmarshalHeader unmarshals []bytes to Header.
|
2018-07-29 23:44:23 +08:00
|
|
|
func UnmarshalHeader(b []byte, h *Header) error {
|
|
|
|
if h == nil {
|
|
|
|
return errors.New("unmarshal header must not be nil")
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(b) != HeaderLen {
|
|
|
|
return errors.New("unmarshal header bytes has an unexpected size")
|
|
|
|
}
|
|
|
|
|
|
|
|
h.ID = binary.BigEndian.Uint16(b[:2])
|
|
|
|
h.Bits = binary.BigEndian.Uint16(b[2:4])
|
|
|
|
h.QDCOUNT = binary.BigEndian.Uint16(b[4:6])
|
|
|
|
h.ANCOUNT = binary.BigEndian.Uint16(b[6:8])
|
|
|
|
h.NSCOUNT = binary.BigEndian.Uint16(b[8:10])
|
|
|
|
h.ARCOUNT = binary.BigEndian.Uint16(b[10:])
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-05-06 20:10:18 +08:00
|
|
|
// Question format:
|
2021-08-04 19:13:22 +08:00
|
|
|
// https://www.rfc-editor.org/rfc/rfc1035#section-4.1.2
|
2018-07-29 23:44:23 +08:00
|
|
|
// The question section is used to carry the "question" in most queries,
|
|
|
|
// i.e., the parameters that define what is being asked. The section
|
|
|
|
// contains QDCOUNT (usually 1) entries, each of the following format:
|
|
|
|
//
|
2023-11-28 18:26:33 +08:00
|
|
|
// 1 1 1 1 1 1
|
|
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | |
|
|
|
|
// / QNAME /
|
|
|
|
// / /
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | QTYPE |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | QCLASS |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
2018-07-29 23:44:23 +08:00
|
|
|
type Question struct {
|
|
|
|
QNAME string
|
|
|
|
QTYPE uint16
|
|
|
|
QCLASS uint16
|
|
|
|
}
|
|
|
|
|
2019-03-12 23:32:23 +08:00
|
|
|
// NewQuestion returns a new dns question.
|
2018-07-29 23:44:23 +08:00
|
|
|
func NewQuestion(qtype uint16, domain string) *Question {
|
|
|
|
return &Question{
|
|
|
|
QNAME: domain,
|
|
|
|
QTYPE: qtype,
|
2018-08-02 00:11:22 +08:00
|
|
|
QCLASS: ClassINET,
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-20 12:41:53 +08:00
|
|
|
// MarshalTo marshals Question struct to []byte and write to w.
|
2020-08-23 23:23:30 +08:00
|
|
|
func (q *Question) MarshalTo(w io.Writer) (n int, err error) {
|
|
|
|
n, err = MarshalDomainTo(w, q.QNAME)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2018-07-29 23:44:23 +08:00
|
|
|
|
2022-03-06 12:58:20 +08:00
|
|
|
if err = binary.Write(w, binary.BigEndian, q.QTYPE); err != nil {
|
2020-08-23 23:23:30 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
n += 2
|
2018-07-29 23:44:23 +08:00
|
|
|
|
2022-03-06 12:58:20 +08:00
|
|
|
if err = binary.Write(w, binary.BigEndian, q.QCLASS); err != nil {
|
2020-08-23 23:23:30 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
n += 2
|
|
|
|
|
|
|
|
return
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
|
|
|
|
2019-03-12 23:32:23 +08:00
|
|
|
// UnmarshalQuestion unmarshals []bytes to Question.
|
2018-07-29 23:44:23 +08:00
|
|
|
func (m *Message) UnmarshalQuestion(b []byte, q *Question) (n int, err error) {
|
|
|
|
if q == nil {
|
|
|
|
return 0, errors.New("unmarshal question must not be nil")
|
|
|
|
}
|
|
|
|
|
2018-08-06 08:03:07 +08:00
|
|
|
if len(b) <= 5 {
|
|
|
|
return 0, errors.New("UnmarshalQuestion: not enough data")
|
|
|
|
}
|
|
|
|
|
2020-08-26 19:21:35 +08:00
|
|
|
sb := new(strings.Builder)
|
|
|
|
sb.Grow(32)
|
|
|
|
idx, err := m.UnmarshalDomainTo(sb, b)
|
2018-07-31 00:03:36 +08:00
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2020-08-26 19:21:35 +08:00
|
|
|
q.QNAME = sb.String()
|
2018-07-29 23:44:23 +08:00
|
|
|
q.QTYPE = binary.BigEndian.Uint16(b[idx : idx+2])
|
|
|
|
q.QCLASS = binary.BigEndian.Uint16(b[idx+2 : idx+4])
|
|
|
|
|
|
|
|
return idx + 3 + 1, nil
|
|
|
|
}
|
|
|
|
|
2020-05-06 20:10:18 +08:00
|
|
|
// RR format:
|
2021-08-04 19:13:22 +08:00
|
|
|
// https://www.rfc-editor.org/rfc/rfc1035#section-3.2.1
|
|
|
|
// https://www.rfc-editor.org/rfc/rfc1035#section-4.1.3
|
2018-07-29 23:44:23 +08:00
|
|
|
// The answer, authority, and additional sections all share the same
|
|
|
|
// format: a variable number of resource records, where the number of
|
|
|
|
// records is specified in the corresponding count field in the header.
|
|
|
|
// Each resource record has the following format:
|
|
|
|
//
|
2023-11-28 18:26:33 +08:00
|
|
|
// 1 1 1 1 1 1
|
|
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | |
|
|
|
|
// / /
|
|
|
|
// / NAME /
|
|
|
|
// | |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | TYPE |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | CLASS |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | TTL |
|
|
|
|
// | |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | RDLENGTH |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
|
|
|
|
// / RDATA /
|
|
|
|
// / /
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
2018-07-29 23:44:23 +08:00
|
|
|
type RR struct {
|
|
|
|
NAME string
|
|
|
|
TYPE uint16
|
|
|
|
CLASS uint16
|
|
|
|
TTL uint32
|
|
|
|
RDLENGTH uint16
|
|
|
|
RDATA []byte
|
|
|
|
|
2022-01-29 21:10:09 +08:00
|
|
|
IP netip.Addr
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
|
|
|
|
2019-03-12 23:32:23 +08:00
|
|
|
// NewRR returns a new dns rr.
|
2018-07-29 23:44:23 +08:00
|
|
|
func NewRR() *RR {
|
2020-05-06 20:10:18 +08:00
|
|
|
return &RR{}
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
|
|
|
|
2020-04-20 12:41:53 +08:00
|
|
|
// MarshalTo marshals RR struct to []byte and write to w.
|
2020-08-23 23:23:30 +08:00
|
|
|
func (rr *RR) MarshalTo(w io.Writer) (n int, err error) {
|
|
|
|
n, err = MarshalDomainTo(w, rr.NAME)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2018-07-31 00:03:36 +08:00
|
|
|
|
2022-03-06 12:58:20 +08:00
|
|
|
if err = binary.Write(w, binary.BigEndian, rr.TYPE); err != nil {
|
2020-08-23 23:23:30 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
n += 2
|
|
|
|
|
2022-03-06 12:58:20 +08:00
|
|
|
if err = binary.Write(w, binary.BigEndian, rr.CLASS); err != nil {
|
2020-08-23 23:23:30 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
n += 2
|
|
|
|
|
2022-03-06 12:58:20 +08:00
|
|
|
if err = binary.Write(w, binary.BigEndian, rr.TTL); err != nil {
|
2020-08-23 23:23:30 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
n += 4
|
|
|
|
|
|
|
|
err = binary.Write(w, binary.BigEndian, rr.RDLENGTH)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
n += 2
|
2018-07-31 00:03:36 +08:00
|
|
|
|
2022-03-06 12:58:20 +08:00
|
|
|
if _, err = w.Write(rr.RDATA); err != nil {
|
2020-08-23 23:23:30 +08:00
|
|
|
return
|
|
|
|
}
|
2020-04-20 12:41:53 +08:00
|
|
|
n += len(rr.RDATA)
|
|
|
|
|
2020-08-23 23:23:30 +08:00
|
|
|
return
|
2018-07-31 00:03:36 +08:00
|
|
|
}
|
|
|
|
|
2019-03-12 23:32:23 +08:00
|
|
|
// UnmarshalRR unmarshals []bytes to RR.
|
2018-07-29 23:44:23 +08:00
|
|
|
func (m *Message) UnmarshalRR(start int, rr *RR) (n int, err error) {
|
|
|
|
if rr == nil {
|
2018-07-31 00:03:36 +08:00
|
|
|
return 0, errors.New("unmarshal rr must not be nil")
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
p := m.unMarshaled[start:]
|
2018-07-30 00:18:10 +08:00
|
|
|
|
2020-08-26 19:21:35 +08:00
|
|
|
sb := new(strings.Builder)
|
|
|
|
sb.Grow(32)
|
|
|
|
|
|
|
|
n, err = m.UnmarshalDomainTo(sb, p)
|
2018-07-31 00:03:36 +08:00
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
2020-08-26 19:21:35 +08:00
|
|
|
rr.NAME = sb.String()
|
2018-07-29 23:44:23 +08:00
|
|
|
|
|
|
|
if len(p) <= n+10 {
|
2018-07-31 00:03:36 +08:00
|
|
|
return 0, errors.New("UnmarshalRR: not enough data")
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
rr.TYPE = binary.BigEndian.Uint16(p[n:])
|
|
|
|
rr.CLASS = binary.BigEndian.Uint16(p[n+2:])
|
|
|
|
rr.TTL = binary.BigEndian.Uint32(p[n+4:])
|
|
|
|
rr.RDLENGTH = binary.BigEndian.Uint16(p[n+8:])
|
2018-09-01 23:44:47 +08:00
|
|
|
|
2018-09-02 00:16:16 +08:00
|
|
|
if len(p) < n+10+int(rr.RDLENGTH) {
|
2018-09-01 23:44:47 +08:00
|
|
|
return 0, errors.New("UnmarshalRR: not enough data for RDATA")
|
|
|
|
}
|
|
|
|
|
2018-07-29 23:44:23 +08:00
|
|
|
rr.RDATA = p[n+10 : n+10+int(rr.RDLENGTH)]
|
|
|
|
|
|
|
|
if rr.TYPE == QTypeA {
|
2022-01-29 21:10:09 +08:00
|
|
|
rr.IP = netip.AddrFrom4(*(*[4]byte)(rr.RDATA[:4]))
|
2018-07-29 23:44:23 +08:00
|
|
|
} else if rr.TYPE == QTypeAAAA {
|
2022-01-29 21:10:09 +08:00
|
|
|
rr.IP = netip.AddrFrom16(*(*[16]byte)(rr.RDATA[:16]))
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
n = n + 10 + int(rr.RDLENGTH)
|
|
|
|
|
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
2020-04-20 12:41:53 +08:00
|
|
|
// MarshalDomainTo marshals domain string struct to []byte and write to w.
|
2020-08-23 23:23:30 +08:00
|
|
|
func MarshalDomainTo(w io.Writer, domain string) (n int, err error) {
|
|
|
|
nn := 0
|
2018-07-29 23:44:23 +08:00
|
|
|
for _, seg := range strings.Split(domain, ".") {
|
2020-08-23 23:23:30 +08:00
|
|
|
nn, err = w.Write([]byte{byte(len(seg))})
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
n += nn
|
|
|
|
|
|
|
|
nn, err = io.WriteString(w, seg)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
n += nn
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
|
|
|
|
2020-08-23 23:23:30 +08:00
|
|
|
nn, err = w.Write([]byte{0x00})
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
n += nn
|
|
|
|
|
|
|
|
return
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
|
|
|
|
2020-08-26 19:21:35 +08:00
|
|
|
// UnmarshalDomainTo gets domain from bytes to string builder.
|
|
|
|
func (m *Message) UnmarshalDomainTo(sb *strings.Builder, b []byte) (int, error) {
|
2018-07-29 23:44:23 +08:00
|
|
|
var idx, size int
|
|
|
|
|
2020-08-26 19:21:35 +08:00
|
|
|
for len(b[idx:]) != 0 {
|
2021-08-04 19:13:22 +08:00
|
|
|
// https://www.rfc-editor.org/rfc/rfc1035#section-4.1.4
|
2018-07-30 01:05:08 +08:00
|
|
|
// "Message compression",
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | 1 1| OFFSET |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
2020-08-26 19:21:35 +08:00
|
|
|
if b[idx]&0xC0 == 0xC0 {
|
2020-08-21 23:54:18 +08:00
|
|
|
if len(b[idx:]) < 2 {
|
2020-08-26 19:21:35 +08:00
|
|
|
return 0, errors.New("UnmarshalDomainTo: not enough size for compressed domain")
|
2020-08-21 23:54:18 +08:00
|
|
|
}
|
|
|
|
|
2018-07-29 23:44:23 +08:00
|
|
|
offset := binary.BigEndian.Uint16(b[idx : idx+2])
|
2022-03-06 12:58:20 +08:00
|
|
|
if err := m.UnmarshalDomainPointTo(sb, int(offset&0x3FFF)); err != nil {
|
2020-08-26 19:21:35 +08:00
|
|
|
return 0, err
|
2018-07-31 00:03:36 +08:00
|
|
|
}
|
|
|
|
|
2018-07-29 23:44:23 +08:00
|
|
|
idx += 2
|
|
|
|
break
|
2020-08-26 19:21:35 +08:00
|
|
|
}
|
2020-05-06 20:10:18 +08:00
|
|
|
|
2020-08-26 19:21:35 +08:00
|
|
|
size = int(b[idx])
|
|
|
|
idx++
|
2020-05-06 20:10:18 +08:00
|
|
|
|
2020-08-26 19:21:35 +08:00
|
|
|
// root domain name
|
|
|
|
if size == 0 {
|
|
|
|
break
|
|
|
|
}
|
2018-08-02 00:11:22 +08:00
|
|
|
|
2020-08-26 19:21:35 +08:00
|
|
|
if size > 63 {
|
|
|
|
return 0, errors.New("UnmarshalDomainTo: label size larger than 63")
|
|
|
|
}
|
2018-07-31 00:03:36 +08:00
|
|
|
|
2020-08-26 19:21:35 +08:00
|
|
|
if idx+size > len(b) {
|
|
|
|
return 0, errors.New("UnmarshalDomainTo: label size larger than msg length")
|
|
|
|
}
|
2018-07-31 00:03:36 +08:00
|
|
|
|
2020-08-26 19:21:35 +08:00
|
|
|
if sb.Len() > 0 {
|
|
|
|
sb.WriteByte('.')
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
2020-08-26 19:21:35 +08:00
|
|
|
sb.Write(b[idx : idx+size])
|
2020-05-06 20:10:18 +08:00
|
|
|
|
2020-08-26 19:21:35 +08:00
|
|
|
idx += size
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
|
|
|
|
2020-08-26 19:21:35 +08:00
|
|
|
return idx, nil
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|
|
|
|
|
2020-08-26 19:21:35 +08:00
|
|
|
// UnmarshalDomainPointTo gets domain from offset point to string builder.
|
|
|
|
func (m *Message) UnmarshalDomainPointTo(sb *strings.Builder, offset int) error {
|
2018-07-31 00:03:36 +08:00
|
|
|
if offset > len(m.unMarshaled) {
|
2020-08-26 19:21:35 +08:00
|
|
|
return errors.New("UnmarshalDomainPointTo: offset larger than msg length")
|
2018-07-31 00:03:36 +08:00
|
|
|
}
|
2020-08-26 19:21:35 +08:00
|
|
|
_, err := m.UnmarshalDomainTo(sb, m.unMarshaled[offset:])
|
|
|
|
return err
|
2018-07-29 23:44:23 +08:00
|
|
|
}
|