packagehoneypotimport("context""fmt""honeypot/internal/database""honeypot/internal/types""log""log/slog""strings""time")// Honeypot is the interface that all honeypot implementations must satisfy.typeHoneypotinterface{// Name returns the name of the honeypot (e.g., "ssh", "http").Name()types.HoneypotType// Label returns the label of the honeypot used in the UI (e.g., "SSH", "HTTP").Label()string// Start starts the honeypot server. It should run until the context is cancelled.Start(ctxcontext.Context,logger*slog.Logger)error// GetScores returns the scored ip addresses for the honeypot.GetScores(db*database.Database,intervalstring)ScoreMap// Ports returns the ports the honeypot is listening on.Ports()[]uint16}typeScorestruct{Scoreuint`json:"score"`Tags[]types.Tag`json:"tags"`}typeScoreMapmap[string]ScoretypeScoreCachestruct{ScoresScoreMapLastUpdatedtime.Time}funcMergeScores(maps...ScoreMap)ScoreMap{result:=ScoreMap{}for_,m:=rangemaps{forip,score:=rangem{existing,ok:=result[ip]if!ok{// first time we see this IPresult[ip]=scorecontinue}// add scoreexisting.Score+=score.Score// merge tags (deduplicated)existing.Tags=MergeTags(existing.Tags,score.Tags)result[ip]=existing}}returnresult}funcMergeTags(a,b[]types.Tag)[]types.Tag{seen:=make(map[types.Tag]struct{},len(a)+len(b))out:=make([]types.Tag,0,len(a)+len(b))for_,t:=rangea{if_,ok:=seen[t];!ok{seen[t]=struct{}{}out=append(out,t)}}for_,t:=rangeb{if_,ok:=seen[t];!ok{seen[t]=struct{}{}out=append(out,t)}}returnout}funcGetAuthAttemptScores(db*database.Database,intervalstring)ScoreMap{rows,err:=db.DB.Query(fmt.Sprintf(` SELECT remote_addr, COUNT(*) AS score
FROM honeypot_events
WHERE event = ?
AND time >= now() - INTERVAL %s
GROUP BY remote_addr ORDER BY score DESC;
`,interval),types.EventAuthAttempt)iferr!=nil{log.Println("error querying auth attempt scores:",err)returnScoreMap{}}deferrows.Close()scores:=ScoreMap{}forrows.Next(){varipstringvarscoreuinterr:=rows.Scan(&ip,&score)iferr!=nil{log.Println("error getting auth attempt scores:",err)returnScoreMap{}}scores[ip]=Score{Score:score*100,Tags:[]types.Tag{types.TagAuthAttempt}}}returnscores}funcUpdateBlocklist(db*database.Database,scoresScoreMap){blockCounts,err:=db.GetBlockCounts()iferr!=nil{log.Println("error getting block counts:",err)return}blockedAddresses,err:=db.GetBlockedAddresses()iferr!=nil{log.Println("error getting blocked addresses:",err)return}blockedMap:=make(map[string]bool)for_,entry:=rangeblockedAddresses{blockedMap[entry.Address]=true}foraddress,score:=rangescores{ifblockedMap[address]{continue}blockCount,ok:=blockCounts[address]if!ok{blockCount=1}reason:=""for_,tag:=rangescore.Tags{reason+=string(tag)+","}reason=strings.TrimSuffix(reason,",")db.InsertBlocklist(address,reason,time.Duration(blockCount)*time.Hour)}}