1package magna
2
3import (
4 "bytes"
5 "encoding/binary"
6 "net"
7 "testing"
8
9 "github.com/stretchr/testify/assert"
10)
11
12func TestMessageDecode(t *testing.T) {
13 tests := []struct {
14 name string
15 input []byte
16 expected Message
17 wantErr bool
18 }{
19 {
20 name: "Valid DNS message with one question",
21 input: func() []byte {
22 buf := new(bytes.Buffer)
23 binary.Write(buf, binary.BigEndian, uint16(1234))
24 binary.Write(buf, binary.BigEndian, uint16(0x0100))
25 binary.Write(buf, binary.BigEndian, uint16(1))
26 binary.Write(buf, binary.BigEndian, uint16(0))
27 binary.Write(buf, binary.BigEndian, uint16(0))
28 binary.Write(buf, binary.BigEndian, uint16(0))
29 buf.Write([]byte{3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0})
30 binary.Write(buf, binary.BigEndian, uint16(1))
31 binary.Write(buf, binary.BigEndian, uint16(1))
32 return buf.Bytes()
33 }(),
34 expected: Message{
35 Header: Header{
36 ID: 1234,
37 QR: false,
38 RD: true,
39 OPCode: 0,
40 QDCount: 1,
41 },
42 Question: []Question{
43 {
44 QName: "www.example.com",
45 QType: 1,
46 QClass: 1,
47 },
48 },
49 },
50 wantErr: false,
51 },
52 {
53 name: "Valid DNS message with one answer",
54 input: func() []byte {
55 buf := new(bytes.Buffer)
56 binary.Write(buf, binary.BigEndian, uint16(5678))
57 binary.Write(buf, binary.BigEndian, uint16(0x8180))
58 binary.Write(buf, binary.BigEndian, uint16(0))
59 binary.Write(buf, binary.BigEndian, uint16(1))
60 binary.Write(buf, binary.BigEndian, uint16(0))
61 binary.Write(buf, binary.BigEndian, uint16(0))
62 buf.Write([]byte{3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0})
63 binary.Write(buf, binary.BigEndian, uint16(1))
64 binary.Write(buf, binary.BigEndian, uint16(1))
65 binary.Write(buf, binary.BigEndian, uint32(3600))
66 binary.Write(buf, binary.BigEndian, uint16(4))
67 binary.Write(buf, binary.BigEndian, uint32(0x0A000001))
68 return buf.Bytes()
69 }(),
70 expected: Message{
71 Header: Header{
72 ID: 5678,
73 QR: true,
74 OPCode: 0,
75 AA: false,
76 RD: true,
77 RA: true,
78 RCode: 0,
79 ANCount: 1,
80 },
81 Answer: []ResourceRecord{
82 {
83 Name: "www.example.com",
84 RType: 1,
85 RClass: 1,
86 TTL: 3600,
87 RDLength: 4,
88 RData: &A{net.IP([]byte{10, 0, 0, 1})},
89 },
90 },
91 },
92 wantErr: false,
93 },
94 {
95 name: "Invalid input - empty buffer",
96 input: []byte{},
97 wantErr: true,
98 },
99 }
100
101 for _, tt := range tests {
102 t.Run(tt.name, func(t *testing.T) {
103 m := &Message{}
104 err := m.Decode(tt.input)
105
106 if tt.wantErr {
107 assert.Error(t, err)
108 } else {
109 assert.NoError(t, err)
110 assert.Equal(t, tt.expected.Header, m.Header)
111 assert.Equal(t, tt.expected.Question, m.Question)
112 assert.Equal(t, tt.expected.Answer, m.Answer)
113 assert.Equal(t, tt.expected.Authority, m.Authority)
114 assert.Equal(t, tt.expected.Additional, m.Additional)
115 }
116 })
117 }
118}
119
120func FuzzDecodeMessage(f *testing.F) {
121 testcases := [][]byte{
122 {
123 0x8e, 0x19, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6e, 0x65,
124 0x77, 0x73, 0x0b, 0x79, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x03,
125 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00,
126 0x00, 0x00, 0x01, 0x00, 0x04, 0xd1, 0xd8, 0xe6, 0xcf,
127 },
128 }
129 for _, tc := range testcases {
130 f.Add(tc)
131 }
132 f.Fuzz(func(t *testing.T, msg []byte) {
133 var m Message
134 m.Decode(msg)
135 })
136}