最后活跃于 1 month ago

nuno 修订了这个 Gist 1 month ago. 转到此修订

1 file changed, 157 insertions

gistfile1.txt(文件已创建)

@@ -0,0 +1,157 @@
1 + function 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 + }
52 + function 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 + }
上一页 下一页