Ostatnio aktywny 2 months ago

nuno zrewidował ten Gist 2 months ago. Przejdź do rewizji

Brak zmian

nuno zrewidował ten Gist 2 months ago. Przejdź do rewizji

1 file changed, 207 insertions

gistfile1.txt(stworzono plik)

@@ -0,0 +1,207 @@
1 + #!/usr/bin/env bash
2 +
3 + # ============================================
4 + # Config
5 + # ============================================
6 +
7 + MONITOR_DIR="$(ctx::root)/daemon"
8 + WATCHLIST_FILE="${MONITOR_DIR}/watchlist.json"
9 + EVENTS_LOG="${MONITOR_DIR}/events.log"
10 + MONITOR_SERVICE="wgctl-monitor"
11 +
12 + # ============================================
13 + # Lifecycle
14 + # ============================================
15 +
16 + function monitor::on_load() {
17 + if [[ ! -f "$WATCHLIST_FILE" ]]; then
18 + echo '{}' > "$WATCHLIST_FILE"
19 + fi
20 + if [[ ! -f "$EVENTS_LOG" ]]; then
21 + touch "$EVENTS_LOG"
22 + fi
23 + }
24 +
25 + # ============================================
26 + # Watchlist
27 + # ============================================
28 +
29 + function monitor::watch() {
30 + local ip="$1" client="$2"
31 + json::set "$WATCHLIST_FILE" "$ip" "$client"
32 + log::wg "Watching: ${client} (${ip})"
33 + }
34 +
35 + function monitor::unwatch() {
36 + local ip="$1"
37 + json::delete "$WATCHLIST_FILE" "$ip"
38 + }
39 +
40 + function monitor::is_watched() {
41 + local ip="$1"
42 + python3 -c "
43 + import json
44 + with open('${WATCHLIST_FILE}') as f:
45 + wl = json.load(f)
46 + exit(0 if '${ip}' in wl else 1)
47 + "
48 + }
49 +
50 + function monitor::unwatch_client() {
51 + local name="$1"
52 + python3 -c "
53 + import json
54 + with open('${WATCHLIST_FILE}') as f:
55 + wl = json.load(f)
56 + wl = {k: v for k, v in wl.items() if v != '${name}'}
57 + with open('${WATCHLIST_FILE}', 'w') as f:
58 + json.dump(wl, f, indent=2)
59 + "
60 + log::wg "Unwatched client: ${name}"
61 + }
62 +
63 + # ============================================
64 + # Events
65 + # ============================================
66 +
67 + function monitor::last_attempt() {
68 + local client="$1"
69 + python3 -c "
70 + import json
71 +
72 + events = []
73 + try:
74 + with open('${EVENTS_LOG}') as f:
75 + for line in f:
76 + try:
77 + e = json.loads(line.strip())
78 + if e.get('client') == '${client}':
79 + events.append(e)
80 + except:
81 + pass
82 + except:
83 + pass
84 +
85 + if events:
86 + print(events[-1].get('timestamp', ''))
87 + "
88 + }
89 +
90 + function monitor::last_endpoint() {
91 + local client="$1"
92 + python3 -c "
93 + import json
94 +
95 + events = []
96 + try:
97 + with open('${EVENTS_LOG}') as f:
98 + for line in f:
99 + try:
100 + e = json.loads(line.strip())
101 + if e.get('client') == '${client}' and e.get('endpoint'):
102 + events.append(e)
103 + except:
104 + pass
105 + except:
106 + pass
107 +
108 + if events:
109 + print(events[-1].get('endpoint', ''))
110 + "
111 + }
112 +
113 + function monitor::events_for() {
114 + local ip="$1"
115 + local limit="${2:-50}"
116 + python3 -c "
117 + import json
118 + from datetime import datetime, timezone
119 +
120 + events = []
121 + try:
122 + with open('${EVENTS_LOG}') as f:
123 + for line in f:
124 + try:
125 + e = json.loads(line.strip())
126 + if e.get('ip') == '${ip}':
127 + events.append(e)
128 + except:
129 + pass
130 + except:
131 + pass
132 +
133 + for e in events[-${limit}:]:
134 + ts = e.get('timestamp', '')
135 + try:
136 + dt = datetime.fromisoformat(ts)
137 + ts = dt.strftime('%Y-%m-%d %H:%M:%S')
138 + except:
139 + pass
140 + endpoint = e.get('endpoint', '—')
141 + client = e.get('client', '—')
142 + event = e.get('event', '—')
143 + print(f' {ts} {client:<20} {endpoint:<20} {event}')
144 + "
145 + }
146 +
147 + # ============================================
148 + # Endpoint Cache (for blocked clients)
149 + # ============================================
150 +
151 + ENDPOINT_CACHE="${WGCTL_DIR}/daemon/endpoint_cache.json"
152 +
153 + function monitor::cache_endpoint() {
154 + local client="$1" ip="$2"
155 + json::set "$ENDPOINT_CACHE" "$client" "$ip"
156 + }
157 +
158 + function monitor::get_cached_endpoint() {
159 + local client="$1"
160 + json::get "$ENDPOINT_CACHE" "$client"
161 + }
162 +
163 + function monitor::update_endpoint_cache() {
164 + while IFS=$'\t' read -r key endpoint; do
165 + [[ "$endpoint" == "(none)" ]] && continue
166 + local ip
167 + ip=$(echo "$endpoint" | cut -d':' -f1)
168 + local client
169 + client=$(keys::find_by_public "$key") || continue
170 + monitor::cache_endpoint "$client" "$ip"
171 + done < <(wg show "$(config::interface)" endpoints 2>/dev/null)
172 + }
173 +
174 + # ============================================
175 + # Endpoint (from wg show, for active clients)
176 + # ============================================
177 +
178 + function monitor::endpoint_for_key() {
179 + local public_key="$1"
180 + wg show "$(config::interface)" endpoints 2>/dev/null \
181 + | grep "^${public_key}" \
182 + | awk '{print $2}' \
183 + | cut -d':' -f1
184 + }
185 +
186 + # ============================================
187 + # Service
188 + # ============================================
189 +
190 + function monitor::start() {
191 + systemctl start "$MONITOR_SERVICE"
192 + log::wg_start "Monitor daemon started"
193 + }
194 +
195 + function monitor::stop() {
196 + systemctl stop "$MONITOR_SERVICE"
197 + log::wg_stop "Monitor daemon stopped"
198 + }
199 +
200 + function monitor::restart() {
201 + systemctl restart "$MONITOR_SERVICE"
202 + log::wg_start "Monitor daemon restarted"
203 + }
204 +
205 + function monitor::is_running() {
206 + systemctl is-active --quiet "$MONITOR_SERVICE"
207 + }
Nowsze Starsze