1package magna
2
3import (
4 "fmt"
5 "math/rand"
6)
7
8// Decode decodes a DNS packet.
9func (m *Message) Decode(buf []byte) (err error) {
10 offset, err := m.Header.Decode(buf, 0)
11 if err != nil {
12 return fmt.Errorf("failed to decode message header: %w", err)
13 }
14
15 m.Question = make([]Question, 0, m.Header.QDCount)
16 for i := range m.Header.QDCount {
17 var question Question
18 offset, err = question.Decode(buf, offset)
19 if err != nil {
20 return fmt.Errorf("failed to decode question #%d: %w", i+1, err)
21 }
22
23 m.Question = append(m.Question, question)
24 }
25
26 m.Answer = make([]ResourceRecord, 0, m.Header.ANCount)
27 for i := range m.Header.ANCount {
28 var rr ResourceRecord
29 offset, err = rr.Decode(buf, offset)
30 if err != nil {
31 return fmt.Errorf("failed to decode answer record #%d: %w", i+1, err)
32 }
33
34 m.Answer = append(m.Answer, rr)
35 }
36
37 m.Authority = make([]ResourceRecord, 0, m.Header.NSCount)
38 for i := range m.Header.NSCount {
39 var rr ResourceRecord
40 offset, err = rr.Decode(buf, offset)
41 if err != nil {
42 return fmt.Errorf("failed to decode authority record #%d: %w", i+1, err)
43 }
44
45 m.Authority = append(m.Authority, rr)
46 }
47
48 m.Additional = make([]ResourceRecord, 0, m.Header.ARCount)
49 for i := range m.Header.ARCount {
50 var rr ResourceRecord
51 offset, err = rr.Decode(buf, offset)
52 if err != nil {
53 return fmt.Errorf("failed to decode additional record #%d: %w", i+1, err)
54 }
55
56 m.Additional = append(m.Additional, rr)
57 }
58
59 return nil
60}
61
62// Encode encodes a message to a DNS packet.
63// TODO: set truncation bit if over 512 and udp is protocol
64func (m *Message) Encode() ([]byte, error) {
65 m.offsets = make(map[string]uint16)
66 bytes := make([]byte, 0, 512)
67
68 headerBytes := m.Header.Encode()
69 bytes = append(bytes, headerBytes...)
70
71 var err error
72
73 for i, question := range m.Question {
74 bytes, err = question.Encode(bytes, &m.offsets)
75 if err != nil {
76 return nil, fmt.Errorf("failed to encode question #%d (%s): %w", i+1, question.QName, err)
77 }
78 }
79
80 for i, answer := range m.Answer {
81 bytes, err = answer.Encode(bytes, &m.offsets)
82 if err != nil {
83 return nil, fmt.Errorf("failed to encode answer record #%d (%s): %w", i+1, answer.Name, err)
84 }
85 }
86
87 for i, authority := range m.Authority {
88 bytes, err = authority.Encode(bytes, &m.offsets)
89 if err != nil {
90 return nil, fmt.Errorf("failed to encode authority record #%d (%s): %w", i+1, authority.Name, err)
91 }
92 }
93
94 for i, additional := range m.Additional {
95 bytes, err = additional.Encode(bytes, &m.offsets)
96 if err != nil {
97 return nil, fmt.Errorf("failed to encode additional record #%d (%s): %w", i+1, additional.Name, err)
98 }
99 }
100
101 return bytes, nil
102}
103
104func CreateRequest(op OPCode, rd bool) *Message {
105 return &Message{
106 Header: Header{
107 ID: uint16(rand.Intn(65534) + 1),
108 QR: false,
109 OPCode: op,
110 AA: false,
111 TC: false,
112 RD: rd,
113 RA: false,
114 Z: 0,
115 RCode: NOERROR,
116 QDCount: 0,
117 ARCount: 0,
118 NSCount: 0,
119 ANCount: 0,
120 },
121 Question: make([]Question, 0),
122 Answer: make([]ResourceRecord, 0),
123 Additional: make([]ResourceRecord, 0),
124 Authority: make([]ResourceRecord, 0),
125 }
126}
127
128func (m *Message) CreateReply(req *Message) *Message {
129 m.Header.ID = req.Header.ID
130 m.Header.QR = true
131 m.Header.OPCode = req.Header.OPCode
132
133 return m
134}
135
136func (m *Message) AddQuestion(q Question) *Message {
137 m.Header.QDCount += 1
138 m.Question = append(m.Question, q)
139
140 return m
141}
142
143func (m *Message) SetRCode(rc RCode) *Message {
144 m.Header.RCode = rc
145
146 return m
147}