最后活跃于 1 month ago

nuno 修订了这个 Gist 1 month ago. 转到此修订

1 file changed, 299 insertions

gistfile1.txt(文件已创建)

@@ -0,0 +1,299 @@
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 +
13 + function cmd::net::help() {
14 + cat <<EOF
15 + Usage: wgctl net <subcommand> [options]
16 +
17 + Manage named network services for use with block/allow rules.
18 + Services map names to IPs and ports, making rules more readable.
19 +
20 + Subcommands:
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 +
29 + Options 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 +
35 + Options 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 +
40 + Options for list:
41 + --detailed Show ports for each service
42 + --tag <tag> Filter by tag
43 +
44 + Examples:
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
55 + EOF
56 + }
57 +
58 + function 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 +
78 + function 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 +
151 + function 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 +
194 + function 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 +
251 + function 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 + }
上一页 下一页