@@ -3,9 +3,11 @@ package layers
33import (
44 "encoding/binary"
55 "fmt"
6+ "strings"
7+ "unsafe"
68)
79
8- const dnsHeaderSize = 12
10+ const headerSizeDNS = 12
911
1012type DNSMessage struct {
1113 TransactionID uint16 // Used for matching response to queries.
@@ -27,6 +29,7 @@ func (d *DNSMessage) String() string {
2729- Authority RRs: %d
2830- Additional RRs: %d
2931- Payload: %d bytes
32+ %s
3033` ,
3134 d .TransactionID ,
3235 d .Flags ,
@@ -36,21 +39,22 @@ func (d *DNSMessage) String() string {
3639 d .AuthorityRRs ,
3740 d .AdditionalRRs ,
3841 len (d .payload ),
42+ d .queries (),
3943 )
4044}
4145
4246// Parse parses the given byte data into a DNSMessage struct.
4347func (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 ))
4650 }
4751 d .TransactionID = binary .BigEndian .Uint16 (data [0 :2 ])
4852 d .Flags = binary .BigEndian .Uint16 (data [2 :4 ])
4953 d .Questions = binary .BigEndian .Uint16 (data [4 :6 ])
5054 d .AnswerRRs = binary .BigEndian .Uint16 (data [6 :8 ])
5155 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 :]
5458 return nil
5559}
5660
@@ -79,15 +83,15 @@ func (d *DNSMessage) flags() string {
7983 default :
8084 opcodes = "Unknown"
8185 }
86+ tc := (d .Flags >> 9 ) & 1
87+ rd := (d .Flags >> 8 ) & 1
88+ z := (d .Flags >> 6 ) & 1
89+ na := (d .Flags >> 4 ) & 1
8290 qr := (d .Flags >> 15 ) & 1
8391 var qrs string
8492 switch qr {
8593 case 0 :
8694 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
9195 flags = fmt .Sprintf (` - Response: Message is a %s (%d)
9296 - Opcode: %s (%d)
9397 - Truncated: %d
@@ -97,12 +101,8 @@ func (d *DNSMessage) flags() string {
97101 case 1 :
98102 qrs = "reply"
99103 a := (d .Flags >> 10 ) & 1
100- tc := (d .Flags >> 9 ) & 1
101- rd := (d .Flags >> 8 ) & 1
102104 ra := (d .Flags >> 7 ) & 1
103- z := (d .Flags >> 6 ) & 1
104105 aa := (d .Flags >> 5 ) & 1
105- na := (d .Flags >> 4 ) & 1
106106 rcode := d .Flags & 15
107107 var rcodes string
108108 switch rcode {
@@ -142,3 +142,72 @@ func (d *DNSMessage) flags() string {
142142 }
143143 return flags
144144}
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