Ostatnio aktywny 1 month ago

gistfile1.txt Surowy
1#!/usr/bin/env bash
2
3function 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
13function cmd::net::help() {
14 cat <<EOF
15Usage: wgctl net <subcommand> [options]
16
17Manage named network services for use with block/allow rules.
18Services map names to IPs and ports, making rules more readable.
19
20Subcommands:
21 list List all services
22 show --name <name> Show service details
23 add --name <name> --ip <ip> Add a service
24 add --name <svc:port-name> --port <port:proto>
25 Add a port to a service
26 rm --name <name> Remove service or port
27 rm --name <svc:ports> Remove all ports from service
28
29Options for add (service):
30 --name <name> Service name (e.g. proxmox)
31 --ip <ip> Service IP address
32 --desc <description> Optional description
33 --tag <tag> Optional tag (repeatable)
34
35Options for add (port):
36 --name <svc:port-name> Service:port-name (e.g. proxmox:web-ui)
37 --port <port:proto> Port and protocol (e.g. 8006:tcp)
38 --desc <description> Optional description
39
40Options for list:
41 --detailed Show ports for each service
42 --tag <tag> Filter by tag
43
44Examples:
45 wgctl net list
46 wgctl net list --detailed
47 wgctl net list --tag admin
48 wgctl net show --name proxmox
49 wgctl net add --name proxmox --ip 10.0.0.100 --desc "Proxmox VE"
50 wgctl net add --name proxmox:web-ui --port 8006:tcp --desc "Web UI"
51 wgctl net add --name proxmox:ssh --port 22:tcp
52 wgctl net rm --name proxmox:web-ui
53 wgctl net rm --name proxmox:ports
54 wgctl net rm --name proxmox
55EOF
56}
57
58function cmd::net::run() {
59 local subcmd="${1:-list}"
60 shift || true
61 case "$subcmd" in
62 list) cmd::net::list "$@" ;;
63 show) cmd::net::show "$@" ;;
64 add) cmd::net::add "$@" ;;
65 rm|remove|del) cmd::net::rm "$@" ;;
66 help) cmd::net::help ;;
67 *)
68 log::error "Unknown subcommand: '${subcmd}'"
69 cmd::net::help
70 return 1 ;;
71 esac
72}
73
74# ============================================
75# List
76# ============================================
77
78function cmd::net::list() {
79 local detailed=false filter_tag=""
80
81 while [[ $# -gt 0 ]]; do
82 case "$1" in
83 --detailed) detailed=true; shift ;;
84 --tag) filter_tag="$2"; shift 2 ;;
85 --help) cmd::net::help; return ;;
86 *) log::error "Unknown flag: $1"; return 1 ;;
87 esac
88 done
89
90 local net_file
91 net_file="$(ctx::net)"
92
93 if [[ ! -f "$net_file" ]]; then
94 log::wg_warning "No services configured. Use 'wgctl net add' to add one."
95 return 0
96 fi
97
98 log::section "Network Services"
99 printf "\n %-20s %-16s %-6s %s\n" "NAME" "IP" "PORTS" "DESCRIPTION"
100 local divider
101 divider=$(printf '─%.0s' {1..72})
102 printf " %s\n" "$divider"
103
104 local found=false
105 while IFS="|" read -r name ip desc tags ports; do
106 [[ -z "$name" ]] && continue
107
108 # Tag filter
109 if [[ -n "$filter_tag" ]]; then
110 [[ "$tags" != *"$filter_tag"* ]] && continue
111 fi
112
113 found=true
114 local tag_display=""
115 [[ -n "$tags" ]] && tag_display=" \033[0;37m[${tags}]\033[0m"
116
117 printf " %-20s %-16s %-6s %s%b\n" \
118 "$name" "$ip" "${ports}p" "${desc:-—}" "$tag_display"
119
120 if $detailed; then
121 local has_ports=false
122 # Show ports inline
123 while IFS="|" read -r ptype pname pport pproto pdesc; do
124 [[ "$ptype" != "port" ]] && continue
125 has_ports=true
126 local ann
127 ann=$(net::annotation "$ip" "$pport" "$pproto")
128 printf " \033[0;37m%-18s %s:%s%s\033[0m\n" \
129 "${pname}" "$pport" "$pproto" \
130 "${pdesc:+ # $pdesc}"
131 done < <(json::net_show "$net_file" "$name")
132 $has_ports && printf "\n" # newline after each service with ports
133 fi
134
135 done < <(json::net_list "$net_file")
136
137 if ! $found; then
138 [[ -n "$filter_tag" ]] && \
139 log::wg_warning "No services with tag: ${filter_tag}" || \
140 log::wg_warning "No services configured"
141 fi
142
143 printf "\n"
144 return 0
145}
146
147# ============================================
148# Show
149# ============================================
150
151function cmd::net::show() {
152 local name=""
153 while [[ $# -gt 0 ]]; do
154 case "$1" in
155 --name) util::require_flag "--name" "${2:-}" || return 1
156 name="$2"; shift 2 ;;
157 --help) cmd::net::help; return ;;
158 *) log::error "Unknown flag: $1"; return 1 ;;
159 esac
160 done
161
162 [[ -z "$name" ]] && log::error "Missing required flag: --name" && return 1
163 net::require_exists "$name" || return 1
164
165 log::section "Service: ${name}"
166 printf "\n"
167
168 while IFS="|" read -r key val1 val2 val3 val4; do
169 case "$key" in
170 name) ui::row "Name" "$val1" ;;
171 ip) ui::row "IP" "$val1" ;;
172 desc) ui::row "Description" "${val1:-—}" ;;
173 tags) ui::row "Tags" "${val1:-—}" ;;
174 port)
175 # val1=port_name val2=port val3=proto val4=desc
176 local ann
177 ann=$(net::annotation "$(json::net_resolve "$(ctx::net)" "$name")" \
178 "$val2" "$val3" 2>/dev/null || true)
179 printf " %-20s \033[0;36m%s\033[0m %s:%s%s\n" \
180 "${val1}:" "" "$val2" "$val3" \
181 "${val4:+ # $val4}"
182 ;;
183 esac
184 done < <(json::net_show "$(ctx::net)" "$name")
185
186 printf "\n"
187 return 0
188}
189
190# ============================================
191# Add
192# ============================================
193
194function cmd::net::add() {
195 local name="" ip="" port="" desc="" tags=()
196
197 while [[ $# -gt 0 ]]; do
198 case "$1" in
199 --name) util::require_flag "--name" "${2:-}" || return 1
200 name="$2"; shift 2 ;;
201 --ip) ip="$2"; shift 2 ;;
202 --port) port="$2"; shift 2 ;;
203 --desc) desc="$2"; shift 2 ;;
204 --tag) tags+=("$2"); shift 2 ;;
205 --help) cmd::net::help; return ;;
206 *) log::error "Unknown flag: $1"; return 1 ;;
207 esac
208 done
209
210 [[ -z "$name" ]] && log::error "Missing required flag: --name" && return 1
211
212 if [[ "$name" == *:* ]]; then
213 # Port mode: proxmox:web-ui
214 local svc_name="${name%%:*}"
215 local port_name="${name##*:}"
216
217 [[ -z "$port" ]] && log::error "Missing required flag: --port" && return 1
218 net::require_exists "$svc_name" || return 1
219
220 local port_num proto
221 if [[ "$port" == *:* ]]; then
222 port_num="${port%%:*}"
223 proto="${port##*:}"
224 else
225 port_num="$port"
226 proto="tcp"
227 fi
228
229 json::net_add_port "$(ctx::net)" "$svc_name" "$port_name" \
230 "$port_num" "$proto" "$desc"
231
232 log::wg_success "Added port: ${svc_name}:${port_name} → ${port_num}/${proto}"
233 else
234 # Service mode: proxmox
235 [[ -z "$ip" ]] && log::error "Missing required flag: --ip" && return 1
236
237 local tags_str
238 tags_str=$(IFS=','; echo "${tags[*]}")
239
240 json::net_add_service "$(ctx::net)" "$name" "$ip" "$desc" "$tags_str"
241
242 log::wg_success "Service added: ${name} → ${ip}"
243 fi
244 return 0
245}
246
247# ============================================
248# Remove
249# ============================================
250
251function cmd::net::rm() {
252 local name="" force=false
253
254 while [[ $# -gt 0 ]]; do
255 case "$1" in
256 --name) util::require_flag "--name" "${2:-}" || return 1
257 name="$2"; shift 2 ;;
258 --force) force=true; shift ;;
259 --help) cmd::net::help; return ;;
260 *) log::error "Unknown flag: $1"; return 1 ;;
261 esac
262 done
263
264 [[ -z "$name" ]] && log::error "Missing required flag: --name" && return 1
265
266 # Validate existence
267 if [[ "$name" == *:* ]]; then
268 local svc_name="${name%%:*}"
269 local port_name="${name##*:}"
270 if [[ "$port_name" != "ports" ]]; then
271 # Check specific port exists
272 local exists
273 exists=$(json::net_exists "$(ctx::net)" "$name")
274 if [[ "$exists" != "true" ]]; then
275 log::error "Port not found: ${name}"
276 return 1
277 fi
278 else
279 net::require_exists "$svc_name" || return 1
280 fi
281 else
282 net::require_exists "$name" || return 1
283 fi
284
285 if ! $force; then
286 local what="service '${name}'"
287 [[ "$name" == *:ports ]] && what="all ports from '${name%%:*}'"
288 [[ "$name" == *:* && "$name" != *:ports ]] && what="port '${name}'"
289 read -r -p "Remove ${what}? [y/N] " confirm
290 case "$confirm" in
291 [yY]*) ;;
292 *) log::info "Aborted"; return 0 ;;
293 esac
294 fi
295
296 json::net_remove "$(ctx::net)" "$name"
297 log::wg_success "Removed: ${name}"
298 return 0
299}