Optimized background tracker

This commit is contained in:
Sam
2026-01-29 00:12:27 -06:00
parent b5ee7e9e47
commit b03aae3461

View File

@@ -1517,62 +1517,104 @@ AWK_BIN=$(command -v gawk 2>/dev/null || command -v awk 2>/dev/null || echo "awk
LOCAL_IP=$(ip route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="src") print $(i+1)}') LOCAL_IP=$(ip route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="src") print $(i+1)}')
[ -z "$LOCAL_IP" ] && LOCAL_IP=$(hostname -I 2>/dev/null | awk '{print $1}') [ -z "$LOCAL_IP" ] && LOCAL_IP=$(hostname -I 2>/dev/null | awk '{print $1}')
# Main capture loop: tcpdump -> awk -> process # Batch process: resolve GeoIP + merge into cumulative files in bulk
while true; do process_batch() {
# Process tcpdump output in awk, sync every 15 seconds local batch="$1"
while IFS= read -r line; do local resolved="$PERSIST_DIR/resolved_batch"
if [ "$line" = "SYNC_MARKER" ]; then local geo_map="$PERSIST_DIR/geo_map"
continue
# Step 1: Extract unique IPs and bulk-resolve GeoIP
# Read cache once, resolve uncached, produce ip|country mapping
$AWK_BIN -F'|' '{print $2}' "$batch" | sort -u > "$PERSIST_DIR/batch_ips"
# Build geo mapping: read cache + resolve missing
> "$geo_map"
while IFS= read -r ip; do
[ -z "$ip" ] && continue
country=""
if [ -f "$GEOIP_CACHE" ]; then
country=$(grep "^${ip}|" "$GEOIP_CACHE" 2>/dev/null | head -1 | cut -d'|' -f2)
fi fi
# Parse: direction|IP|bytes if [ -z "$country" ]; then
local_dir=$(echo "$line" | cut -d'|' -f1) country=$(geo_lookup "$ip")
local_ip_addr=$(echo "$line" | cut -d'|' -f2) fi
local_bytes=$(echo "$line" | cut -d'|' -f3) # Normalize
[ -z "$local_ip_addr" ] && continue
# Resolve country
country=$(geo_lookup "$local_ip_addr")
# Normalize country names
case "$country" in case "$country" in
*"Iran, Islamic Republic of"*) country="Iran - #FreeIran" ;; *"Iran, Islamic Republic of"*) country="Iran - #FreeIran" ;;
*"Moldova, Republic of"*) country="Moldova" ;; *"Moldova, Republic of"*) country="Moldova" ;;
esac esac
echo "${ip}|${country}" >> "$geo_map"
done < "$PERSIST_DIR/batch_ips"
# Update cumulative data # Step 2: Single awk pass — merge batch into cumulative_data + write snapshot
if [ -f "$STATS_FILE" ]; then $AWK_BIN -F'|' -v snap="$SNAPSHOT_FILE" '
existing=$(grep "^${country}|" "$STATS_FILE" 2>/dev/null | head -1) FILENAME == ARGV[1] { geo[$1] = $2; next }
if [ -n "$existing" ]; then FILENAME == ARGV[2] { existing[$1] = $2 "|" $3; next }
old_from=$(echo "$existing" | cut -d'|' -f2) FILENAME == ARGV[3] {
old_to=$(echo "$existing" | cut -d'|' -f3) dir = $1; ip = $2; bytes = $3 + 0
if [ "$local_dir" = "FROM" ]; then c = geo[ip]
new_from=$((old_from + local_bytes)) if (c == "") c = "Unknown"
new_to=$old_to if (dir == "FROM") from_bytes[c] += bytes
else else to_bytes[c] += bytes
new_from=$old_from # Also collect snapshot lines
new_to=$((old_to + local_bytes)) print dir "|" c "|" bytes "|" ip > snap
fi next
# Update in place using temp file }
grep -v "^${country}|" "$STATS_FILE" > "$STATS_FILE.tmp" 2>/dev/null || true END {
echo "${country}|${new_from}|${new_to}" >> "$STATS_FILE.tmp" # Merge existing + new
mv "$STATS_FILE.tmp" "$STATS_FILE" for (c in existing) {
else split(existing[c], v, "|")
if [ "$local_dir" = "FROM" ]; then f = v[1] + 0; t = v[2] + 0
echo "${country}|${local_bytes}|0" >> "$STATS_FILE" f += from_bytes[c] + 0
else t += to_bytes[c] + 0
echo "${country}|0|${local_bytes}" >> "$STATS_FILE" print c "|" f "|" t
fi delete from_bytes[c]
fi delete to_bytes[c]
fi }
# New countries not in existing
for (c in from_bytes) {
f = from_bytes[c] + 0
t = to_bytes[c] + 0
print c "|" f "|" t
delete to_bytes[c]
}
for (c in to_bytes) {
print c "|0|" to_bytes[c] + 0
}
}
' "$geo_map" "$STATS_FILE" "$batch" > "$STATS_FILE.tmp" && mv "$STATS_FILE.tmp" "$STATS_FILE"
# Update cumulative IPs # Step 3: Single awk pass — merge batch IPs into cumulative_ips
if ! grep -q "^${country}|${local_ip_addr}$" "$IPS_FILE" 2>/dev/null; then $AWK_BIN -F'|' '
echo "${country}|${local_ip_addr}" >> "$IPS_FILE" FILENAME == ARGV[1] { geo[$1] = $2; next }
FILENAME == ARGV[2] { seen[$0] = 1; print; next }
FILENAME == ARGV[3] {
ip = $2; c = geo[ip]
if (c == "") c = "Unknown"
key = c "|" ip
if (!(key in seen)) { seen[key] = 1; print key }
}
' "$geo_map" "$IPS_FILE" "$batch" > "$IPS_FILE.tmp" && mv "$IPS_FILE.tmp" "$IPS_FILE"
rm -f "$PERSIST_DIR/batch_ips" "$geo_map" "$resolved"
}
# Main capture loop: tcpdump -> awk -> batch process
while true; do
BATCH_FILE="$PERSIST_DIR/batch_tmp"
> "$BATCH_FILE"
while IFS= read -r line; do
if [ "$line" = "SYNC_MARKER" ]; then
# Process entire batch at once
if [ -s "$BATCH_FILE" ]; then
> "$SNAPSHOT_FILE"
process_batch "$BATCH_FILE"
fi fi
> "$BATCH_FILE"
# Write snapshot for speed calculation continue
echo "${local_dir}|${country}|${local_bytes}|${local_ip_addr}" >> "$SNAPSHOT_FILE" fi
echo "$line" >> "$BATCH_FILE"
done < <($TCPDUMP_BIN -tt -l -ni any -n -q "(tcp or udp) and not port 22" 2>/dev/null | $AWK_BIN -v local_ip="$LOCAL_IP" ' done < <($TCPDUMP_BIN -tt -l -ni any -n -q "(tcp or udp) and not port 22" 2>/dev/null | $AWK_BIN -v local_ip="$LOCAL_IP" '
BEGIN { last_sync = 0 } BEGIN { last_sync = 0 }
{ {