最后活跃于 1 month ago

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

1 file changed, 195 insertions

config.module.sh(文件已创建)

@@ -0,0 +1,195 @@
1 + #!/usr/bin/env bash
2 +
3 + # ============================================
4 + # Lifecycle
5 + # ============================================
6 +
7 + function config::on_load() {
8 + config::_init_defaults
9 + config::load
10 + config::validate
11 + fmt::set_date_format "${_FMT_DATE_FORMAT:-iso}"
12 + }
13 +
14 + # ============================================
15 + # Defaults
16 + # ============================================
17 +
18 + # Activity thresholds
19 + declare -g _ACTIVITY_TOTAL_LOW_BYTES="${ACTIVITY_TOTAL_LOW_BYTES:-1000000}"
20 + declare -g _ACTIVITY_TOTAL_MED_BYTES="${ACTIVITY_TOTAL_MED_BYTES:-10000000}"
21 + declare -g _ACTIVITY_TOTAL_HIGH_BYTES="${ACTIVITY_TOTAL_HIGH_BYTES:-100000000}"
22 +
23 + declare -g _ACTIVITY_CURRENT_LOW_BYTES="${ACTIVITY_CURRENT_LOW_BYTES:-1000000}"
24 + declare -g _ACTIVITY_CURRENT_MED_BYTES="${ACTIVITY_CURRENT_MED_BYTES:-10000000}"
25 + declare -g _ACTIVITY_CURRENT_HIGH_BYTES="${ACTIVITY_CURRENT_HIGH_BYTES:-100000000}"
26 +
27 +
28 + function config::_init_defaults() {
29 + _WG_INTERFACE="${WG_INTERFACE:-wg0}"
30 + _WG_DNS="${WG_DNS:-10.0.0.103}"
31 + _WG_DNS_FALLBACK="${WG_DNS_FALLBACK:-}"
32 + _WG_LAN="${WG_LAN:-10.0.0.0/24}"
33 + _WG_SUBNET="${WG_SUBNET:-10.1.0.0/16}"
34 + _WG_PORT="${WG_PORT:-51820}"
35 + _WG_ENDPOINT="${WG_ENDPOINT:-}"
36 + _WG_HANDSHAKE_CHECK_TIME_SEC="${WG_HANDSHAKE_CHECK_TIME_SEC:-180}"
37 +
38 + # Derived
39 + _WG_CONFIG="$(ctx::wg)/${_WG_INTERFACE}.conf"
40 + _WG_SERVER_PUBLIC_KEY_FILE="$(ctx::wg)/server_public.key"
41 + _WG_SERVER_PRIVATE_KEY_FILE="$(ctx::wg)/server_private.key"
42 + _WG_TUNNEL_SPLIT="${_WG_SUBNET}, ${_WG_LAN}"
43 + _WG_TUNNEL_FULL="0.0.0.0/0, ::/0"
44 + }
45 +
46 + # ============================================
47 + # Validation
48 + # ============================================
49 +
50 + function config::validate() {
51 + local errors=()
52 +
53 + # Server key and config files
54 + if [[ ! -f "$_WG_SERVER_PUBLIC_KEY_FILE" ]]; then
55 + errors+=("Server public key not found: ${_WG_SERVER_PUBLIC_KEY_FILE}")
56 + fi
57 + if [[ ! -f "$_WG_SERVER_PRIVATE_KEY_FILE" ]]; then
58 + errors+=("Server private key not found: ${_WG_SERVER_PRIVATE_KEY_FILE}")
59 + fi
60 + if [[ ! -f "$_WG_CONFIG" ]]; then
61 + errors+=("WireGuard config not found: ${_WG_CONFIG}")
62 + fi
63 +
64 + # Required config values
65 + local endpoint
66 + endpoint=$(config::endpoint)
67 + if [[ -z "$endpoint" ]]; then
68 + errors+=("WG_ENDPOINT is not set — required for client config generation")
69 + elif [[ "$endpoint" != *:* ]]; then
70 + errors+=("WG_ENDPOINT must include port (e.g. wg.example.com:51820)")
71 + fi
72 +
73 + local port
74 + port=$(config::port)
75 + if [[ -z "$port" ]]; then
76 + errors+=("WG_PORT is not set")
77 + elif ! [[ "$port" =~ ^[0-9]+$ ]] || (( port < 1 || port > 65535 )); then
78 + errors+=("WG_PORT must be a valid port number (1-65535)")
79 + fi
80 +
81 + local dns
82 + dns=$(config::dns)
83 + if [[ -z "$dns" ]]; then
84 + errors+=("WG_DNS is not set — required for client configs")
85 + elif ! ip::is_valid "$dns"; then
86 + errors+=("WG_DNS must be a valid IP address")
87 + fi
88 +
89 + local subnet
90 + subnet=$(config::subnet)
91 + if [[ -z "$subnet" ]]; then
92 + errors+=("WG_SUBNET is not set — required for IP allocation")
93 + fi
94 +
95 + # Warn-only
96 + local lan
97 + lan=$(config::lan)
98 + if [[ -z "$lan" ]]; then
99 + log::wg_warning "WG_LAN is not set — some rule features may not work correctly"
100 + fi
101 +
102 + if [[ ${#errors[@]} -gt 0 ]]; then
103 + log::error "wgctl configuration errors:"
104 + for err in "${errors[@]}"; do
105 + printf " ✗ %s\n" "$err" >&2
106 + done
107 + printf "\n Edit /etc/wireguard/.wgctl/wgctl.conf to fix these issues.\n\n" >&2
108 + return 1
109 + fi
110 +
111 + return 0
112 + }
113 +
114 + # ============================================
115 + # Load overrides from .wgctl/wgctl.conf
116 + # ============================================
117 +
118 + function config::load() {
119 + local conf_file
120 + conf_file="$(ctx::data)/wgctl.conf"
121 + [[ ! -f "$conf_file" ]] && return 0
122 + while IFS='=' read -r key value || [[ -n "$key" ]]; do
123 + [[ "$key" =~ ^[[:space:]]*# ]] && continue
124 + [[ -z "${key// }" ]] && continue
125 + key="${key// /}"
126 + value="${value// /}"
127 + case "$key" in
128 + WG_INTERFACE) _WG_INTERFACE="$value" ;;
129 + WG_ENDPOINT) _WG_ENDPOINT="$value" ;;
130 + WG_DNS) _WG_DNS="$value" ;;
131 + WG_DNS_FALLBACK) _WG_DNS_FALLBACK="$value" ;;
132 + WG_PORT) _WG_PORT="$value" ;;
133 + WG_SUBNET) _WG_SUBNET="$value" ;;
134 + WG_LAN) _WG_LAN="$value" ;;
135 + WG_HANDSHAKE_CHECK_TIME_SEC) _WG_HANDSHAKE_CHECK_TIME_SEC="$value" ;;
136 + ACTIVITY_LOW_BYTES) _ACTIVITY_LOW_BYTES="$value" ;;
137 + ACTIVITY_MED_BYTES) _ACTIVITY_MED_BYTES="$value" ;;
138 + ACTIVITY_HIGH_BYTES) _ACTIVITY_HIGH_BYTES="$value" ;;
139 + DATE_FORMAT)
140 + _FMT_DATE_FORMAT="$value"
141 + fmt::set_date_format "$value"
142 + ;;
143 + esac
144 + done < "$conf_file"
145 +
146 + # Recompute derived values after overrides
147 + _WG_CONFIG="$(ctx::wg)/${_WG_INTERFACE}.conf"
148 + _WG_TUNNEL_SPLIT="${_WG_SUBNET}, ${_WG_LAN}"
149 + }
150 +
151 + # ============================================
152 + # Accessors
153 + # ============================================
154 +
155 + function config::interface() { echo "$_WG_INTERFACE"; }
156 + function config::config_file() { echo "$_WG_CONFIG"; }
157 + function config::endpoint() { echo "$_WG_ENDPOINT"; }
158 + function config::dns() { echo "$_WG_DNS"; }
159 + function config::dns_fallback() { echo "${_WG_DNS_FALLBACK:-}"; }
160 + function config::port() { echo "$_WG_PORT"; }
161 + function config::subnet() { echo "$_WG_SUBNET"; }
162 + function config::lan() { echo "$_WG_LAN"; }
163 + function config::tunnel_split() { echo "$_WG_TUNNEL_SPLIT"; }
164 + function config::tunnel_full() { echo "$_WG_TUNNEL_FULL"; }
165 + function config::handshake_time_sec() { echo "$_WG_HANDSHAKE_CHECK_TIME_SEC"; }
166 + function config::activity_total_low() { echo "$_ACTIVITY_TOTAL_LOW_BYTES"; }
167 + function config::activity_total_med() { echo "$_ACTIVITY_TOTAL_MED_BYTES"; }
168 + function config::activity_total_high() { echo "$_ACTIVITY_TOTAL_HIGH_BYTES"; }
169 + function config::activity_current_low() { echo "$_ACTIVITY_TOTAL_LOW_BYTES"; }
170 + function config::activity_current_med() { echo "$_ACTIVITY_TOTAL_MED_BYTES"; }
171 + function config::activity_current_high() { echo "$_ACTIVITY_TOTAL_HIGH_BYTES"; }
172 + function config::server_public_key() { cat "$_WG_SERVER_PUBLIC_KEY_FILE"; }
173 +
174 + function config::allowed_ips_for() {
175 + local tunnel="${1:-split}"
176 + case "$tunnel" in
177 + full) echo "$_WG_TUNNEL_FULL" ;;
178 + split) echo "$_WG_TUNNEL_SPLIT" ;;
179 + *)
180 + log::error "Unknown tunnel mode: ${tunnel} (use 'split' or 'full')"
181 + return 1
182 + ;;
183 + esac
184 + }
185 +
186 + function config::dns_string() {
187 + local fallback
188 + fallback=$(config::dns_fallback)
189 + if [[ -n "$fallback" ]]; then
190 + echo "$(config::dns), ${fallback}"
191 + else
192 + echo "$(config::dns)"
193 + fi
194 + }
195 +
上一页 下一页