summaryrefslogtreecommitdiff
path: root/analytics/analyzer.go
diff options
context:
space:
mode:
Diffstat (limited to 'analytics/analyzer.go')
-rw-r--r--analytics/analyzer.go71
1 files changed, 71 insertions, 0 deletions
diff --git a/analytics/analyzer.go b/analytics/analyzer.go
new file mode 100644
index 0000000..ac8ff03
--- /dev/null
+++ b/analytics/analyzer.go
@@ -0,0 +1,71 @@
+package analytics
+
+import (
+ "cmp"
+ "slices"
+ "strings"
+
+ "github.com/x-way/crawlerdetect"
+ "src.eltr.ac/eltrac/audidi/data"
+)
+
+type AnalyticsResult struct {
+ Client string
+ // 0 = Human
+ // 1 = Human operating non-browser tools
+ // 2 = Automated crawler
+ // 3 = Malicious crawler
+ BotIndex float32
+}
+
+func Analyze(log data.LogEntry) *AnalyticsResult {
+ uaResult := analyzeUA(log.UserAgent)
+ ja4Client, ja4Result := analyzeJA4(log.JA4)
+ matchScore := analyzeClientMatch(log.UserAgent, ja4Client)
+ ASNScore := analyzeASN(log.ASN)
+
+ return &AnalyticsResult{
+ Client: cmp.Or(ja4Client, log.UserAgent),
+ BotIndex: (uaResult + ja4Result + matchScore + ASNScore) / 4,
+ }
+}
+
+func analyzeUA(ua string) float32 {
+ if crawlerdetect.IsCrawler(ua) {
+ return 2
+ } else {
+ return 0
+ }
+}
+
+func analyzeJA4(ja4 string) (client string, botIndex float32) {
+ client, clientType := LookupClientByJA4(ja4)
+
+ return client, float32(clientType)
+}
+
+func analyzeClientMatch(ua string, ja4client string) float32 {
+ uaClient := strings.ToLower(ua)
+ ja4Client := strings.ToLower(ja4client)
+
+ if strings.Contains(uaClient, ja4Client) {
+ return 0
+ } else {
+ return 3
+ }
+}
+
+func analyzeASN(asn int) float32 {
+ DataCenterASNs := []int{
+ 16509, 14618, 8987, 38895, 8075, 8068, 12076, 15169, 396982, 19527, 31898, 36351,
+ 37963, 45102, 24429, 132203, 45090, 55990, 136907, 38365,
+ 13335, 20940, 16625, 21342, 63949, 54113, 60068, 212238, 15133, 19551,
+ 14061, 20473, 16276, 24940, 51167, 12876, 60781, 28753, 9009,
+ 53667, 49505, 9123, 197540, 8560, 6724, 210644, 55293,
+ 26496, 46606, 32244, 26347, 33070, 19994, 22612, 19871, 2635,
+ }
+ if slices.Contains(DataCenterASNs, asn) {
+ return 2
+ }
+ return 0
+}