最後活躍 1 month ago

gistfile1.txt 原始檔案
1#!/usr/bin/env bash
2
3function cmd::inspect::on_load() {
4 flag::register --name
5 flag::register --type
6 flag::register --config
7 flag::register --qr
8}
9
10function cmd::inspect::help() {
11 cat <<EOF
12Usage: wgctl inspect --name <name> [--type <type>]
13 wgctl inspect <full-name>
14
15Show detailed information for a single client.
16
17Options:
18 --name <name> Client name
19 --type <type> Device type (optional, combines with --name)
20 --config Show raw client config
21 --qr Show QR code
22
23Examples:
24 wgctl inspect --name phone-nuno
25 wgctl inspect --name nuno --type phone
26 wgctl inspect --name phone-nuno --config
27 wgctl inspect --name phone-nuno --qr
28EOF
29}
30
31# ============================================
32# Private helpers
33# ============================================
34
35function cmd::inspect::_section() {
36 local title="$1"
37 printf "\n \033[0;37m── %s ──────────────────────────────────\033[0m\n" "$title"
38}
39
40function cmd::inspect::_peer_info() {
41 local name="${1:-}"
42
43 local ip type rule public_key allowed_ips
44 ip=$(peers::get_ip "$name")
45 type=$(peers::get_type "$name")
46 rule=$(peers::get_meta "$name" "rule")
47 public_key=$(keys::public "$name" 2>/dev/null || echo "")
48 allowed_ips=$(grep "^AllowedIPs" "$(ctx::clients)/${name}.conf" \
49 2>/dev/null | cut -d'=' -f2- | xargs)
50
51 # Status
52 local handshake_ts is_blocked last_ts
53 handshake_ts=$(monitor::get_handshake_ts "$public_key")
54 peers::is_blocked "$name" && is_blocked="true" || is_blocked="false"
55 last_ts=$(monitor::last_attempt "$name")
56
57 local status last_seen endpoint
58 status=$(peers::format_status "$name" "$public_key" \
59 "$is_blocked" "false" "$handshake_ts" "$last_ts")
60 last_seen=$(peers::format_last_seen "$name" "$public_key" \
61 "$is_blocked" "$last_ts" "" "$handshake_ts")
62 endpoint=$(monitor::get_cached_endpoint "$name")
63
64 local activity_total
65 activity_total=$(peers::format_activity_total "$public_key")
66
67 local activity_current
68 activity_current=$(peers::format_activity_current "$public_key")
69
70 local subtype
71 subtype=$(peers::get_meta "$name" "subtype")
72
73 cmd::inspect::_section "Client"
74 ui::row "Name" "$name"
75 ui::row "IP" "$ip"
76 ui::row "Type" "$(peers::display_type "$type" "$subtype")"
77 ui::row "Rule" "${rule:-—}"
78 ui::row "Status" "$(echo -e "$status")"
79 ui::row "Endpoint" "${endpoint:-—}"
80 ui::row "Last seen" "$last_seen"
81 ui::row "AllowedIPs" "$allowed_ips"
82 ui::row "Public key" "${public_key:-—}"
83 ui::row "Activity" "Total: $activity_total | Current: $activity_current"
84}
85
86function cmd::inspect::_rule_info() {
87 local name="$1"
88 local rule
89 rule=$(peers::get_meta "$name" "rule")
90 [[ -z "$rule" ]] && return 0
91
92 rule::exists "$rule" || return 0
93
94 local rule_file
95 rule_file="$(ctx::rule::path "${rule}.rule")"
96
97 ui::section "Rule: ${rule}"
98
99 local desc dns_redirect
100 desc=$(json::get "$rule_file" "desc")
101 dns_redirect=$(json::get "$rule_file" "dns_redirect")
102 ui::row "Description" "${desc:-—}"
103 ui::row "DNS Redirect" "${dns_redirect:-false}"
104
105 local allow_ports allow_ips block_ips block_ports
106 allow_ports=$(json::get "$rule_file" "allow_ports")
107 allow_ips=$(json::get "$rule_file" "allow_ips")
108 block_ips=$(json::get "$rule_file" "block_ips")
109 block_ports=$(json::get "$rule_file" "block_ports")
110
111 if [[ -n "$allow_ports" || -n "$allow_ips" ]]; then
112 printf " %-20s\n" "Allows:"
113 ui::print_list "+" "$allow_ports"
114 ui::print_list "+" "$allow_ips"
115 else
116 ui::row "Allows" "—"
117 fi
118
119 if [[ -n "$block_ips" || -n "$block_ports" ]]; then
120 printf " %-20s\n" "Blocks:"
121 ui::print_list "-" "$block_ips"
122 ui::print_list "-" "$block_ports"
123 else
124 ui::row "Blocks" "—"
125 fi
126}
127
128function cmd::inspect::_group_info() {
129 local name="$1"
130
131 ui::section "Groups"
132
133 local groups=()
134 mapfile -t groups < <(json::peer_groups "$(ctx::groups)" "$name")
135
136 if [[ ${#groups[@]} -eq 0 ]] || [[ -z "${groups[0]:-}" ]]; then
137 printf " —\n"
138 return 0
139 fi
140
141 for g in "${groups[@]}"; do
142 [[ -z "$g" ]] && continue
143 local count
144 count=$(json::count "$(group::path "$g")" "peers")
145 printf " %-20s %s peers\n" "$g" "$count"
146 done
147}
148
149function cmd::inspect::_firewall_info() {
150 local name="$1" show_nflog="${2:-false}"
151 local ip
152 ip=$(peers::get_ip "$name")
153
154 ui::section "Firewall"
155
156 local count=0
157 while IFS=":" read -r pname pcount; do
158 [[ "$pname" == "$name" ]] && count="$pcount" && break
159 done < <(json::audit_fw_counts "$(ctx::clients)")
160
161 ui::row "Active rules" "$count"
162
163if [[ "$count" -gt 0 ]]; then
164 printf "\n"
165 iptables -L FORWARD -n </dev/null | grep -F "$ip" | while IFS= read -r rule; do
166 [[ -z "$rule" ]] && continue
167 echo "$rule" | grep -q "NFLOG" && continue # skip NFLOG
168 ui::firewall_rule "$rule"
169 done
170 fi
171}
172
173function cmd::inspect::_config() {
174 local name="$1"
175 cmd::inspect::_section "Config"
176 printf "\n"
177 cat "$(ctx::clients)/${name}.conf"
178 printf "\n"
179}
180
181# ============================================
182# Run
183# ============================================
184
185function cmd::inspect::run() {
186 local name="" type="" show_config=false show_qr=false
187
188 if [[ $# -gt 0 && "$1" != "--"* ]]; then
189 name="$1"
190 shift
191 fi
192
193 while [[ $# -gt 0 ]]; do
194 case "$1" in
195 --name) name="$2"; shift 2 ;;
196 --type) type="$2"; shift 2 ;;
197 --config) show_config=true; shift ;;
198 --qr) show_qr=true; shift ;;
199 --help) cmd::inspect::help; return ;;
200 *)
201 log::error "Unknown flag: $1"
202 cmd::inspect::help
203 return 1
204 ;;
205 esac
206 done
207
208 if [[ -z "$name" ]]; then
209 log::error "Missing required flag: --name"
210 cmd::inspect::help
211 return 1
212 fi
213
214 name=$(peers::resolve_and_require "$name" "$type") || return 1
215
216 load_command list
217
218 log::section "Inspect: ${name}"
219
220 cmd::inspect::_peer_info "$name"
221 cmd::inspect::_rule_info "$name"
222 cmd::inspect::_group_info "$name"
223 cmd::inspect::_firewall_info "$name"
224
225 if $show_config; then
226 cmd::inspect::_config "$name"
227 fi
228
229 if $show_qr; then
230 cmd::inspect::_section "QR Code"
231 printf "\n"
232 load_command qr
233 cmd::qr::run --name "$name"
234 fi
235
236 printf "\n"
237}