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