Dernière activité 1 month ago

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

1 file changed, 223 insertions

gistfile1.txt(fichier créé)

@@ -0,0 +1,223 @@
1 + #!/usr/bin/env bash
2 +
3 + # ============================================
4 + # Lifecycle
5 + # ============================================
6 +
7 + function cmd::block::on_load() {
8 + flag::register --name
9 + flag::register --type
10 + flag::register --force
11 + flag::register --quiet
12 + flag::register --ip
13 + flag::register --port
14 + flag::register --proto
15 + flag::register --subnet
16 + flag::register --block-name
17 +
18 + # System - NET Services
19 + flag::register --service
20 + }
21 +
22 + # ============================================
23 + # Help
24 + # ============================================
25 +
26 + function cmd::block::help() {
27 + cat <<EOF
28 + Usage: wgctl block --name <name> [options]
29 +
30 + Block a client entirely or restrict access to specific IPs/ports/subnets.
31 + Block rules are persisted and restored on WireGuard restart.
32 +
33 + Options:
34 + --name <name> Client name (e.g. phone-nuno)
35 + --type <type> Device type (optional, combines with --name)
36 + --ip <ip> Block access to specific IP (repeatable)
37 + --subnet <cidr> Block access to subnet (repeatable)
38 + --port <ip:port:proto> Block specific port, e.g. 10.0.0.210:9000:tcp (repeatable)
39 + --force Skip confirmation prompt
40 + --quiet Suppress output (used by group block)
41 +
42 + Examples:
43 + wgctl block --name phone-nuno
44 + wgctl block --name nuno --type phone
45 + wgctl block --name phone-nuno --ip 10.0.0.210
46 + wgctl block --name phone-nuno --subnet 10.0.0.0/24
47 + wgctl block --name phone-nuno --port 10.0.0.210:9000:tcp
48 + wgctl ban --name phone-nuno
49 + EOF
50 + }
51 +
52 + # ============================================
53 + # Block Run
54 + # ============================================
55 +
56 + function cmd::block::run() {
57 + local name="" type="" block_name=""
58 + local ips=() subnets=() ports=() services=()
59 + local quiet=false force=false
60 + local changed=false
61 +
62 + while [[ $# -gt 0 ]]; do
63 + case "$1" in
64 + --name) name="$2"; shift 2 ;;
65 + --type) type="$2"; shift 2 ;;
66 + --ip) ips+=("$2"); shift 2 ;;
67 + --block-name) block_name="$2"; shift 2 ;;
68 + --service) services+=("$2"); shift 2 ;;
69 + --force) force=true; shift ;;
70 + --quiet) quiet=true; shift ;;
71 + --subnet) subnets+=("$2"); shift 2 ;;
72 + --port) ports+=("$2"); shift 2 ;;
73 + --help) cmd::block::help; return ;;
74 + *)
75 + log::error "Unknown flag: $1"
76 + cmd::block::help
77 + return 1 ;;
78 + esac
79 + done
80 +
81 + [[ -z "$name" ]] && log::error "Missing required flag: --name" && \
82 + cmd::block::help && return 1
83 +
84 + name=$(peers::resolve_and_require "$name" "$type") || return 1
85 +
86 + local client_ip
87 + client_ip=$(peers::get_ip "$name") || return 1
88 +
89 + # Full block if no specific targets
90 + if [[ ${#ips[@]} -eq 0 && ${#ports[@]} -eq 0 && \
91 + ${#subnets[@]} -eq 0 && ${#services[@]} -eq 0 ]]; then
92 + if peers::is_blocked "$name" || block::has_file "$name"; then
93 + log::wg_warning "Client is already blocked: ${name}"
94 + return 0
95 + fi
96 + monitor::update_endpoint_cache
97 + cmd::block::_block_all "$name" "$client_ip" "$quiet"
98 + return 0
99 + fi
100 +
101 + # Specific rules — check if already fully blocked
102 + if block::has_file "$name"; then
103 + local direct
104 + direct=$(block::is_blocked_direct "$name")
105 + if [[ "$direct" == "true" ]]; then
106 + log::wg_warning "${name} is fully blocked — unblock first to add specific rules"
107 + return 1
108 + fi
109 + fi
110 +
111 + # Block specific IPs
112 + for ip in "${ips[@]}"; do
113 + ip::require_valid "$ip"
114 + fw::block_ip "$client_ip" "$ip"
115 + block::add_rule "$name" "$client_ip" "ip" "${block_name:-}" "$ip"
116 + $quiet || log::wg_success "${ip} has been blocked for ${name}"
117 + done
118 +
119 + # Block specific subnets
120 + for subnet in "${subnets[@]}"; do
121 + ip::require_valid "$subnet"
122 + fw::block_subnet "$client_ip" "$subnet"
123 + block::add_rule "$name" "$client_ip" "subnet" "${block_name:-}" "$subnet"
124 + $quiet || log::wg_success "${subnet} has been blocked for ${name}"
125 + done
126 +
127 + # Block specific ports
128 + for entry in "${ports[@]}"; do
129 + local b_target b_port b_proto
130 + IFS=":" read -r b_target b_port b_proto <<< "$entry"
131 + ip::require_valid "$b_target"
132 + fw::block_port "$client_ip" "$b_target" "$b_port" "${b_proto:-tcp}"
133 + block::add_rule "$name" "$client_ip" "port" "${block_name:-}" \
134 + "$b_target" "$b_port" "${b_proto:-tcp}"
135 + $quiet || log::wg_success "${client_ip}:${b_port}:${b_proto:-tcp} has been blocked for ${name}"
136 + done
137 +
138 + # Block services
139 + for svc in "${services[@]}"; do
140 + local resolved_lines=()
141 + mapfile -t resolved_lines < <(net::resolve "$svc" 2>/dev/null)
142 + if [[ ${#resolved_lines[@]} -eq 0 ]]; then
143 + log::error "Service not found or has no ports: ${svc}"
144 + return 1
145 + fi
146 +
147 + # Check if already blocked
148 + local already_blocked=true
149 + for resolved in "${resolved_lines[@]}"; do
150 + if [[ "$resolved" == *:*:* ]]; then
151 + local b_ip b_port b_proto
152 + IFS=":" read -r b_ip b_port b_proto <<< "$resolved"
153 + fw::has_block_rule "$client_ip" "$b_ip" "$b_proto" "$b_port" 2>/dev/null || \
154 + { already_blocked=false; break; }
155 + else
156 + fw::has_block_rule "$client_ip" "$resolved" 2>/dev/null || \
157 + { already_blocked=false; break; }
158 + fi
159 + done
160 +
161 + if $already_blocked; then
162 + $quiet || log::wg_warning "${svc} is already blocked for ${name}"
163 + continue
164 + fi
165 +
166 + for resolved in "${resolved_lines[@]}"; do
167 + if [[ "$resolved" == *:*:* ]]; then
168 + local b_ip b_port b_proto
169 + IFS=":" read -r b_ip b_port b_proto <<< "$resolved"
170 + fw::block_port "$client_ip" "$b_ip" "$b_port" "$b_proto"
171 + block::add_rule "$name" "$client_ip" "port" "$svc" \
172 + "$b_ip" "$b_port" "$b_proto"
173 + else
174 + fw::block_ip "$client_ip" "$resolved"
175 + block::add_rule "$name" "$client_ip" "ip" "$svc" "$resolved"
176 + fi
177 + done
178 +
179 + changed=true
180 + $quiet || log::wg_success "${svc} has been blocked for ${name}"
181 + done
182 +
183 + [[ ${#ips[@]} -gt 0 || ${#ports[@]} -gt 0 || \
184 + ${#subnets[@]} -gt 0 ]] && changed=true
185 +
186 + # Reapply in correct order: rule ACCEPT first, then peer DROP rules
187 + # Only reorder if rules were actually added
188 + if $changed; then
189 + local peer_rule
190 + peer_rule=$(peers::get_meta "$name" "rule")
191 + if [[ -n "$peer_rule" ]] && rule::exists "$peer_rule"; then
192 + fw::flush_peer "$client_ip"
193 + rule::apply "$peer_rule" "$client_ip" "$name"
194 + block::restore_rules_for "$name" "$client_ip"
195 + fi
196 + fi
197 +
198 + return 0
199 + }
200 +
201 + function cmd::block::_get_endpoint() {
202 + local name="$1" public_key="$2"
203 + local endpoint
204 + endpoint=$(monitor::endpoint_for_key "$public_key")
205 + if [[ -z "$endpoint" || "$endpoint" == "(none)" ]]; then
206 + endpoint=$(monitor::get_cached_endpoint "$name")
207 + fi
208 + echo "$endpoint"
209 + }
210 +
211 + function cmd::block::_block_all() {
212 + local name="${1:?name required}"
213 + local client_ip="${2:?client_ip required}"
214 + local quiet="${3:-false}"
215 +
216 + # Apply fw rules and remove from server
217 + block::apply_full "$name" "$client_ip"
218 +
219 + # Mark as directly blocked
220 + block::set_direct "$name" "$client_ip" "true"
221 +
222 + $quiet || log::wg_success "${name} has been blocked."
223 + }
Plus récent Plus ancien