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 := make([]byte, 0, 512)
62 bytes = append(bytes, m.Header.Encode()...)
63
64 for _, question := range m.Question {
65 bytes = question.Encode(bytes, &m.offsets)
66 }
67
68 for _, answer := range m.Answer {
69 bytes = answer.Encode(bytes, &m.offsets)
70 }
71
72 for _, authority := range m.Authority {
73 bytes = authority.Encode(bytes, &m.offsets)
74 }
75
76 for _, additional := range m.Additional {
77 bytes = additional.Encode(bytes, &m.offsets)
78 }
79
80 return bytes
81}
82
83func CreateRequest(op OPCode, rd bool) *Message {
84 return &Message{
85 Header: Header{
86 ID: uint16(rand.Intn(65534) + 1),
87 QR: false,
88 OPCode: op,
89 AA: false,
90 TC: false,
91 RD: rd,
92 RA: false,
93 Z: 0,
94 RCode: NOERROR,
95 QDCount: 0,
96 ARCount: 0,
97 NSCount: 0,
98 ANCount: 0,
99 },
100 Question: make([]Question, 0),
101 Answer: make([]ResourceRecord, 0),
102 Additional: make([]ResourceRecord, 0),
103 Authority: make([]ResourceRecord, 0),
104 }
105}
106
107func (m *Message) CreateReply(req *Message) *Message {
108 m.Header.ID = req.Header.ID
109 m.Header.QR = true
110 m.Header.OPCode = req.Header.OPCode
111
112 return m
113}
114
115func (m *Message) AddQuestion(q Question) *Message {
116 m.Header.QDCount += 1
117 m.Question = append(m.Question, q)
118
119 return m
120}
121
122func (m *Message) SetRCode(rc RCode) *Message {
123 m.Header.RCode = rc
124
125 return m
126}