@@ -3,9 +3,11 @@ package layers
3
3
import (
4
4
"encoding/binary"
5
5
"fmt"
6
+ "strings"
7
+ "unsafe"
6
8
)
7
9
8
- const dnsHeaderSize = 12
10
+ const headerSizeDNS = 12
9
11
10
12
type DNSMessage struct {
11
13
TransactionID uint16 // Used for matching response to queries.
@@ -27,6 +29,7 @@ func (d *DNSMessage) String() string {
27
29
- Authority RRs: %d
28
30
- Additional RRs: %d
29
31
- Payload: %d bytes
32
+ %s
30
33
` ,
31
34
d .TransactionID ,
32
35
d .Flags ,
@@ -36,21 +39,22 @@ func (d *DNSMessage) String() string {
36
39
d .AuthorityRRs ,
37
40
d .AdditionalRRs ,
38
41
len (d .payload ),
42
+ d .queries (),
39
43
)
40
44
}
41
45
42
46
// Parse parses the given byte data into a DNSMessage struct.
43
47
func (d * DNSMessage ) Parse (data []byte ) error {
44
- if len (data ) < dnsHeaderSize {
45
- return fmt .Errorf ("minimum header size for DNS is %d bytes, got %d bytes" , dnsHeaderSize , len (data ))
48
+ if len (data ) < headerSizeDNS {
49
+ return fmt .Errorf ("minimum header size for DNS is %d bytes, got %d bytes" , headerSizeDNS , len (data ))
46
50
}
47
51
d .TransactionID = binary .BigEndian .Uint16 (data [0 :2 ])
48
52
d .Flags = binary .BigEndian .Uint16 (data [2 :4 ])
49
53
d .Questions = binary .BigEndian .Uint16 (data [4 :6 ])
50
54
d .AnswerRRs = binary .BigEndian .Uint16 (data [6 :8 ])
51
55
d .AuthorityRRs = binary .BigEndian .Uint16 (data [8 :10 ])
52
- d .AdditionalRRs = binary .BigEndian .Uint16 (data [10 :dnsHeaderSize ])
53
- d .payload = data [dnsHeaderSize :]
56
+ d .AdditionalRRs = binary .BigEndian .Uint16 (data [10 :headerSizeDNS ])
57
+ d .payload = data [headerSizeDNS :]
54
58
return nil
55
59
}
56
60
@@ -79,15 +83,15 @@ func (d *DNSMessage) flags() string {
79
83
default :
80
84
opcodes = "Unknown"
81
85
}
86
+ tc := (d .Flags >> 9 ) & 1
87
+ rd := (d .Flags >> 8 ) & 1
88
+ z := (d .Flags >> 6 ) & 1
89
+ na := (d .Flags >> 4 ) & 1
82
90
qr := (d .Flags >> 15 ) & 1
83
91
var qrs string
84
92
switch qr {
85
93
case 0 :
86
94
qrs = "query"
87
- tc := (d .Flags >> 9 ) & 1
88
- rd := (d .Flags >> 8 ) & 1
89
- z := (d .Flags >> 6 ) & 1
90
- na := (d .Flags >> 4 ) & 1
91
95
flags = fmt .Sprintf (` - Response: Message is a %s (%d)
92
96
- Opcode: %s (%d)
93
97
- Truncated: %d
@@ -97,12 +101,8 @@ func (d *DNSMessage) flags() string {
97
101
case 1 :
98
102
qrs = "reply"
99
103
a := (d .Flags >> 10 ) & 1
100
- tc := (d .Flags >> 9 ) & 1
101
- rd := (d .Flags >> 8 ) & 1
102
104
ra := (d .Flags >> 7 ) & 1
103
- z := (d .Flags >> 6 ) & 1
104
105
aa := (d .Flags >> 5 ) & 1
105
- na := (d .Flags >> 4 ) & 1
106
106
rcode := d .Flags & 15
107
107
var rcodes string
108
108
switch rcode {
@@ -142,3 +142,72 @@ func (d *DNSMessage) flags() string {
142
142
}
143
143
return flags
144
144
}
145
+
146
+ func bytesToStr (myBytes []byte ) string {
147
+ return unsafe .String (unsafe .SliceData (myBytes ), len (myBytes ))
148
+ }
149
+
150
+ func extractDomain (data []byte , offset int ) (string , int ) {
151
+ var parts []string
152
+ for {
153
+ blen := int (data [offset ])
154
+ offset ++
155
+ if blen == 0 {
156
+ break
157
+ }
158
+ if blen == 0xc0 {
159
+ offset = int (data [offset ]) - headerSizeDNS
160
+ blen = int (data [offset ])
161
+ offset ++
162
+ }
163
+ parts = append (parts , bytesToStr (data [offset :offset + blen ]))
164
+ offset += blen
165
+ }
166
+ return strings .Join (parts , "." ), offset
167
+ }
168
+
169
+ func (d * DNSMessage ) queries () string {
170
+ var (
171
+ sb strings.Builder
172
+ offset int
173
+ )
174
+ if d .Questions > 0 {
175
+ sb .WriteString ("- Queries:\n " )
176
+ for range d .Questions {
177
+ var domain string
178
+ domain , offset = extractDomain (d .payload , offset )
179
+ typ := binary .BigEndian .Uint16 (d .payload [offset : offset + 2 ])
180
+ offset += 2
181
+ class := binary .BigEndian .Uint16 (d .payload [offset : offset + 2 ])
182
+ offset += 2
183
+ // TODO: add type and class description https://en.wikipedia.org/wiki/List_of_DNS_record_types
184
+ sb .WriteString (fmt .Sprintf (" %s: type %d class %d\n " , domain , typ , class ))
185
+ }
186
+ }
187
+ if d .AnswerRRs > 0 {
188
+ sb .WriteString ("- Answers:\n " )
189
+ for range d .AnswerRRs {
190
+ no := binary .BigEndian .Uint16 (d .payload [offset : offset + 2 ])
191
+ offset += 2
192
+ domain , _ := extractDomain (d .payload , int (no & 0xFF )- headerSizeDNS )
193
+ typ := binary .BigEndian .Uint16 (d .payload [offset : offset + 2 ])
194
+ offset += 2
195
+ class := binary .BigEndian .Uint16 (d .payload [offset : offset + 2 ])
196
+ offset += 2
197
+ ttl := binary .BigEndian .Uint32 (d .payload [offset : offset + 4 ])
198
+ offset += 4
199
+ rdl := int (binary .BigEndian .Uint16 (d .payload [offset : offset + 2 ]))
200
+ offset += 2
201
+ //rdata := d.payload[offset : offset+rdl]
202
+ offset += rdl
203
+ sb .WriteString (fmt .Sprintf (" %s: type %d class %d ttl %d rdl %d\n " , domain , typ , class , ttl , rdl ))
204
+ }
205
+ }
206
+ if d .AuthorityRRs > 0 {
207
+
208
+ }
209
+ if d .AdditionalRRs > 0 {
210
+
211
+ }
212
+ return sb .String ()
213
+ }
0 commit comments