Son aktivite 1 month ago

gistfile1.txt Ham
1#!/usr/bin/env bash
2
3FW_EVENTS_LOG="$(ctx::fw_events_log)"
4WG_EVENTS_LOG="$(ctx::events_log)"
5
6function 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
20function cmd::logs::help() {
21 cat <<EOF
22Usage: wgctl logs [subcommand] [options]
23
24Show or manage WireGuard and firewall activity logs.
25
26Subcommands:
27 show (default) Show activity logs
28 remove, rm Remove log entries
29 rotate Remove entries older than N days
30
31Options 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
39Options 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
47Options for rotate:
48 --days <n> Days to keep (default: 7)
49 --force Skip confirmation
50
51Examples:
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
61EOF
62}
63
64function 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
85function 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
126function 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
167function 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
236function 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
262function 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
292function 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}