Files
dpi/protocol/detect/dns/detect_test.go
2025-10-09 17:58:40 +02:00

116 lines
3.4 KiB
Go

package dns
import (
"testing"
"git.maze.io/go/dpi/protocol"
)
func TestDetectDNS(t *testing.T) {
// A valid DNS query for "www.google.com" (A record)
dnsQuery := []byte{
0x12, 0x34, // Transaction ID
0x01, 0x00, // Flags (Standard Query, Recursion Desired)
0x00, 0x01, // Questions: 1
0x00, 0x00, // Answer RRs: 0
0x00, 0x00, // Authority RRs: 0
0x00, 0x00, // Additional RRs: 0
0x03, 'w', 'w', 'w', // Question section:
0x06, 'g', 'o', 'o', 'g', 'l', 'e', //
0x03, 'c', 'o', 'm', //
0x00, // Null terminator for the name
0x00, 0x01, // Type: A (Host Address)
0x00, 0x01, // Class: IN (Internet)
}
// A valid DNS reply for the above query
dnsReply := []byte{
0x12, 0x34, // Transaction ID (matches query)
0x81, 0x80, // Flags (Response, Recursion Desired, Recursion Available)
0x00, 0x01, // Questions: 1
0x00, 0x01, // Answer RRs: 1
0x00, 0x00, // Authority RRs: 0
0x00, 0x00, // Additional RRs: 0
0x03, 'w', 'w', 'w', // Question section (same as query)
0x06, 'g', 'o', 'o', 'g', 'l', 'e', //
0x03, 'c', 'o', 'm', //
0x00, //
0x00, 0x01, //
0x00, 0x01, //
0xc0, 0x0c, // Answer section. Name: Pointer to the question name at offset 12 (0x0c)
0x00, 0x01, // Type: A
0x00, 0x01, // Class: IN
0x00, 0x00, 0x01, 0x2c, // Time to Live (TTL): 300 seconds
0x00, 0x04, // Data Length: 4 bytes
0x08, 0x08, 0x08, 0x08, // RDATA: IP Address 8.8.8.8
}
// This is just the first 12 bytes of a DNS query with a single question.
headerWithQuestionPromise := []byte{
0x12, 0x34, // Transaction ID
0x01, 0x00, // Flags (Standard Query)
0x00, 0x01, // Questions: 1 <-- This promises more data!
0x00, 0x00, // Answer RRs: 0
0x00, 0x00, // Authority RRs: 0
0x00, 0x00, // Additional RRs: 0
}
// This is a valid, self-contained "empty" DNS message.
headerWithNoPromise := []byte{
0x56, 0x78, // Transaction ID
0x01, 0x00, // Flags (Standard Query)
0x00, 0x00, // Questions: 0 <-- This promises NO more data.
0x00, 0x00, // Answer RRs: 0
0x00, 0x00, // Authority RRs: 0
0x00, 0x00, // Additional RRs: 0
}
t.Run("query", func(t *testing.T) {
p, c, err := protocol.Detect(protocol.Both, dnsQuery, 1234, 53)
if err != nil {
t.Fatalf("unexpected error: %v", err)
return
}
t.Logf("detected %s confidence %g%%", p.Name, c*100)
if p.Name != protocolName {
t.Errorf("expected %q protocol, got %q", protocolName, p.Name)
}
})
t.Run("answer", func(t *testing.T) {
p, c, err := protocol.Detect(protocol.Both, dnsReply, 53, 1234)
if err != nil {
t.Fatalf("unexpected error: %v", err)
return
}
t.Logf("detected %s confidence %g%%", p.Name, c*100)
if p.Name != protocolName {
t.Errorf("expected %q protocol, got %q", protocolName, p.Name)
}
})
t.Run("header with no promise", func(t *testing.T) {
p, c, err := protocol.Detect(protocol.Both, headerWithNoPromise, 1234, 53)
if err != nil {
t.Fatalf("unexpected error: %v", err)
return
}
t.Logf("detected %s confidence %g%%", p.Name, c*100)
if p.Name != protocolName {
t.Errorf("expected %q protocol, got %q", protocolName, p.Name)
}
})
t.Run("header with question promise", func(t *testing.T) {
p, c, err := protocol.Detect(protocol.Both, headerWithQuestionPromise, 1234, 53)
if err != nil {
t.Fatalf("unexpected error: %v", err)
return
}
t.Logf("detected %s confidence %g%%", p.Name, c*100)
if p.Name != protocolName {
t.Errorf("expected %q protocol, got %q", protocolName, p.Name)
}
})
}