Skip to content

Commit 2de1437

Browse files
author
shadowy-pycoder
committed
Added parsing of DNS message headers
1 parent 281453c commit 2de1437

File tree

2 files changed

+134
-4
lines changed

2 files changed

+134
-4
lines changed

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,6 @@ create:
1414
bench: create
1515
./mshark.test -test.bench=. -test.benchmem -test.run=^$$ -test.benchtime 1000x \
1616
-test.cpuprofile='cpu.prof' -test.memprofile='mem.prof'
17+
18+
clear:
19+
rm -v *.txt *.pcap*

layers/dns.go

Lines changed: 131 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,144 @@
11
package layers
22

3-
// https://en.wikipedia.org/wiki/Domain_Name_System
4-
// port 53
5-
type DNSMessage struct{}
3+
import (
4+
"encoding/binary"
5+
"fmt"
6+
)
7+
8+
const dnsHeaderSize = 12
9+
10+
type DNSMessage struct {
11+
TransactionID uint16 // Used for matching response to queries.
12+
Flags uint16 // Flags specify the requested operation and a response code.
13+
Questions uint16 // Count of entries in the queries section.
14+
AnswerRRs uint16 // Count of entries in the answers section.
15+
AuthorityRRs uint16 // Count of entries in the authority section.
16+
AdditionalRRs uint16 // Count of entries in the additional section.
17+
payload []byte
18+
}
619

720
func (d *DNSMessage) String() string {
8-
return ""
21+
return fmt.Sprintf(`DNS Message:
22+
- Transaction ID: %#04x
23+
- Flags: %#04x
24+
%s
25+
- Questions: %d
26+
- Answer RRs: %d
27+
- Authority RRs: %d
28+
- Additional RRs: %d
29+
- Payload: %d bytes
30+
`,
31+
d.TransactionID,
32+
d.Flags,
33+
d.flags(),
34+
d.Questions,
35+
d.AnswerRRs,
36+
d.AuthorityRRs,
37+
d.AdditionalRRs,
38+
len(d.payload),
39+
)
940
}
1041

42+
// Parse parses the given byte data into a DNSMessage struct.
1143
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))
46+
}
47+
d.TransactionID = binary.BigEndian.Uint16(data[0:2])
48+
d.Flags = binary.BigEndian.Uint16(data[2:4])
49+
d.Questions = binary.BigEndian.Uint16(data[4:6])
50+
d.AnswerRRs = binary.BigEndian.Uint16(data[6:8])
51+
d.AuthorityRRs = binary.BigEndian.Uint16(data[8:10])
52+
d.AdditionalRRs = binary.BigEndian.Uint16(data[10:dnsHeaderSize])
53+
d.payload = data[dnsHeaderSize:]
1254
return nil
1355
}
1456

1557
func (d *DNSMessage) NextLayer() (string, []byte) {
1658
return "", nil
1759
}
60+
61+
func (d *DNSMessage) flags() string {
62+
// https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
63+
var flags string
64+
opcode := (d.Flags >> 11) & 15
65+
var opcodes string
66+
switch opcode {
67+
case 0:
68+
opcodes = "Standard query"
69+
case 1:
70+
opcodes = "Inverse query"
71+
case 2:
72+
opcodes = "Server status request"
73+
case 4:
74+
opcodes = "Notify"
75+
case 5:
76+
opcodes = "Update"
77+
case 6:
78+
opcodes = "Stateful operation"
79+
default:
80+
opcodes = "Unknown"
81+
}
82+
qr := (d.Flags >> 15) & 1
83+
var qrs string
84+
switch qr {
85+
case 0:
86+
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+
flags = fmt.Sprintf(` - Response: Message is a %s (%d)
92+
- Opcode: %s (%d)
93+
- Truncated: %d
94+
- Recursion desired: %d
95+
- Reserved: %d
96+
- Non-authenticated data: %d`, qrs, qr, opcodes, opcode, tc, rd, z, na)
97+
case 1:
98+
qrs = "reply"
99+
a := (d.Flags >> 10) & 1
100+
tc := (d.Flags >> 9) & 1
101+
rd := (d.Flags >> 8) & 1
102+
ra := (d.Flags >> 7) & 1
103+
z := (d.Flags >> 6) & 1
104+
aa := (d.Flags >> 5) & 1
105+
na := (d.Flags >> 4) & 1
106+
rcode := d.Flags & 15
107+
var rcodes string
108+
switch rcode {
109+
case 0:
110+
rcodes = "No error"
111+
case 1:
112+
rcodes = "Format error"
113+
case 2:
114+
rcodes = "Server failed to complete the DNS request"
115+
case 3:
116+
rcodes = "Domain name does not exist"
117+
case 4:
118+
rcodes = "Function not implemented"
119+
case 5:
120+
rcodes = "The server refused to answer for the query"
121+
case 6:
122+
rcodes = "Name that should not exist, does exist"
123+
case 7:
124+
rcodes = "RRset that should not exist, does exist"
125+
case 8:
126+
rcodes = "Server not authoritative for the zone"
127+
case 9:
128+
rcodes = "Name not in zone"
129+
default:
130+
rcodes = "Unknown"
131+
}
132+
flags = fmt.Sprintf(` - Response: Message is a %s (%d)
133+
- Opcode: %s (%d)
134+
- Authoritative: %d
135+
- Truncated: %d
136+
- Recursion desired: %d
137+
- Recursion available: %d
138+
- Reserved: %d
139+
- Answer authenticated: %d
140+
- Non-authenticated data: %d
141+
- Reply code: %s (%d)`, qrs, qr, opcodes, opcode, a, tc, rd, ra, z, aa, na, rcodes, rcode)
142+
}
143+
return flags
144+
}

0 commit comments

Comments
 (0)