-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpihole-status-report.bash
More file actions
215 lines (187 loc) · 7.81 KB
/
pihole-status-report.bash
File metadata and controls
215 lines (187 loc) · 7.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#!/bin/bash
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
LIGHTBLUE='\033[1;36m'
CYAN='\033[0;36m'
BOLD='\033[1m'
ITALIC='\033[3m'
NC='\033[0m'
REFRESH=10
API="http://localhost/api"
API_KEY_FILE="/etc/pihole/cli_pw"
W=56 # total inner width of the box
# ─────────────────────────────────────────────
# AUTH
# ─────────────────────────────────────────────
get_sid() {
[[ ! -f "$API_KEY_FILE" ]] && return
local pw sid
pw=$(cat "$API_KEY_FILE")
sid=$(curl -s -X POST "$API/auth" \
-H "Content-Type: application/json" \
-d "{\"password\":\"$pw\"}" \
| grep -o '"sid":"[^"]*"' | cut -d'"' -f4)
echo "$sid"
}
# ─────────────────────────────────────────────
# API
# ─────────────────────────────────────────────
api_get() {
local endpoint="$1" sid="$2"
if [[ -n "$sid" ]]; then
curl -s -H "X-FTL-SID: $sid" "$API/$endpoint"
else
curl -s "$API/$endpoint"
fi
}
# ─────────────────────────────────────────────
# HELPERS
# ─────────────────────────────────────────────
json_val() { echo "$1" | grep -o "\"$2\":[^,}]*" | head -1 | sed 's/.*://;s/[" }]//g'; }
service_status() {
if systemctl is-active --quiet "$1" 2>/dev/null; then
printf "${GREEN}${BOLD}active${NC}"
else
printf "${RED}${BOLD}inactive${NC}"
fi
}
# Draw a simple ASCII bar [====----] width=24
bar() {
local val=$1 max=$2 width=24
[[ $max -eq 0 ]] && max=1
local filled=$(( val * width / max ))
[[ $filled -gt $width ]] && filled=$width
local empty=$(( width - filled ))
local b="["
for ((i=0; i<filled; i++)); do b+="="; done
for ((i=0; i<empty; i++)); do b+="-"; done
b+="]"
printf "${LIGHTBLUE}%s${NC}" "$b"
}
# Section header
section() {
printf "\n${CYAN}${BOLD} %-${W}s${NC}\n" "$1"
printf "${CYAN} "
printf '%0.s-' $(seq 1 $W)
printf "${NC}\n"
}
# ─────────────────────────────────────────────
# DRAW
# ─────────────────────────────────────────────
draw() {
local sid="$1"
# ── Fetch ──
local summary top_domains top_clients versions
summary=$(api_get "stats/summary" "$sid")
top_domains=$(api_get "stats/top_domains?blocked=true&count=5" "$sid")
top_clients=$(api_get "stats/top_clients?count=5" "$sid")
versions=$(api_get "info/version" "$sid")
# ── Parse summary ──
local queries blocked percent gravity
queries=$(json_val "$summary" "queries")
blocked=$(json_val "$summary" "blocked")
gravity=$(json_val "$summary" "gravity_size")
queries=${queries:-0}
blocked=${blocked:-0}
if [[ "$queries" -gt 0 ]]; then
percent=$(awk "BEGIN {printf \"%.1f\", $blocked/$queries*100}")
else
percent="0.0"
fi
# ── Parse versions (nested: version.core.local.version) ──
local ph_ver ftl_ver
ph_ver=$(echo "$versions" | grep -o '"core":{.*' | grep -o '"version":"[^"]*"' | head -1 | cut -d'"' -f4)
ftl_ver=$(echo "$versions" | grep -o '"ftl":{.*' | grep -o '"version":"[^"]*"' | head -1 | cut -d'"' -f4)
ph_ver=${ph_ver:-n/a}
ftl_ver=${ftl_ver:-n/a}
# ── System info ──
local sys_uptime ram_used ram_total ram_pct disk_used disk_total disk_pct
sys_uptime=$(uptime -p 2>/dev/null | sed 's/up //')
ram_used=$(free -m | awk '/^Mem:/{print $3}')
ram_total=$(free -m | awk '/^Mem:/{print $2}')
ram_pct=$(awk "BEGIN {printf \"%d\", ${ram_used:-0}/${ram_total:-1}*100}")
disk_used=$(df -BG / | awk 'NR==2{gsub("G","",$3); print $3}')
disk_total=$(df -BG / | awk 'NR==2{gsub("G","",$2); print $2}')
disk_pct=$(df / | awk 'NR==2{gsub("%","",$5); print $5}')
# ── Render ──
tput cup 0 0
# Header box (pure ASCII, fixed width = W+2)
local sep
sep=$(printf '%0.s-' $(seq 1 $((W+2))))
local title="Pi-hole Status Report - Live Dashboard"
local sub
sub="$(date '+%a %d %b %Y %H:%M:%S') [refresh: ${REFRESH}s]"
printf "${YELLOW}${BOLD}+%s+${NC}\n" "$sep"
printf "${YELLOW}${BOLD}|${NC} ${BOLD}%-${W}s${NC} ${YELLOW}${BOLD}|${NC}\n" "$title"
printf "${YELLOW}${BOLD}|${NC} ${CYAN}%-${W}s${NC} ${YELLOW}${BOLD}|${NC}\n" "$sub"
printf "${YELLOW}${BOLD}+%s+${NC}\n" "$sep"
# VERSIONS
section "VERSIONS"
printf " ${LIGHTBLUE}${BOLD}%-22s${NC} %s\n" "Pi-hole:" "$ph_ver"
printf " ${LIGHTBLUE}${BOLD}%-22s${NC} %s\n" "FTL:" "$ftl_ver"
printf " ${LIGHTBLUE}${BOLD}%-22s${NC} %s\n" "System uptime:" "$sys_uptime"
# SERVICES
section "SERVICES"
printf " ${LIGHTBLUE}${BOLD}%-22s${NC} [%b]\n" "pihole-FTL:" "$(service_status pihole-FTL)"
printf " ${LIGHTBLUE}${BOLD}%-22s${NC} [%b]\n" "cron:" "$(service_status cron)"
# QUERIES TODAY
section "QUERIES TODAY"
printf " ${LIGHTBLUE}${BOLD}%-22s${NC} %s\n" "Total queries:" "$queries"
printf " ${LIGHTBLUE}${BOLD}%-22s${NC} %s (%s%%)\n" "Blocked:" "$blocked" "$percent"
printf " ${LIGHTBLUE}${BOLD}%-22s${NC} " "Block rate:"
bar "$blocked" "$queries"; echo
printf " ${LIGHTBLUE}${BOLD}%-22s${NC} %s\n" "Gravity domains:" "${gravity:-n/a}"
# SYSTEM RESOURCES
section "SYSTEM RESOURCES"
printf " ${LIGHTBLUE}${BOLD}%-22s${NC} %4s MB / %4s MB (%3s%%) " "RAM:" "$ram_used" "$ram_total" "$ram_pct"
bar "$ram_pct" 100; echo
printf " ${LIGHTBLUE}${BOLD}%-22s${NC} %4s GB / %4s GB (%3s%%) " "Disk (/):" "$disk_used" "$disk_total" "$disk_pct"
bar "$disk_pct" 100; echo
# TOP 5 BLOCKED DOMAINS
section "TOP 5 BLOCKED DOMAINS"
local domains_found=0
while IFS= read -r line; do
local domain count
domain=$(echo "$line" | grep -o '"domain":"[^"]*"' | cut -d'"' -f4)
count=$(echo "$line" | grep -o '"count":[0-9]*' | cut -d':' -f2)
[[ -z "$domain" ]] && continue
printf " ${RED}>${NC} %-40s %s hits\n" "$domain" "$count"
((domains_found++))
done < <(echo "$top_domains" | grep -o '{[^}]*"domain":"[^"]*"[^}]*}')
[[ $domains_found -eq 0 ]] && printf " ${YELLOW}No data available${NC}\n"
# TOP 5 CLIENTS
section "TOP 5 CLIENTS"
local clients_found=0
while IFS= read -r line; do
local ip name count label
ip=$(echo "$line" | grep -o '"ip":"[^"]*"' | cut -d'"' -f4)
name=$(echo "$line" | grep -o '"name":"[^"]*"' | cut -d'"' -f4)
count=$(echo "$line" | grep -o '"count":[0-9]*' | cut -d':' -f2)
[[ -z "$ip" ]] && continue
label="${name:-$ip}"
printf " ${LIGHTBLUE}>${NC} %-40s %s queries\n" "$label" "$count"
((clients_found++))
done < <(echo "$top_clients" | grep -o '{[^}]*"ip":"[^"]*"[^}]*}')
[[ $clients_found -eq 0 ]] && printf " ${YELLOW}No data available${NC}\n"
printf "\n${CYAN} "
printf '%0.s-' $(seq 1 $W)
printf "${NC}\n"
printf " ${ITALIC}Press Ctrl+C to exit${NC}\n"
}
# ─────────────────────────────────────────────
# MAIN
# ─────────────────────────────────────────────
if [[ ! "${EUID}" -eq 0 ]]; then
echo && echo -e "${RED}${BOLD}✗ Error:${NC} ${RED}This script requires elevated privileges to run.${NC}"
echo -e "${YELLOW}${BOLD}➜ Solution:${NC} ${YELLOW}Please restart as root user or with sudo command.${NC}" && echo
sleep 1 && exit 1
fi
SID=$(get_sid)
tput clear
tput civis
trap 'tput cnorm; tput clear; echo -e "${YELLOW}Goodbye!${NC}"; echo; exit 0' INT TERM
while true; do
draw "$SID"
sleep "$REFRESH"
done