Dernière activité 1 month ago

nuno a révisé ce gist 1 month ago. Aller à la révision

1 file changed, 189 insertions

gistfile1.txt(fichier créé)

@@ -0,0 +1,189 @@
1 + #!/usr/bin/env bash
2 +
3 + function cmd::audit::on_load() {
4 + flag::register --fix
5 + flag::register --peer
6 + flag::register --type
7 + }
8 +
9 + function cmd::audit::help() {
10 + cat <<EOF
11 + Usage: wgctl audit [options]
12 +
13 + Verify that all peers have the correct iptables firewall rules applied.
14 + Checks expected rule count (including inherited rules) vs actual iptables state.
15 +
16 + Options:
17 + --peer <name> Audit specific peer only
18 + --type <type> Audit peers of specific device type only
19 + --fix Attempt to auto-repair missing or extra rules
20 +
21 + Output:
22 + ✅ pass — peer has correct rule count
23 + ❌ fail — peer has missing rules (run --fix to repair)
24 + ⚠️ warn — peer has extra rules (e.g. blocked peers with base rules)
25 +
26 + Examples:
27 + wgctl audit
28 + wgctl audit --peer phone-nuno
29 + wgctl audit --type guest
30 + wgctl audit --fix
31 + EOF
32 + }
33 +
34 + function cmd::audit::run() {
35 + local fix=false peer="" type=""
36 +
37 + while [[ $# -gt 0 ]]; do
38 + case "$1" in
39 + --fix) fix=true; shift ;;
40 + --peer)
41 + if [[ -z "${2:-}" ]]; then
42 + log::error "Flag --peer requires a value"
43 + cmd::audit::help
44 + return 1
45 + fi
46 + peer="$2"
47 + shift 2
48 + ;;
49 + --type) type="$2"; shift 2 ;;
50 + --help) cmd::audit::help; return ;;
51 + *)
52 + log::error "Unknown flag: $1"
53 + return 1
54 + ;;
55 + esac
56 + done
57 +
58 + test::reset
59 + log::section "WireGuard Audit"
60 +
61 + # Precompute iptables counts via single Python call
62 + declare -A peer_fw_counts
63 + while IFS=":" read -r peer_name count; do
64 + [[ -n "$peer_name" ]] && peer_fw_counts["$peer_name"]="$count"
65 + done < <(json::audit_fw_counts "$(ctx::clients)")
66 +
67 + test::section "Peer Rules"
68 + while IFS= read -r peer_name; do
69 + [[ -n "$peer" && "$peer_name" != "$peer" ]] && continue
70 + [[ -n "$type" && "$peer_name" != "${type}-"* ]] && continue
71 + cmd::audit::check_peer "$peer_name" "$fix" "${peer_fw_counts[$peer_name]:-0}"
72 + done < <(peers::all)
73 +
74 + test::section "WireGuard Server"
75 + cmd::audit::check_wg "$fix" "$peer" "$type"
76 +
77 + test::section "Rules"
78 + cmd::audit::check_rules
79 +
80 + test::summary
81 + }
82 +
83 + function cmd::audit::check_peer() {
84 + local peer_name="$1"
85 + local fix="$2"
86 + local actual="${3:-0}"
87 + local ip rule
88 +
89 + ip=$(peers::get_ip "$peer_name")
90 + rule=$(peers::get_meta "$peer_name" "rule")
91 +
92 + # Check rule assigned
93 + if [[ -z "$rule" ]]; then
94 + test::warn "$peer_name — no rule assigned (effective: $(peers::default_rule "$peer_name"))"
95 + return
96 + fi
97 +
98 + # Check rule exists
99 + if ! rule::exists "$rule"; then
100 + test::fail "$peer_name — assigned rule '$rule' does not exist"
101 + return
102 + fi
103 +
104 + # Count expected iptables rules from rule file
105 + local rule_file
106 + rule_file="$(ctx::rule::path "${rule}.rule")"
107 + local block_ports block_ips allow_ports allow_ips expected
108 + block_ports=$(json::count_resolved "$rule" "block_ports")
109 + block_ips=$(json::count_resolved "$rule" "block_ips")
110 + allow_ports=$(json::count_resolved "$rule" "allow_ports")
111 + allow_ips=$(json::count_resolved "$rule" "allow_ips")
112 + expected=$(( (block_ports + block_ips) * 2 + allow_ports + allow_ips ))
113 +
114 + # actual is passed in as $3 — no iptables call here
115 + if [[ "$actual" -eq "$expected" ]]; then
116 + test::pass "$(printf "%-28s rule=%-15s fw: %s/%s" "$peer_name" "$rule" "$actual" "$expected")"
117 + elif [[ "$actual" -gt "$expected" ]]; then
118 + test::warn "$(printf "%-28s rule=%-15s fw: %s/%s (extra rules)" "$peer_name" "$rule" "$actual" "$expected")"
119 + if $fix; then
120 + fw::flush_peer "$ip"
121 + rule::apply "$rule" "$ip" "$peer_name"
122 + test::pass " Fixed: $peer_name"
123 + fi
124 + else
125 + test::fail "$(printf "%-28s rule=%-15s fw: %s/%s (missing rules)" "$peer_name" "$rule" "$actual" "$expected")"
126 + if $fix; then
127 + rule::apply "$rule" "$ip" "$peer_name"
128 + test::pass " Fixed: $peer_name"
129 + fi
130 + fi
131 + }
132 +
133 + function cmd::audit::check_wg() {
134 + local fix="$1" filter_peer="$2" filter_type="$3"
135 + local wg_peers
136 + wg_peers=$(wg show wg0 peers 2>/dev/null)
137 +
138 + while IFS= read -r peer_name; do
139 + [[ -n "$filter_peer" && "$peer_name" != "$filter_peer" ]] && continue
140 + [[ -n "$filter_type" && "$peer_name" != "${filter_type}-"* ]] && continue
141 +
142 + local pub_key
143 + pub_key=$(keys::public "$peer_name" 2>/dev/null)
144 + [[ -z "$pub_key" ]] && test::fail "$peer_name — missing public key" && continue
145 +
146 + if peers::is_blocked "$peer_name"; then
147 + if echo "$wg_peers" | grep -q "$pub_key"; then
148 + test::fail "$peer_name — blocked but still in wg0"
149 + $fix && peers::remove_from_server "$peer_name" && peers::reload
150 + else
151 + test::pass "$peer_name — correctly blocked (not in wg0)"
152 + fi
153 + else
154 + if echo "$wg_peers" | grep -q "$pub_key"; then
155 + test::pass "$peer_name — present in wg0"
156 + else
157 + test::fail "$peer_name — missing from wg0"
158 + if $fix; then
159 + local ip
160 + ip=$(peers::get_ip "$peer_name")
161 + peers::add_to_server "$peer_name" "$pub_key" "$ip"
162 + peers::reload
163 + fi
164 + fi
165 + fi
166 + done < <(peers::all)
167 + }
168 +
169 + function cmd::audit::check_rules() {
170 + local rules_dir
171 + rules_dir="$(ctx::rules)"
172 +
173 + # Precompute peer counts
174 + declare -A rule_counts
175 + while IFS= read -r peer_name; do
176 + local r
177 + r=$(peers::get_meta "$peer_name" "rule")
178 + [[ -z "$r" ]] && continue
179 + rule_counts["$r"]=$(( ${rule_counts["$r"]:-0} + 1 ))
180 + done < <(peers::all)
181 +
182 + for rule_file in "${rules_dir}"/*.rule; do
183 + [[ -f "$rule_file" ]] || continue
184 + local name
185 + name=$(json::get "$rule_file" "name")
186 + local count=${rule_counts["$name"]:-0}
187 + test::pass "Rule '${name}' — ${count} peers assigned"
188 + done
189 + }
Plus récent Plus ancien