Skip to content

Commit c8d6d83

Browse files
author
shadowy-pycoder
committed
Added basic parsing of rdata
1 parent f02ef26 commit c8d6d83

File tree

1 file changed

+135
-48
lines changed

1 file changed

+135
-48
lines changed

layers/dns.go

Lines changed: 135 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package layers
33
import (
44
"encoding/binary"
55
"fmt"
6+
"net/netip"
67
"strings"
78
"unsafe"
89
)
@@ -147,13 +148,13 @@ func bytesToStr(myBytes []byte) string {
147148
return unsafe.String(unsafe.SliceData(myBytes), len(myBytes))
148149
}
149150

150-
func extractDomain(data []byte, tail []byte) (string, []byte) {
151+
func (d *DNSMessage) extractDomain(tail []byte) (string, []byte) {
151152
var domainName string
152153
for {
153154
blen := tail[0]
154155
if blen>>6 == 0b11 {
155156
offset := binary.BigEndian.Uint16(tail[0:2])&(1<<14-1) - headerSizeDNS
156-
part, _ := extractDomain(data, data[offset:])
157+
part, _ := d.extractDomain(d.payload[offset:])
157158
domainName += part
158159
tail = tail[2:]
159160
break
@@ -167,76 +168,162 @@ func extractDomain(data []byte, tail []byte) (string, []byte) {
167168

168169
tail = tail[blen:]
169170
}
170-
return domainName, tail
171+
return strings.TrimRight(domainName, "."), tail
172+
}
173+
174+
func (d *DNSMessage) parseRData(typ uint16, tail []byte, rdl int) (string, string, []byte) {
175+
var rdata string
176+
var typname string
177+
switch typ {
178+
case 1:
179+
typname = "A"
180+
addr, _ := netip.AddrFromSlice(tail[0:rdl])
181+
rdata = fmt.Sprintf("Address: %s", addr)
182+
case 2:
183+
typname = "NS"
184+
domain, _ := d.extractDomain(tail)
185+
rdata = fmt.Sprintf("%s: %s", typname, domain)
186+
case 5:
187+
typname = "CNAME"
188+
domain, _ := d.extractDomain(tail)
189+
rdata = fmt.Sprintf("%s: %s", typname, domain)
190+
case 6:
191+
typname = "SOA"
192+
var (
193+
primary string
194+
mailbox string
195+
)
196+
ttail := tail
197+
primary, ttail = d.extractDomain(ttail)
198+
mailbox, ttail = d.extractDomain(ttail)
199+
serial := binary.BigEndian.Uint32(ttail[0:4])
200+
refresh := binary.BigEndian.Uint32(ttail[4:8])
201+
retry := binary.BigEndian.Uint32(ttail[8:12])
202+
expire := binary.BigEndian.Uint32(ttail[12:16])
203+
min := binary.BigEndian.Uint32(ttail[16:20])
204+
rdata = fmt.Sprintf(`Primary name server: %s
205+
- Responsible authority's mailbox: %s
206+
- Serial number: %d
207+
- Refresh interval: %d
208+
- Retry interval: %d
209+
- Expire limit: %d
210+
- Minimum TTL: %d
211+
`, primary, mailbox, serial, refresh, retry, expire, min)
212+
case 15:
213+
typname = "MX"
214+
preference := binary.BigEndian.Uint16(tail[0:2])
215+
domain, _ := d.extractDomain(tail[2:rdl])
216+
rdata = fmt.Sprintf("%s: preference %d %s", typname, preference, domain)
217+
case 16:
218+
typname = "TXT"
219+
rdata = fmt.Sprintf("%s: %s", typname, tail[:rdl])
220+
case 28:
221+
typname = "AAAA"
222+
addr, _ := netip.AddrFromSlice(tail[0:rdl])
223+
rdata = fmt.Sprintf("Address: %s", addr)
224+
case 41:
225+
typname = "OPT"
226+
default:
227+
rdata = fmt.Sprintf("Unknown: %d bytes", rdl)
228+
}
229+
return typname, rdata, tail[rdl:]
230+
}
231+
232+
func (d *DNSMessage) parseQuery(tail []byte) (string, []byte) {
233+
var domain string
234+
domain, tail = d.extractDomain(tail)
235+
typ := binary.BigEndian.Uint16(tail[0:2])
236+
class := binary.BigEndian.Uint16(tail[2:4])
237+
tail = tail[4:]
238+
// TODO: add type and class description https://en.wikipedia.org/wiki/List_of_DNS_record_types
239+
return fmt.Sprintf(` - %s:
240+
- Name: %s
241+
- Type: (%d)
242+
- Class: %d
243+
`, domain, domain, typ, class), tail
244+
}
245+
246+
func (d *DNSMessage) parseRR(tail []byte) (string, []byte) {
247+
var domain string
248+
domain, tail = d.extractDomain(tail)
249+
typ := binary.BigEndian.Uint16(tail[0:2])
250+
class := binary.BigEndian.Uint16(tail[2:4])
251+
ttl := binary.BigEndian.Uint32(tail[4:8])
252+
rdl := int(binary.BigEndian.Uint16(tail[8:10]))
253+
var (
254+
typename string
255+
rdata string
256+
)
257+
typename, rdata, tail = d.parseRData(typ, tail[10:], rdl)
258+
return fmt.Sprintf(` - %s:
259+
- Name: %s
260+
- Type: %s (%d)
261+
- Class: %d
262+
- TTL: %d
263+
- Data Length: %d
264+
- %s
265+
`, domain, domain, typename, typ, class, ttl, rdl, rdata), tail
266+
}
267+
268+
func (d *DNSMessage) parseRoot(tail []byte) (string, []byte) {
269+
domain := "Root"
270+
tail = tail[1:]
271+
typ := binary.BigEndian.Uint16(tail[0:2])
272+
ups := binary.BigEndian.Uint16(tail[2:4])
273+
hb := tail[4]
274+
ednsv := tail[5]
275+
zres := binary.BigEndian.Uint16(tail[6:8])
276+
rdl := int(binary.BigEndian.Uint16(tail[8:10]))
277+
var typename string
278+
typename, _, tail = d.parseRData(typ, tail[10:], rdl)
279+
return fmt.Sprintf(` - %s:
280+
- Name: %s
281+
- Type: %s (%d)
282+
- UDP payload size: %d
283+
- Higher bits in extended RCODE: %#02x
284+
- EDNS0 version: %d
285+
- Z: %d
286+
- Data Length: %d
287+
`, domain, domain, typename, typ, ups, hb, ednsv, zres, rdl), tail
171288
}
172289

173290
func (d *DNSMessage) rrecords() string {
174-
var sb strings.Builder
175-
tail := d.payload
291+
var (
292+
sb strings.Builder
293+
rec string
294+
tail = d.payload
295+
)
176296
if d.Questions > 0 {
177297
sb.WriteString("- Queries:\n")
178298
for range d.Questions {
179-
var domain string
180-
domain, tail = extractDomain(d.payload, tail)
181-
typ := binary.BigEndian.Uint16(tail[0:2])
182-
class := binary.BigEndian.Uint16(tail[2:4])
183-
tail = tail[4:]
184-
// TODO: add type and class description https://en.wikipedia.org/wiki/List_of_DNS_record_types
185-
sb.WriteString(fmt.Sprintf(" %s: type %d class %d\n", domain, typ, class))
299+
rec, tail = d.parseQuery(tail)
300+
sb.WriteString(rec)
186301
}
187302
}
188303
if d.AnswerRRs > 0 {
189304
sb.WriteString("- Answers:\n")
190305
for range d.AnswerRRs {
191-
var domain string
192-
domain, tail = extractDomain(d.payload, tail)
193-
typ := binary.BigEndian.Uint16(tail[0:2])
194-
class := binary.BigEndian.Uint16(tail[2:4])
195-
ttl := binary.BigEndian.Uint32(tail[4:8])
196-
rdl := int(binary.BigEndian.Uint16(tail[8:10]))
197-
//rdata := d.payload[offset : offset+rdl]
198-
tail = tail[10+rdl:]
199-
sb.WriteString(fmt.Sprintf(" %s: type %d class %d ttl %08x rdl %04x\n", domain, typ, class, ttl, rdl))
306+
rec, tail = d.parseRR(tail)
307+
sb.WriteString(rec)
200308
}
201309
}
202310
if d.AuthorityRRs > 0 {
203311
sb.WriteString("- Authoritative nameservers:\n")
204312
for range d.AuthorityRRs {
205-
var domain string
206-
domain, tail = extractDomain(d.payload, tail)
207-
typ := binary.BigEndian.Uint16(tail[0:2])
208-
class := binary.BigEndian.Uint16(tail[2:4])
209-
ttl := binary.BigEndian.Uint32(tail[4:8])
210-
rdl := int(binary.BigEndian.Uint16(tail[8:10]))
211-
//rdata := d.payload[offset : offset+rdl]
212-
tail = tail[10+rdl:]
213-
sb.WriteString(fmt.Sprintf(" %s: type %d class %d ttl %d rdl %d\n", domain, typ, class, ttl, rdl))
313+
rec, tail = d.parseRR(tail)
314+
sb.WriteString(rec)
214315
}
215316
}
216317
if d.AdditionalRRs > 0 {
217318
sb.WriteString("- Additional records:\n")
218319
for range d.AdditionalRRs {
219320
if tail[0] != 0 {
220-
var domain string
221-
domain, tail = extractDomain(d.payload, tail)
222-
typ := binary.BigEndian.Uint16(tail[0:2])
223-
class := binary.BigEndian.Uint16(tail[2:4])
224-
ttl := binary.BigEndian.Uint32(tail[4:8])
225-
rdl := int(binary.BigEndian.Uint16(tail[8:10]))
226-
//rdata := d.payload[offset : offset+rdl]
227-
tail = tail[10+rdl:]
228-
sb.WriteString(fmt.Sprintf(" %s: type %d class %d ttl %d rdl %d\n", domain, typ, class, ttl, rdl))
321+
rec, tail = d.parseRR(tail)
322+
sb.WriteString(rec)
229323
} else {
230-
tail = tail[1:]
231-
typ := binary.BigEndian.Uint16(tail[0:2])
232-
ups := binary.BigEndian.Uint16(tail[2:4])
233-
t1 := tail[4]
234-
zres := binary.BigEndian.Uint16(tail[5:7])
235-
rdl := int(binary.BigEndian.Uint16(tail[7:9]))
236-
tail = tail[9+rdl:]
237-
sb.WriteString(fmt.Sprintf(" Root: type %d UDP payload size %d t1 %d zres %d rdl %d\n", typ, ups, t1, zres, rdl))
324+
rec, tail = d.parseRoot(tail)
325+
sb.WriteString(rec)
238326
}
239-
240327
}
241328
}
242329
return sb.String()

0 commit comments

Comments
 (0)