Ultima attività 1 month ago

nuno ha revisionato questo gist 1 month ago. Vai alla revisione

1 file changed, 358 insertions

net.command.sh(file creato)

@@ -0,0 +1,358 @@
1 + #!/usr/bin/env bash
2 +
3 + function cmd::net::on_load() {
4 + flag::register --name
5 + flag::register --ip
6 + flag::register --port
7 + flag::register --desc
8 + flag::register --tag
9 + flag::register --detailed
10 + flag::register --force
11 +
12 + command::mixin json_output
13 + }
14 +
15 + function cmd::net::help() {
16 + cat <<EOF
17 + Usage: wgctl net <subcommand> [options]
18 +
19 + Manage named network services for use with block/allow rules.
20 + Services map names to IPs and ports, making rules more readable.
21 +
22 + Subcommands:
23 + list List all services
24 + show --name <name> Show service details
25 + add --name <name> --ip <ip> Add a service
26 + add --name <svc:port-name> --port <port:proto>
27 + Add a port to a service
28 + rm --name <name> Remove service or port
29 + rm --name <svc:ports> Remove all ports from service
30 +
31 + Options for add (service):
32 + --name <name> Service name (e.g. proxmox)
33 + --ip <ip> Service IP address
34 + --desc <description> Optional description
35 + --tag <tag> Optional tag (repeatable)
36 +
37 + Options for add (port):
38 + --name <svc:port-name> Service:port-name (e.g. proxmox:web-ui)
39 + --port <port:proto> Port and protocol (e.g. 8006:tcp)
40 + --desc <description> Optional description
41 +
42 + Options for list:
43 + --detailed Show ports for each service
44 + --tag <tag> Filter by tag
45 +
46 + Examples:
47 + wgctl net list
48 + wgctl net list --detailed
49 + wgctl net list --tag admin
50 + wgctl net show --name proxmox
51 + wgctl net add --name proxmox --ip 10.0.0.100 --desc "Proxmox VE"
52 + wgctl net add --name proxmox:web-ui --port 8006:tcp --desc "Web UI"
53 + wgctl net add --name proxmox:ssh --port 22:tcp
54 + wgctl net rm --name proxmox:web-ui
55 + wgctl net rm --name proxmox:ports
56 + wgctl net rm --name proxmox
57 + EOF
58 + }
59 +
60 + function cmd::net::run() {
61 + local subcmd="${1:-list}"
62 + shift || true
63 +
64 + if command::json; then
65 + cmd::net::_output_json
66 + return 0
67 + fi
68 +
69 + case "$subcmd" in
70 + list) cmd::net::list "$@" ;;
71 + show) cmd::net::show "$@" ;;
72 + add) cmd::net::add "$@" ;;
73 + rm|remove|del) cmd::net::rm "$@" ;;
74 + help) cmd::net::help ;;
75 + *)
76 + log::error "Unknown subcommand: '${subcmd}'"
77 + cmd::net::help
78 + return 1 ;;
79 + esac
80 + }
81 +
82 + # ============================================
83 + # List
84 + # ============================================
85 +
86 + function cmd::net::list() {
87 + local detailed=false filter_tag=""
88 +
89 + while [[ $# -gt 0 ]]; do
90 + case "$1" in
91 + --detailed) detailed=true; shift ;;
92 + --tag) filter_tag="$2"; shift 2 ;;
93 + --help) cmd::net::help; return ;;
94 + *) log::error "Unknown flag: $1"; return 1 ;;
95 + esac
96 + done
97 +
98 + local net_file
99 + net_file="$(ctx::net)"
100 +
101 + if [[ ! -f "$net_file" ]]; then
102 + log::wg_warning "No services configured. Use 'wgctl net add' to add one."
103 + return 0
104 + fi
105 +
106 + # Collect filtered data and build ports display per service
107 + local filtered_data=""
108 + while IFS="|" read -r name ip desc tags port_count; do
109 + [[ -z "$name" ]] && continue
110 + [[ -n "$filter_tag" && "$tags" != *"$filter_tag"* ]] && continue
111 +
112 + # Build ports display from json::net_show
113 + local ports_display=""
114 + while IFS="|" read -r ptype pname pport pproto pdesc; do
115 + [[ "$ptype" != "port" ]] && continue
116 + local port_str=":${pport}"
117 + [[ -n "$pproto" && "$pproto" != "tcp" ]] && port_str="${port_str}/${pproto}"
118 + ports_display+="${port_str}, "
119 + done < <(json::net_show "$net_file" "$name")
120 + ports_display="${ports_display%, }"
121 + [[ -z "$ports_display" ]] && ports_display="-"
122 +
123 + filtered_data+="${name}|${ip}|${desc}|${tags}|${ports_display}"$'\n'
124 + done < <(json::net_list "$net_file")
125 +
126 + [[ -z "$filtered_data" ]] && {
127 + [[ -n "$filter_tag" ]] && \
128 + log::wg_warning "No services with tag: ${filter_tag}" || \
129 + log::wg_warning "No services configured"
130 + return 0
131 + }
132 +
133 + # Measure column widths
134 + local w_name=12 w_ip=13 w_ports=16
135 + while IFS="|" read -r name ip desc tags ports; do
136 + [[ -z "$name" ]] && continue
137 + (( ${#name} > w_name )) && w_name=${#name}
138 + (( ${#ip} > w_ip )) && w_ip=${#ip}
139 + (( ${#ports} > w_ports )) && w_ports=${#ports}
140 + done <<< "$filtered_data"
141 + (( w_name += 2 ))
142 + (( w_ip += 2 ))
143 + (( w_ports += 2 ))
144 +
145 + log::section "Network Services"
146 + echo ""
147 +
148 + if display::is_table "net_list"; then
149 + cmd::net::_render_table "$filtered_data"
150 + return 0
151 + fi
152 +
153 + while IFS="|" read -r name ip desc tags ports; do
154 + [[ -z "$name" ]] && continue
155 + ui::net::list_row "$name" "$ip" "$desc" "$tags" "$ports" \
156 + "$w_name" "$w_ip" "$w_ports"
157 +
158 + if $detailed; then
159 + while IFS="|" read -r ptype pname pport pproto pdesc; do
160 + [[ "$ptype" != "port" ]] && continue
161 + ui::net::show_port_row "$pname" "$pport" "$pproto" "$pdesc"
162 + done < <(json::net_show "$net_file" "$name")
163 + echo ""
164 + fi
165 + done <<< "$filtered_data"
166 +
167 + echo ""
168 + }
169 +
170 + function cmd::net::_render_table() {
171 + local data="${1:-}"
172 + [[ -z "$data" ]] && return 0
173 +
174 + ui::net::list_header_table
175 + while IFS='|' read -r name ip desc tags port_count; do
176 + [[ -z "$name" ]] && continue
177 + ui::net::list_row_table "$name" "$ip" "$desc" "$tags" "$port_count"
178 + done <<< "$data"
179 + }
180 +
181 + # ============================================
182 + # Show
183 + # ============================================
184 +
185 + function cmd::net::show() {
186 + local name=""
187 + while [[ $# -gt 0 ]]; do
188 + case "$1" in
189 + --name) util::require_flag "--name" "${2:-}" || return 1
190 + name="$2"; shift 2 ;;
191 + --help) cmd::net::help; return ;;
192 + *) log::error "Unknown flag: $1"; return 1 ;;
193 + esac
194 + done
195 +
196 + [[ -z "$name" ]] && log::error "Missing required flag: --name" && return 1
197 + net::require_exists "$name" || return 1
198 +
199 + log::section "Service: ${name}"
200 + printf "\n"
201 +
202 + local has_ports=false
203 + while IFS="|" read -r key val1 val2 val3 val4; do
204 + case "$key" in
205 + name) ui::row "Name" "$val1" ;;
206 + desc) ui::row "Description" "${val1:-—}" ;;
207 + tags) ui::row "Tags" "${val1:-—}" ;;
208 + ip) ui::row "IP" "$val1" ;;
209 + port)
210 + if ! $has_ports; then
211 + printf " %-20s\n" "Ports:"
212 + has_ports=true
213 + fi
214 + ui::net::show_port_row "$val1" "$val2" "$val3" "$val4"
215 + ;;
216 + esac
217 + done < <(json::net_show "$(ctx::net)" "$name")
218 +
219 + printf "\n"
220 + }
221 +
222 + # ============================================
223 + # Add
224 + # ============================================
225 +
226 + function cmd::net::add() {
227 + local name="" ip="" port="" desc="" tags=()
228 +
229 + while [[ $# -gt 0 ]]; do
230 + case "$1" in
231 + --name) util::require_flag "--name" "${2:-}" || return 1
232 + name="$2"; shift 2 ;;
233 + --ip) ip="$2"; shift 2 ;;
234 + --port) port="$2"; shift 2 ;;
235 + --desc) desc="$2"; shift 2 ;;
236 + --tag) tags+=("$2"); shift 2 ;;
237 + --help) cmd::net::help; return ;;
238 + *) log::error "Unknown flag: $1"; return 1 ;;
239 + esac
240 + done
241 +
242 + [[ -z "$name" ]] && log::error "Missing required flag: --name" && return 1
243 +
244 + if [[ "$name" == *:* ]]; then
245 + # Port mode: proxmox:web-ui
246 + local svc_name="${name%%:*}"
247 + local port_name="${name##*:}"
248 +
249 + [[ -z "$port" ]] && log::error "Missing required flag: --port" && return 1
250 + net::require_exists "$svc_name" || return 1
251 +
252 + local port_num proto
253 + if [[ "$port" == *:* ]]; then
254 + port_num="${port%%:*}"
255 + proto="${port##*:}"
256 + else
257 + port_num="$port"
258 + proto="tcp"
259 + fi
260 +
261 + json::net_add_port "$(ctx::net)" "$svc_name" "$port_name" \
262 + "$port_num" "$proto" "$desc"
263 +
264 + log::wg_success "Added port: ${svc_name}:${port_name} → ${port_num}/${proto}"
265 + else
266 + # Service mode: proxmox
267 + [[ -z "$ip" ]] && log::error "Missing required flag: --ip" && return 1
268 +
269 + local tags_str
270 + tags_str=$(IFS=','; echo "${tags[*]}")
271 +
272 + json::net_add_service "$(ctx::net)" "$name" "$ip" "$desc" "$tags_str"
273 +
274 + log::wg_success "Service added: ${name} → ${ip}"
275 + fi
276 + return 0
277 + }
278 +
279 + # ============================================
280 + # Remove
281 + # ============================================
282 +
283 + function cmd::net::rm() {
284 + local name="" force=false
285 +
286 + while [[ $# -gt 0 ]]; do
287 + case "$1" in
288 + --name) util::require_flag "--name" "${2:-}" || return 1
289 + name="$2"; shift 2 ;;
290 + --force) force=true; shift ;;
291 + --help) cmd::net::help; return ;;
292 + *) log::error "Unknown flag: $1"; return 1 ;;
293 + esac
294 + done
295 +
296 + [[ -z "$name" ]] && log::error "Missing required flag: --name" && return 1
297 +
298 + # Validate existence
299 + if [[ "$name" == *:* ]]; then
300 + local svc_name="${name%%:*}"
301 + local port_name="${name##*:}"
302 + if [[ "$port_name" != "ports" ]]; then
303 + # Check specific port exists
304 + local exists
305 + exists=$(json::net_exists "$(ctx::net)" "$name")
306 + if [[ "$exists" != "true" ]]; then
307 + log::error "Port not found: ${name}"
308 + return 1
309 + fi
310 + else
311 + net::require_exists "$svc_name" || return 1
312 + fi
313 + else
314 + net::require_exists "$name" || return 1
315 + fi
316 +
317 + if ! $force; then
318 + local what="service '${name}'"
319 + [[ "$name" == *:ports ]] && what="all ports from '${name%%:*}'"
320 + [[ "$name" == *:* && "$name" != *:ports ]] && what="port '${name}'"
321 + read -r -p "Remove ${what}? [y/N] " confirm
322 + case "$confirm" in
323 + [yY]*) ;;
324 + *) log::info "Aborted"; return 0 ;;
325 + esac
326 + fi
327 +
328 + json::net_remove "$(ctx::net)" "$name"
329 + log::wg_success "Removed: ${name}"
330 + return 0
331 + }
332 +
333 + function cmd::net::_output_json() {
334 + local net_file
335 + net_file="$(ctx::net)"
336 + local data
337 + data=$(json::net_list "$net_file" 2>/dev/null)
338 +
339 + local -a services=()
340 + while IFS='|' read -r name ip desc tags port_count; do
341 + [[ -z "$name" ]] && continue
342 + # Build tags array
343 + local tags_json="[]"
344 + if [[ -n "$tags" ]]; then
345 + local tags_array
346 + tags_array=$(echo "$tags" | tr ',' '\n' | \
347 + while IFS= read -r t; do [[ -n "$t" ]] && printf '"%s",' "$t"; done | sed 's/,$//')
348 + tags_json="[${tags_array}]"
349 + fi
350 + services+=("$(printf '{"name":"%s","ip":"%s","desc":"%s","tags":%s,"port_count":%s}' \
351 + "$name" "$ip" "$desc" "$tags_json" "$port_count")")
352 + done <<< "$data"
353 +
354 + local count=${#services[@]}
355 + local array
356 + array=$(printf '%s\n' "${services[@]:-}" | paste -sd ',' -)
357 + printf '{"services":[%s]}' "${array:-}" | json::envelope "net list" "$count"
358 + }
Più nuovi Più vecchi