最終更新 1 month ago

nuno revised this gist 1 month ago. Go to revision

1 file changed, 327 insertions

gistfile1.txt(file created)

@@ -0,0 +1,327 @@
1 + #!/usr/bin/env bash
2 +
3 + FW_EVENTS_LOG="$(ctx::fw_events_log)"
4 + WG_EVENTS_LOG="$(ctx::events_log)"
5 +
6 + function cmd::logs::on_load() {
7 + flag::register --name
8 + flag::register --type
9 + flag::register --since
10 + flag::register --limit
11 + flag::register --fw
12 + flag::register --wg
13 + flag::register --follow
14 + flag::register --all
15 + flag::register --before
16 + flag::register --force
17 + flag::register --days
18 + }
19 +
20 + function cmd::logs::help() {
21 + cat <<EOF
22 + Usage: wgctl logs [subcommand] [options]
23 +
24 + Show or manage WireGuard and firewall activity logs.
25 +
26 + Subcommands:
27 + show (default) Show activity logs
28 + remove, rm Remove log entries
29 + rotate Remove entries older than N days
30 +
31 + Options for show:
32 + --name <name> Filter by client name
33 + --type <type> Filter by device type
34 + --limit <n> Max results per source (default: 50)
35 + --fw Show only firewall drops
36 + --wg Show only WireGuard events
37 + --follow, -f Follow logs in real time
38 +
39 + Options for remove:
40 + --name <name> Remove entries for specific peer
41 + --all Remove all log entries
42 + --fw Remove only firewall events
43 + --wg Remove only WireGuard events
44 + --before <days> Remove entries older than N days
45 + --force Skip confirmation
46 +
47 + Options for rotate:
48 + --days <n> Days to keep (default: 7)
49 + --force Skip confirmation
50 +
51 + Examples:
52 + wgctl logs
53 + wgctl logs --name phone-nuno
54 + wgctl logs --fw --limit 100
55 + wgctl logs --follow
56 + wgctl logs remove --name phone-nuno
57 + wgctl logs remove --all --force
58 + wgctl logs remove --fw --before 1
59 + wgctl logs rotate
60 + wgctl logs rotate --days 30 --force
61 + EOF
62 + }
63 +
64 + function cmd::logs::run() {
65 + local subcmd="${1:-show}"
66 + if [[ "$subcmd" == --* ]]; then
67 + subcmd="show"
68 + else
69 + shift || true
70 + fi
71 +
72 + case "$subcmd" in
73 + show) cmd::logs::show "$@" ;;
74 + remove|rm|del) cmd::logs::remove "$@" ;;
75 + rotate) cmd::logs::rotate "$@" ;;
76 + help) cmd::logs::help ;;
77 + *)
78 + log::error "Unknown subcommand: '${subcmd}'"
79 + cmd::logs::help
80 + return 1
81 + ;;
82 + esac
83 + }
84 +
85 + function cmd::logs::show() {
86 + local name="" type="" limit=50
87 + local fw_only=false wg_only=false follow=false
88 +
89 + while [[ $# -gt 0 ]]; do
90 + case "$1" in
91 + --name) name="$2"; shift 2 ;;
92 + --type) type="$2"; shift 2 ;;
93 + --limit) limit="$2"; shift 2 ;;
94 + --fw) fw_only=true; shift ;;
95 + --wg) wg_only=true; shift ;;
96 + --follow|-f) follow=true; shift ;;
97 + --help) cmd::logs::help; return ;;
98 + *)
99 + log::error "Unknown flag: $1"
100 + return 1
101 + ;;
102 + esac
103 + done
104 +
105 + if [[ -n "$name" && -n "$type" ]]; then
106 + name=$(peers::resolve_and_require "$name" "$type") || return 1
107 + fi
108 +
109 + local filter_ip=""
110 + if [[ -n "$name" ]]; then
111 + filter_ip=$(peers::get_ip "$name")
112 + [[ -z "$filter_ip" ]] && log::error "Could not find IP for: $name" && return 1
113 + fi
114 +
115 + if $follow; then
116 + cmd::logs::follow "$filter_ip" "$name" "$type" "$fw_only" "$wg_only"
117 + return
118 + fi
119 +
120 + log::section "WireGuard Activity Log"
121 + printf "\n"
122 + $wg_only || cmd::logs::show_fw_events "$filter_ip" "$name" "$type" "$limit"
123 + $fw_only || cmd::logs::show_wg_events "$filter_ip" "$name" "$type" "$limit"
124 + }
125 +
126 + function cmd::logs::follow() {
127 + local filter_ip="${1:-}" filter_name="${2:-}" filter_type="${3:-}"
128 + local fw_only="${4:-false}" wg_only="${5:-false}"
129 + local filter_peers="${6:-}"
130 + local clients_dir
131 + clients_dir="$(ctx::clients)"
132 + local wg_log="$WG_EVENTS_LOG"
133 + local fw_log="$FW_EVENTS_LOG"
134 + $fw_only && wg_log=""
135 + $wg_only && fw_log=""
136 +
137 + log::section "WireGuard Live Log (Ctrl+C to stop)"
138 + printf "\n %-20s %-8s %-20s %-25s %s\n" \
139 + "TIME" "SOURCE" "CLIENT" "DESTINATION/ENDPOINT" "EVENT"
140 + printf " %s\n" "$(printf '─%.0s' {1..90})"
141 +
142 + while IFS="|" read -r source ts client dst_or_endpoint event; do
143 + if [[ "$source" == "fw" ]]; then
144 + local colored_event
145 + case "$event" in
146 + tcp) colored_event="\033[1;33mtcp\033[0m" ;;
147 + udp) colored_event="\033[0;36mudp\033[0m" ;;
148 + icmp) colored_event="\033[0;37micmp\033[0m" ;;
149 + *) colored_event="$event" ;;
150 + esac
151 + printf " %-20s %-8s %-20s %-25s %b\n" \
152 + "$ts" "firewall" "$client" "$dst_or_endpoint" "$colored_event"
153 + else
154 + local colored_event
155 + case "$event" in
156 + attempt) colored_event="\033[1;31mattempt\033[0m" ;;
157 + handshake) colored_event="\033[1;32mhandshake\033[0m" ;;
158 + *) colored_event="$event" ;;
159 + esac
160 + printf " %-20s %-8s %-20s %-25s %b\n" \
161 + "$ts" "wireguard" "$client" "$dst_or_endpoint" "$colored_event"
162 + fi
163 + done < <(json::follow_logs "$fw_log" "$wg_log" "$filter_ip" "$filter_type" \
164 + "$clients_dir" "$filter_peers")
165 + }
166 +
167 + function cmd::logs::remove() {
168 + local name="" type="" before="" force=false
169 + local fw_only=false wg_only=false all=false
170 +
171 + while [[ $# -gt 0 ]]; do
172 + case "$1" in
173 + --name) name="$2"; shift 2 ;;
174 + --type) type="$2"; shift 2 ;;
175 + --before) before="$2"; shift 2 ;;
176 + --fw) fw_only=true; shift ;;
177 + --wg) wg_only=true; shift ;;
178 + --all) all=true; shift ;;
179 + --force) force=true; shift ;;
180 + --help) cmd::logs::help; return ;;
181 + *)
182 + log::error "Unknown flag: $1"
183 + return 1
184 + ;;
185 + esac
186 + done
187 +
188 + # Validate — need at least one filter
189 + if ! $all && [[ -z "$name" && -z "$before" ]]; then
190 + log::error "Specify --name, --before, or --all"
191 + cmd::logs::help
192 + return 1
193 + fi
194 +
195 + local filter_ip=""
196 + if [[ -n "$name" ]]; then
197 + name=$(peers::resolve_and_require "$name" "$type") || return 1
198 + filter_ip=$(peers::get_ip "$name")
199 + fi
200 +
201 + # Build description for confirmation
202 + local desc=""
203 + $all && desc="all entries"
204 + [[ -n "$name" ]] && desc="entries for '${name}'"
205 + [[ -n "$before" ]] && desc="${desc:+$desc, }entries older than ${before} days"
206 + $fw_only && desc="${desc} (fw only)"
207 + $wg_only && desc="${desc} (wg only)"
208 +
209 + if ! $force; then
210 + read -r -p "Remove ${desc}? [y/N] " confirm
211 + case "$confirm" in
212 + [yY][eE][sS]|[yY]) ;;
213 + *) log::info "Aborted"; return 0 ;;
214 + esac
215 + fi
216 +
217 + local result
218 + result=$(json::remove_events_filtered \
219 + "$WG_EVENTS_LOG" "$FW_EVENTS_LOG" \
220 + "${name:-}" "${filter_ip:-}" \
221 + "$fw_only" "$wg_only" \
222 + "${before:-}")
223 +
224 + local removed_wg removed_fw
225 + IFS="|" read -r removed_wg removed_fw <<< "$result"
226 + local total=$(( removed_wg + removed_fw ))
227 +
228 + if [[ "$total" -eq 0 ]]; then
229 + log::wg_warning "No log entries found matching the criteria"
230 + return 0
231 + fi
232 +
233 + log::wg_success "Removed ${total} log entries (wg: ${removed_wg}, fw: ${removed_fw})"
234 + }
235 +
236 + function cmd::logs::show_wg_events() {
237 + local filter_ip="${1:-}" filter_name="${2:-}" filter_type="${3:-}" limit="${4:-50}"
238 +
239 + [[ ! -f "$WG_EVENTS_LOG" ]] && return 0
240 +
241 + printf " WireGuard Events:\n"
242 + printf " %-20s %-20s %-18s %s\n" "TIME" "CLIENT" "ENDPOINT" "EVENT"
243 + printf " %s\n" "$(printf '─%.0s' {1..75})"
244 +
245 + local found=false
246 + while IFS="|" read -r ts client endpoint event; do
247 + [[ -z "$ts" ]] && continue
248 + local colored_event
249 + case "$event" in
250 + attempt*) colored_event="\033[1;31m${event}\033[0m" ;;
251 + handshake*) colored_event="\033[1;32m${event}\033[0m" ;;
252 + *) colored_event="$event" ;;
253 + esac
254 + printf " %-20s %-20s %-18s %b\n" "$ts" "$client" "$endpoint" "$colored_event"
255 + found=true
256 + done < <(json::wg_events "$WG_EVENTS_LOG" "$filter_name" "$filter_type" "$limit")
257 +
258 + $found || printf " —\n"
259 + printf "\n"
260 + }
261 +
262 + function cmd::logs::show_fw_events() {
263 + local filter_ip="${1:-}" filter_name="${2:-}" filter_type="${3:-}" limit="${4:-50}"
264 +
265 + [[ ! -f "$FW_EVENTS_LOG" ]] && return 0
266 +
267 + printf " Firewall Drops:\n"
268 + printf " %-20s %-18s %-25s %s\n" "TIME" "CLIENT" "DESTINATION" "PROTOCOL"
269 + printf " %s\n" "$(printf '─%.0s' {1..75})"
270 +
271 + local found=false
272 + while IFS="|" read -r ts client dst proto; do
273 + [[ -z "$ts" ]] && continue
274 + local colored_proto
275 + case "$proto" in
276 + tcp*) colored_proto="\033[1;33m${proto}\033[0m" ;;
277 + udp*) colored_proto="\033[1;36m${proto}\033[0m" ;;
278 + icmp*) colored_proto="\033[0;37m${proto}\033[0m" ;;
279 + *) colored_proto="$proto" ;;
280 + esac
281 + printf " %-20s %-18s %-25s %b\n" "$ts" "$client" "$dst" "$colored_proto"
282 + found=true
283 + done < <(json::fw_events "$FW_EVENTS_LOG" "$filter_ip" "$filter_type" \
284 + "$(ctx::clients)" "$limit")
285 +
286 + $found || printf " —\n"
287 + printf "\n"
288 + }
289 +
290 +
291 +
292 + function cmd::logs::rotate() {
293 + local days=7 force=false
294 +
295 + while [[ $# -gt 0 ]]; do
296 + case "$1" in
297 + --days) days="$2"; shift 2 ;;
298 + --force) force=true; shift ;;
299 + --help) cmd::logs::help; return ;;
300 + *) log::error "Unknown flag: $1"; return 1 ;;
301 + esac
302 + done
303 +
304 + $force || {
305 + read -r -p "Remove log entries older than ${days} days? [y/N] " confirm
306 + case "$confirm" in
307 + [yY]*) ;;
308 + *) log::info "Aborted"; return 0 ;;
309 + esac
310 + }
311 +
312 + local result
313 + result=$(json::remove_events_filtered \
314 + "$WG_EVENTS_LOG" "$FW_EVENTS_LOG" \
315 + "" "" "false" "false" "$days")
316 +
317 + local removed_wg removed_fw
318 + IFS="|" read -r removed_wg removed_fw <<< "$result"
319 + local total=$(( removed_wg + removed_fw ))
320 +
321 + if [[ "$total" -eq 0 ]]; then
322 + log::wg_warning "No log entries older than ${days} days"
323 + return 0
324 + fi
325 +
326 + log::wg_success "Rotated ${total} entries older than ${days} days (wg: ${removed_wg}, fw: ${removed_fw})"
327 + }
Newer Older