package rdp
import (
"fmt"
"log/slog"
"net"
"os"
"testing"
"time"
"honeypot/internal/logger"
"honeypot/internal/types"
)
type mockSink struct {
events []types.LogEvent
}
func (s *mockSink) EmitEvent(e types.LogEvent) {
s.events = append(s.events, e)
}
func TestRDPLogging(t *testing.T) {
sink := &mockSink{}
logger.RegisterEventSink(sink)
l := slog.New(slog.NewJSONHandler(os.Stdout, nil))
hp := New(Config{
ListenAddr: "127.0.0.1",
Ports: []uint16{0},
})
hp.(*rdpHoneypot).logger = l
t.Run("RandomData", func(t *testing.T) {
sink.events = nil
c1, c2 := net.Pipe()
go hp.(*rdpHoneypot).handleConn(c1)
c2.SetDeadline(time.Now().Add(time.Second))
fmt.Fprintf(c2, "hello world")
c2.Close()
time.Sleep(100 * time.Millisecond)
found := false
for _, e := range sink.events {
if e.Event == types.EventTCPPacket && e.Fields["message"] == "non-rdp protocol detected" {
found = true
break
}
}
if !found {
t.Errorf("expected non-rdp protocol detected")
}
})
t.Run("TLSHandshake", func(t *testing.T) {
sink.events = nil
c1, c2 := net.Pipe()
go hp.(*rdpHoneypot).handleConn(c1)
c2.Write([]byte{0x16, 0x03, 0x01, 0x00, 0x05, 0x01, 0x00, 0x00, 0x01, 0x00})
c2.Close()
time.Sleep(100 * time.Millisecond)
found := false
for _, e := range sink.events {
if e.Event == types.EventTLSHandshake {
found = true
break
}
}
if !found {
t.Errorf("expected TLS handshake")
}
})
t.Run("DeferredConnectionOnly", func(t *testing.T) {
sink.events = nil
c1, _ := net.Pipe()
// Closing c1 will make sure handleConn returns WITHOUT logging an event if we don't send anything
go func() {
time.Sleep(50 * time.Millisecond)
c1.Close()
}()
hp.(*rdpHoneypot).handleConn(c1)
time.Sleep(100 * time.Millisecond)
if len(sink.events) != 1 {
t.Errorf("expected 1 event, got %d: %v", len(sink.events), sink.events)
return
}
if sink.events[0].Fields["message"] != "connection closed without rdp events" {
t.Errorf("expected deferred connection log, got: %v", sink.events[0].Fields["message"])
}
})
}