Cybersecurity-Projects/PROJECTS/advanced/honeypot-network/internal/session/tracker.go

168 lines
2.9 KiB
Go

/*
©AngelaMos | 2026
tracker.go
Thread-safe active session tracker
Manages the lifecycle of honeypot sessions from connect to
disconnect. Each connection gets a unique session ID (UUID v7)
and is tracked in an in-memory map. Session metadata accumulates
as the attacker interacts: command counts, login status, MITRE
technique tags, and threat scores.
*/
package session
import (
"sync"
"time"
"github.com/google/uuid"
"github.com/CarterPerez-dev/hive/pkg/types"
)
type Tracker struct {
mu sync.RWMutex
sessions map[string]*types.Session
onStart func(*types.Session)
onEnd func(*types.Session)
}
func NewTracker() *Tracker {
return &Tracker{
sessions: make(map[string]*types.Session),
}
}
func (t *Tracker) SetOnStart(fn func(*types.Session)) {
t.mu.Lock()
defer t.mu.Unlock()
t.onStart = fn
}
func (t *Tracker) Start(
sensorID string,
serviceType types.ServiceType,
sourceIP string,
sourcePort int,
destPort int,
) *types.Session {
sess := &types.Session{
ID: uuid.Must(uuid.NewV7()).String(),
SensorID: sensorID,
StartedAt: time.Now().UTC(),
ServiceType: serviceType,
SourceIP: sourceIP,
SourcePort: sourcePort,
DestPort: destPort,
}
t.mu.Lock()
t.sessions[sess.ID] = sess
onStart := t.onStart
t.mu.Unlock()
if onStart != nil {
onStart(sess)
}
return sess
}
func (t *Tracker) SetOnEnd(fn func(*types.Session)) {
t.mu.Lock()
defer t.mu.Unlock()
t.onEnd = fn
}
func (t *Tracker) End(sessionID string) *types.Session {
t.mu.Lock()
sess, exists := t.sessions[sessionID]
if !exists {
t.mu.Unlock()
return nil
}
now := time.Now().UTC()
sess.EndedAt = &now
delete(t.sessions, sessionID)
onEnd := t.onEnd
t.mu.Unlock()
if onEnd != nil {
onEnd(sess)
}
return sess
}
func (t *Tracker) Get(sessionID string) *types.Session {
t.mu.RLock()
defer t.mu.RUnlock()
return t.sessions[sessionID]
}
func (t *Tracker) Active() []*types.Session {
t.mu.RLock()
defer t.mu.RUnlock()
result := make([]*types.Session, 0, len(t.sessions))
for _, sess := range t.sessions {
result = append(result, sess)
}
return result
}
func (t *Tracker) IncrCommandCount(sessionID string) {
t.mu.Lock()
defer t.mu.Unlock()
if sess, exists := t.sessions[sessionID]; exists {
sess.CommandCount++
}
}
func (t *Tracker) SetLogin(
sessionID string,
success bool,
username string,
clientVersion string,
) {
t.mu.Lock()
defer t.mu.Unlock()
if sess, exists := t.sessions[sessionID]; exists {
sess.LoginSuccess = success
sess.Username = username
sess.ClientVersion = clientVersion
}
}
func (t *Tracker) AddTechnique(
sessionID, techniqueID string,
) {
t.mu.Lock()
defer t.mu.Unlock()
sess, exists := t.sessions[sessionID]
if !exists {
return
}
for _, t := range sess.MITRETechniques {
if t == techniqueID {
return
}
}
sess.MITRETechniques = append(
sess.MITRETechniques, techniqueID,
)
}
func (t *Tracker) Count() int {
t.mu.RLock()
defer t.mu.RUnlock()
return len(t.sessions)
}