Последняя активность 1 month ago

Версия 2b92cdbaa73dc749d654ae6f743a5b359d87d505

gistfile1.txt Исходник
1function cmd::watch::_poll_handshakes() {
2 local filter_name="${1:-}" filter_type="${2:-}" filter_peers="${3:-}"
3 local w_client="${4:-20}" w_dest="${5:-18}"
4
5 while IFS= read -r line; do
6 local public_key ts
7 public_key=$(echo "$line" | awk '{print $1}')
8 ts=$(echo "$line" | awk '{print $2}')
9 [[ -z "$ts" || "$ts" == "0" ]] && continue
10
11 local client_name=""
12 for conf in "$(ctx::clients)"/*.conf; do
13 [[ -f "$conf" ]] || continue
14 local cname
15 cname=$(basename "$conf" .conf)
16 local key
17 key=$(keys::public "$cname" 2>/dev/null || echo "")
18 if [[ "$key" == "$public_key" ]]; then
19 client_name="$cname"
20 break
21 fi
22 done
23 [[ -z "$client_name" ]] && continue
24 [[ -n "$filter_name" && "$client_name" != "$filter_name" ]] && continue
25
26 local safe_key
27 safe_key=$(echo "$public_key" | md5sum | cut -d' ' -f1)
28 local prev_ts_file="/tmp/wgctl_hs_${safe_key}"
29 local prev_ts="0"
30 [[ -f "$prev_ts_file" ]] && prev_ts=$(cat "$prev_ts_file")
31 [[ "$ts" == "$prev_ts" ]] && continue
32
33 local gap=$(( ts - ${prev_ts:-0} ))
34 echo "$ts" > "$prev_ts_file"
35 (( gap < ${WG_HANDSHAKE_CHECK_TIME_SEC:-300} )) && continue
36
37 local ts_fmt
38 ts_fmt=$(fmt::datetime_short "$ts")
39 local endpoint
40 endpoint=$(monitor::endpoint_for_key "$public_key")
41
42 # Resolve endpoint
43 local endpoint_display
44 endpoint_display=$(resolve::ip "${endpoint:-}")
45 [[ -z "$endpoint_display" ]] && endpoint_display="${endpoint:-—}"
46
47 ui::watch::wg_row "$ts_fmt" "$client_name" "$endpoint_display" "handshake" \
48 "$w_client" "$w_dest"
49
50 done < <(wg show "$(config::interface)" latest-handshakes 2>/dev/null)
51}
52function cmd::watch::_tail_events() {
53 local filter_name="${1:-}" filter_type="${2:-}" filter_peers="${3:-}"
54 local blocked_only="${4:-false}" restricted_only="${5:-false}" allowed_only="${6:-false}"
55 local w_client="${7:-20}" w_dest="${8:-18}"
56
57 # Build ip->name map
58 declare -A ip_to_name=()
59 while IFS= read -r conf; do
60 local cname
61 cname=$(basename "$conf" .conf)
62 local ip
63 ip=$(grep "^Address" "$conf" 2>/dev/null | awk '{print $3}' | cut -d'/' -f1)
64 [[ -n "$ip" && -n "$cname" ]] && ip_to_name["$ip"]="$cname"
65 done < <(find "$(ctx::clients)" -name "*.conf" 2>/dev/null)
66
67 declare -A _WATCH_LAST_FW=()
68 declare -A _WATCH_LAST_WG=()
69
70 local source_file
71 source_file=$(mktemp)
72 echo "wg" > "$source_file"
73 trap "rm -f '$source_file'" EXIT
74
75 tail -f "$(ctx::events_log)" "$(ctx::fw_events_log)" 2>/dev/null \
76 | while IFS= read -r line; do
77 [[ -z "$line" ]] && continue
78
79 if [[ "$line" == "==> "* ]]; then
80 [[ "$line" == *"fw_events"* ]] && echo "fw" > "$source_file" || echo "wg" > "$source_file"
81 continue
82 fi
83
84 local source
85 source=$(cat "$source_file")
86
87 if [[ "$source" == "fw" ]]; then
88 $allowed_only && continue
89
90 local fw_data
91 fw_data=$(python3 "$(ctx::json_helper)" parse_fw_event "$line" 2>/dev/null) || continue
92 [[ -z "$fw_data" ]] && continue
93
94 local ts src_ip dest_ip dest_port proto
95 IFS='|' read -r ts src_ip dest_ip dest_port proto <<< "$fw_data"
96 [[ -z "$src_ip" ]] && continue
97
98 local client="${ip_to_name[$src_ip]:-$src_ip}"
99 [[ -n "$filter_name" && "$client" != "$filter_name" ]] && continue
100
101 local fw_key="${src_ip}:${dest_ip}:${dest_port}:${proto}"
102 local now; now=$(date +%s)
103 local window=30
104 [[ "$proto" == "17" || "$proto" == "udp" ]] && window=10
105 [[ "$proto" == "1" || "$proto" == "icmp" ]] && window=5
106 local last="${_WATCH_LAST_FW[$fw_key]:-0}"
107 (( now - last < window )) && continue
108 _WATCH_LAST_FW["$fw_key"]="$now"
109
110 local ts_fmt
111 ts_fmt=$(fmt::datetime_short "$(json::iso_to_ts "$ts" 2>/dev/null || echo 0)")
112
113 local dest_display
114 dest_display=$(resolve::dest "$dest_ip" "$dest_port" "$proto")
115
116 ui::watch::fw_row "$ts_fmt" "$client" "$dest_display" "$w_client" "$w_dest"
117
118 else
119 $restricted_only && continue
120
121 local ev_data
122 ev_data=$(python3 "$(ctx::json_helper)" parse_event "$line" 2>/dev/null) || continue
123 [[ -z "$ev_data" ]] && continue
124
125 local ts client endpoint event
126 IFS='|' read -r ts client endpoint event <<< "$ev_data"
127 [[ -n "$filter_name" && "$client" != "$filter_name" ]] && continue
128 $blocked_only && [[ "$event" != "attempt" ]] && continue
129 $allowed_only && [[ "$event" != "handshake" ]] && continue
130
131 local wg_key="${client}:${endpoint}:${event}"
132 local now; now=$(date +%s)
133 local last="${_WATCH_LAST_WG[$wg_key]:-0}"
134
135 # Handshakes — only show if gap > 5min (new session)
136 # Attempts — shorter window (30s) since each attempt is meaningful
137 local window=30
138 [[ "$event" == "handshake" ]] && window="${WG_HANDSHAKE_CHECK_TIME_SEC:-300}"
139
140 (( now - last < window )) && continue
141 _WATCH_LAST_WG["$wg_key"]="$now"
142
143 local ts_fmt
144 ts_fmt=$(fmt::datetime_short "$(json::iso_to_ts "$ts" 2>/dev/null || echo 0)")
145
146 # Resolve endpoint
147 local endpoint_display
148 endpoint_display=$(resolve::ip "${endpoint:-}")
149 [[ -z "$endpoint_display" ]] && endpoint_display="${endpoint:-—}"
150
151 ui::watch::wg_row "$ts_fmt" "$client" "$endpoint_display" "$event" \
152 "$w_client" "$w_dest"
153 fi
154 done
155
156 rm -f "$source_file"
157}