Ostatnio aktywny 1 month ago

nuno zrewidował ten Gist 1 month ago. Przejdź do rewizji

1 file changed, 266 insertions

gistfile1.txt(stworzono plik)

@@ -0,0 +1,266 @@
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 + function config::_init_defaults() {
28 + _WG_INTERFACE="${WG_INTERFACE:-wg0}"
29 + _WG_DNS="${WG_DNS:-10.0.0.103}"
30 + _WG_LAN="${WG_LAN:-10.0.0.0/24}"
31 + _WG_SUBNET="${WG_SUBNET:-10.1.0.0/16}"
32 + _WG_PORT="${WG_PORT:-51820}"
33 + _WG_ENDPOINT="${WG_ENDPOINT:-}"
34 + _WG_HANDSHAKE_CHECK_TIME_SEC="${WG_HANDSHAKE_CHECK_TIME_SEC:-180}"
35 +
36 + # Derived
37 + _WG_CONFIG="$(ctx::wg)/${_WG_INTERFACE}.conf"
38 + _WG_SERVER_PUBLIC_KEY_FILE="$(ctx::wg)/server_public.key"
39 + _WG_SERVER_PRIVATE_KEY_FILE="$(ctx::wg)/server_private.key"
40 + _WG_TUNNEL_SPLIT="${_WG_SUBNET}, ${_WG_LAN}"
41 + _WG_TUNNEL_FULL="0.0.0.0/0, ::/0"
42 + }
43 +
44 + # ============================================
45 + # Validation
46 + # ============================================
47 +
48 + function config::validate() {
49 + local errors=()
50 +
51 + # Required fields
52 + local endpoint
53 + endpoint=$(config::endpoint)
54 + if [[ -z "$endpoint" ]]; then
55 + errors+=("WG_ENDPOINT is not set — required for client config generation")
56 + elif [[ "$endpoint" != *:* ]]; then
57 + errors+=("WG_ENDPOINT must include port (e.g. wg.example.com:51820)")
58 + fi
59 +
60 + local port
61 + port=$(config::port)
62 + if [[ -z "$port" ]]; then
63 + errors+=("WG_LISTEN_PORT is not set")
64 + elif ! [[ "$port" =~ ^[0-9]+$ ]] || (( port < 1 || port > 65535 )); then
65 + errors+=("WG_LISTEN_PORT must be a valid port number (1-65535)")
66 + fi
67 +
68 + local dns
69 + dns=$(config::dns)
70 + if [[ -z "$dns" ]]; then
71 + errors+=("WG_DNS is not set — required for client configs")
72 + elif ! ip::is_valid "$dns"; then
73 + errors+=("WG_DNS must be a valid IP address")
74 + fi
75 +
76 + local subnet
77 + subnet=$(config::subnet)
78 + if [[ -z "$subnet" ]]; then
79 + errors+=("WG_SUBNET is not set — required for IP allocation")
80 + fi
81 +
82 + local interface
83 + interface=$(config::interface)
84 + if [[ -z "$interface" ]]; then
85 + errors+=("WG_INTERFACE is not set, defaulting to wg0")
86 + fi
87 +
88 + # Warn-only fields
89 + local lan
90 + lan=$(config::lan)
91 + if [[ -z "$lan" ]]; then
92 + log::wg_warning "WG_LAN is not set — some rule features may not work correctly"
93 + fi
94 +
95 + if [[ ${#errors[@]} -gt 0 ]]; then
96 + log::error "wgctl configuration errors:"
97 + for err in "${errors[@]}"; do
98 + printf " ✗ %s\n" "$err" >&2
99 + done
100 + printf "\n Edit /etc/wireguard/.wgctl/wgctl.conf to fix these issues.\n\n" >&2
101 + return 1
102 + fi
103 +
104 + return 0
105 + }
106 +
107 + # ============================================
108 + # Load overrides from .wgctl/wgctl.conf
109 + # ============================================
110 +
111 + function config::load() {
112 + local conf_file
113 + conf_file="$(ctx::data)/wgctl.conf"
114 + [[ ! -f "$conf_file" ]] && return 0
115 + while IFS='=' read -r key value || [[ -n "$key" ]]; do
116 + [[ "$key" =~ ^[[:space:]]*# ]] && continue
117 + [[ -z "${key// }" ]] && continue
118 + key="${key// /}"
119 + value="${value// /}"
120 + case "$key" in
121 + WG_INTERFACE) _WG_INTERFACE="$value" ;;
122 + WG_ENDPOINT) _WG_ENDPOINT="$value" ;;
123 + WG_DNS) _WG_DNS="$value" ;;
124 + WG_PORT) _WG_PORT="$value" ;;
125 + WG_SUBNET) _WG_SUBNET="$value" ;;
126 + WG_LAN) _WG_LAN="$value" ;;
127 + WG_HANDSHAKE_CHECK_TIME_SEC) _WG_HANDSHAKE_CHECK_TIME_SEC="$value" ;;
128 + ACTIVITY_LOW_BYTES) _ACTIVITY_LOW_BYTES="$value" ;;
129 + ACTIVITY_MED_BYTES) _ACTIVITY_MED_BYTES="$value" ;;
130 + ACTIVITY_HIGH_BYTES) _ACTIVITY_HIGH_BYTES="$value" ;;
131 + DATE_FORMAT)
132 + _FMT_DATE_FORMAT="$value"
133 + fmt::set_date_format "$value"
134 + ;;
135 + esac
136 + done < "$conf_file"
137 +
138 + # Recompute derived values after overrides
139 + _WG_CONFIG="$(ctx::wg)/${_WG_INTERFACE}.conf"
140 + _WG_TUNNEL_SPLIT="${_WG_SUBNET}, ${_WG_LAN}"
141 + }
142 +
143 + # ============================================
144 + # Device Type → Subnet Mapping
145 + # ============================================
146 +
147 + declare -gA DEVICE_SUBNETS=(
148 + [desktop]="10.1.1"
149 + [laptop]="10.1.2"
150 + [phone]="10.1.3"
151 + [tablet]="10.1.4"
152 + [guest]="10.1.100"
153 + [guest-desktop]="10.1.101"
154 + [guest-laptop]="10.1.102"
155 + [guest-phone]="10.1.103"
156 + [guest-tablet]="10.1.104"
157 + )
158 +
159 + # ============================================
160 + # Tunnel Modes
161 + # ============================================
162 +
163 + declare -gA DEVICE_TUNNEL_MODE=(
164 + [desktop]="split"
165 + [laptop]="split"
166 + [phone]="split"
167 + [tablet]="split"
168 + [guest]="split"
169 + [guest-desktop]="split"
170 + [guest-laptop]="split"
171 + [guest-phone]="split"
172 + [guest-tablet]="split"
173 + )
174 +
175 + # ============================================
176 + # Accessors
177 + # ============================================
178 +
179 + function config::interface() { echo "$_WG_INTERFACE"; }
180 + function config::config_file() { echo "$_WG_CONFIG"; }
181 + function config::endpoint() { echo "$_WG_ENDPOINT"; }
182 + function config::dns() { echo "$_WG_DNS"; }
183 + function config::port() { echo "$_WG_PORT"; }
184 + function config::subnet() { echo "$_WG_SUBNET"; }
185 + function config::lan() { echo "$_WG_LAN"; }
186 + function config::tunnel_split() { echo "$_WG_TUNNEL_SPLIT"; }
187 + function config::tunnel_full() { echo "$_WG_TUNNEL_FULL"; }
188 + function config::handshake_time_sec() { echo "$_WG_HANDSHAKE_CHECK_TIME_SEC"; }
189 + function config::activity_total_low() { echo "$_ACTIVITY_TOTAL_LOW_BYTES"; }
190 + function config::activity_total_med() { echo "$_ACTIVITY_TOTAL_MED_BYTES"; }
191 + function config::activity_total_high() { echo "$_ACTIVITY_TOTAL_HIGH_BYTES"; }
192 + function config::activity_current_low() { echo "$_ACTIVITY_TOTAL_LOW_BYTES"; }
193 + function config::activity_current_med() { echo "$_ACTIVITY_TOTAL_MED_BYTES"; }
194 + function config::activity_current_high() { echo "$_ACTIVITY_TOTAL_HIGH_BYTES"; }
195 + function config::server_public_key() { cat "$_WG_SERVER_PUBLIC_KEY_FILE"; }
196 +
197 + function config::device_types() {
198 + local types
199 + { set +u; types="${!DEVICE_SUBNETS[@]}"; set -u; }
200 + echo "$types"
201 + }
202 +
203 + function config::is_valid_type() {
204 + local type="$1"
205 + local subnet
206 + subnet=$(config::subnet_for "$type")
207 + [[ -n "$subnet" ]]
208 + }
209 +
210 + function config::is_guest_type() {
211 + local type="$1"
212 + [[ "$type" == "guest" || "$type" == guest-* ]]
213 + }
214 +
215 + function config::subnet_for() {
216 + local type="$1"
217 + local result
218 + { set +u; result="${DEVICE_SUBNETS[$type]:-}"; set -u; }
219 + echo "$result"
220 + }
221 +
222 + function config::default_tunnel_for() {
223 + local type="$1"
224 + local result
225 + { set +u; result="${DEVICE_TUNNEL_MODE[$type]:-split}"; set -u; }
226 + echo "$result"
227 + }
228 +
229 + function config::allowed_ips_for() {
230 + local type="$1"
231 + local tunnel="${2:-}"
232 +
233 + if [[ -z "$tunnel" ]]; then
234 + tunnel=$(config::default_tunnel_for "$type")
235 + fi
236 +
237 + case "$tunnel" in
238 + full) echo "$_WG_TUNNEL_FULL" ;;
239 + split) echo "$_WG_TUNNEL_SPLIT" ;;
240 + *)
241 + log::error "Unknown tunnel mode: ${tunnel} (use 'split' or 'full')"
242 + return 1
243 + ;;
244 + esac
245 + }
246 +
247 + # ============================================
248 + # Validation
249 + # ============================================
250 +
251 + function config::validate() {
252 + if [[ ! -f "$_WG_SERVER_PUBLIC_KEY_FILE" ]]; then
253 + log::error "Server public key not found: ${_WG_SERVER_PUBLIC_KEY_FILE}"
254 + exit 1
255 + fi
256 +
257 + if [[ ! -f "$_WG_SERVER_PRIVATE_KEY_FILE" ]]; then
258 + log::error "Server private key not found: ${_WG_SERVER_PRIVATE_KEY_FILE}"
259 + exit 1
260 + fi
261 +
262 + if [[ ! -f "$_WG_CONFIG" ]]; then
263 + log::error "WireGuard config not found: ${_WG_CONFIG}"
264 + exit 1
265 + fi
266 + }
Nowsze Starsze