最后活跃于 1 month ago

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

1 file changed, 790 insertions

gistfile1.txt(文件已创建)

@@ -0,0 +1,790 @@
1 + #!/usr/bin/env python3
2 + """
3 + wgctl JSON helper — called by shell functions to read/write JSON files.
4 + Usage: json_helper.py <command> <file> [key] [value]
5 + """
6 +
7 + import sys
8 + import json
9 + import os
10 +
11 + DATETIME_FMT = os.environ.get('WGCTL_DATETIME_FMT', '%Y-%m-%d %H:%M')
12 +
13 + def get(file, key):
14 + try:
15 + with open(file) as f:
16 + data = json.load(f)
17 + val = data.get(key, [])
18 + if isinstance(val, bool):
19 + print(str(val).lower()) # true/false not True/False
20 + elif isinstance(val, list):
21 + if val:
22 + print('\n'.join(str(v) for v in val))
23 + else:
24 + if val:
25 + print(val)
26 + except:
27 + sys.exit(0)
28 +
29 + def set_key(file, key, value):
30 + try:
31 + data = {}
32 + if os.path.exists(file):
33 + with open(file) as f:
34 + data = json.load(f)
35 + # Try to parse as JSON value first (for arrays/bools)
36 + try:
37 + data[key] = json.loads(value)
38 + except:
39 + data[key] = value
40 + with open(file, 'w') as f:
41 + json.dump(data, f, indent=2)
42 + except Exception as e:
43 + print(f"Error: {e}", file=sys.stderr)
44 + sys.exit(1)
45 +
46 + def delete_key(file, key):
47 + try:
48 + with open(file) as f:
49 + data = json.load(f)
50 + data.pop(key, None)
51 + with open(file, 'w') as f:
52 + json.dump(data, f, indent=2)
53 + except Exception as e:
54 + print(f"Error: {e}", file=sys.stderr)
55 + sys.exit(1)
56 +
57 + def append(file, key, value):
58 + try:
59 + data = {}
60 + if os.path.exists(file):
61 + with open(file) as f:
62 + data = json.load(f)
63 + if key not in data:
64 + data[key] = []
65 + if value not in data[key]:
66 + data[key].append(value)
67 + with open(file, 'w') as f:
68 + json.dump(data, f, indent=2)
69 + except Exception as e:
70 + print(f"Error: {e}", file=sys.stderr)
71 + sys.exit(1)
72 +
73 + def remove_value(file, key, value):
74 + try:
75 + with open(file) as f:
76 + data = json.load(f)
77 + if key in data and value in data[key]:
78 + data[key].remove(value)
79 + with open(file, 'w') as f:
80 + json.dump(data, f, indent=2)
81 + except Exception as e:
82 + print(f"Error: {e}", file=sys.stderr)
83 + sys.exit(1)
84 +
85 + def cat(file):
86 + try:
87 + with open(file) as f:
88 + data = json.load(f)
89 + print(json.dumps(data, indent=2))
90 + except Exception as e:
91 + sys.exit(1)
92 +
93 + def has_key(file, key):
94 + try:
95 + with open(file) as f:
96 + data = json.load(f)
97 + sys.exit(0 if key in data else 1)
98 + except:
99 + sys.exit(1)
100 +
101 + def filter_values(file, key, value):
102 + """Remove all entries where value matches"""
103 + try:
104 + with open(file) as f:
105 + data = json.load(f)
106 + data = {k: v for k, v in data.items() if v != value}
107 + with open(file, 'w') as f:
108 + json.dump(data, f, indent=2)
109 + except Exception as e:
110 + print(f"Error: {e}", file=sys.stderr)
111 + sys.exit(1)
112 +
113 + def last_event(file, key, field, client):
114 + """Get last event field for a client"""
115 + try:
116 + last = None
117 + with open(file) as f:
118 + for line in f:
119 + try:
120 + e = json.loads(line.strip())
121 + if e.get(key) == client:
122 + last = e
123 + except:
124 + pass
125 + if last:
126 + print(last.get(field, ''))
127 + except:
128 + pass
129 +
130 + def events_for(file, ip, limit):
131 + """Format events for a given IP"""
132 + try:
133 + from datetime import datetime
134 + events = []
135 + with open(file) as f:
136 + for line in f:
137 + try:
138 + e = json.loads(line.strip())
139 + if e.get('ip') == ip:
140 + events.append(e)
141 + except:
142 + pass
143 + for e in events[-int(limit):]:
144 + ts = e.get('timestamp', '')
145 + try:
146 + dt = datetime.fromisoformat(ts)
147 + ts = dt.strftime(DATETIME_FMT)
148 + except:
149 + pass
150 + endpoint = e.get('endpoint', '—')
151 + client = e.get('client', '—')
152 + event = e.get('event', '—')
153 + print(f' {ts} {client:<20} {endpoint:<20} {event}')
154 + except:
155 + pass
156 +
157 + def fw_events(file, filter_ip, filter_type, clients_dir, limit):
158 + """Format firewall drop events"""
159 + import glob
160 +
161 + proto_map = {1: 'icmp', 6: 'tcp', 17: 'udp'}
162 +
163 + # Build ip->name map
164 + ip_to_name = {}
165 + for conf in glob.glob(f"{clients_dir}/*.conf"):
166 + name = os.path.basename(conf).replace('.conf', '')
167 + try:
168 + with open(conf) as f:
169 + for line in f:
170 + if line.startswith('Address'):
171 + ip = line.split('=')[1].strip().split('/')[0]
172 + ip_to_name[ip] = name
173 + except:
174 + pass
175 +
176 + events = []
177 + last_seen = {} # (src, dst, port, proto) -> last timestamp
178 +
179 + try:
180 + with open(file) as f:
181 + for line in f:
182 + try:
183 + e = json.loads(line.strip())
184 + src = e.get('src_ip', '')
185 + if not src:
186 + continue
187 + if filter_ip and src != filter_ip:
188 + continue
189 +
190 + # Dedup key
191 + dst = e.get('dest_ip', '')
192 + port = e.get('dest_port', '')
193 + proto = e.get('ip.protocol', 0)
194 + key = (src, dst, port, proto)
195 +
196 + ts_str = e.get('timestamp', '')
197 + try:
198 + from datetime import datetime
199 + ts = datetime.fromisoformat(ts_str).timestamp()
200 + except:
201 + ts = 0
202 +
203 + # Protocol-aware dedup window
204 + dedup_windows = {1: 5, 6: 30, 17: 10} # icmp=5s, tcp=30s, udp=10s
205 + window = dedup_windows.get(proto, 10)
206 +
207 + # Skip if same event within protocol window
208 + if key in last_seen and (ts - last_seen[key]) < window:
209 + continue
210 + last_seen[key] = ts
211 +
212 + events.append(e)
213 + except:
214 + pass
215 + except:
216 + pass
217 +
218 + for e in events[-int(limit):]:
219 + ts = e.get('timestamp', '')
220 + try:
221 + from datetime import datetime
222 + dt = datetime.fromisoformat(ts)
223 + ts = dt.strftime(DATETIME_FMT)
224 + except:
225 + pass
226 + src = e.get('src_ip', '—')
227 + dst = e.get('dest_ip', '—')
228 + port = e.get('dest_port', '')
229 + proto_num = e.get('ip.protocol', 0)
230 + proto = proto_map.get(proto_num, str(proto_num))
231 + dst_str = f"{dst}:{port}" if port else dst
232 + client = ip_to_name.get(src, src)
233 +
234 + if filter_type and not client.startswith(filter_type + '-'):
235 + continue
236 +
237 + print(f"{ts}|{client}|{dst_str}|{proto}")
238 +
239 + def wg_events(file, filter_client, filter_type, limit):
240 + """Format WireGuard events from events.log"""
241 + events = []
242 + try:
243 + with open(file) as f:
244 + for line in f:
245 + try:
246 + e = json.loads(line.strip())
247 + client = e.get('client', '')
248 + if not client:
249 + continue
250 + if filter_client and client != filter_client:
251 + continue
252 + if filter_type and not client.startswith(filter_type + '-'):
253 + continue
254 + events.append(e)
255 + except:
256 + pass
257 + except:
258 + pass
259 +
260 + for e in events[-int(limit):]:
261 + ts = e.get('timestamp', '')
262 + try:
263 + from datetime import datetime
264 + dt = datetime.fromisoformat(ts)
265 + ts = dt.strftime(DATETIME_FMT)
266 + except:
267 + pass
268 + client = e.get('client', '—')
269 + endpoint = e.get('endpoint', '—')
270 + event = e.get('event', '—')
271 + print(f"{ts}|{client}|{endpoint}|{event}")
272 +
273 + def format_fw_event(line, clients_dir):
274 + """Format a single fw_event line"""
275 + import glob
276 + proto_map = {1: 'icmp', 6: 'tcp', 17: 'udp'}
277 +
278 + # Build ip->name map
279 + ip_to_name = {}
280 + for conf in glob.glob(f"{clients_dir}/*.conf"):
281 + name = os.path.basename(conf).replace('.conf', '')
282 + try:
283 + with open(conf) as f:
284 + for l in f:
285 + if l.startswith('Address'):
286 + ip = l.split('=')[1].strip().split('/')[0]
287 + ip_to_name[ip] = name
288 + except:
289 + pass
290 +
291 + try:
292 + e = json.loads(line.strip())
293 + src = e.get('src_ip', '')
294 + if not src:
295 + return None
296 + ts = e.get('timestamp', '')
297 + try:
298 + from datetime import datetime
299 + dt = datetime.fromisoformat(ts)
300 + ts = dt.strftime(DATETIME_FMT)
301 + except:
302 + pass
303 + dst = e.get('dest_ip', '—')
304 + port = e.get('dest_port', '')
305 + proto_num = e.get('ip.protocol', 0)
306 + proto = proto_map.get(proto_num, str(proto_num))
307 + dst_str = f"{dst}:{port}" if port else dst
308 + client = ip_to_name.get(src, src)
309 + return f"{ts}|{client}|{dst_str}|{proto}"
310 + except:
311 + return None
312 +
313 + def format_wg_event(line):
314 + """Format a single wg_event line"""
315 + try:
316 + e = json.loads(line.strip())
317 + client = e.get('client', '')
318 + if not client:
319 + return None
320 + ts = e.get('timestamp', '')
321 + try:
322 + from datetime import datetime
323 + dt = datetime.fromisoformat(ts)
324 + ts = dt.strftime(DATETIME_FMT)
325 + except:
326 + pass
327 + endpoint = e.get('endpoint', '—')
328 + event = e.get('event', '—')
329 + return f"{ts}|{client}|{endpoint}|{event}|wg"
330 + except:
331 + return None
332 +
333 + def remove_events(file, identifier):
334 + """Remove all events for a client/ip from a JSONL file"""
335 + try:
336 + lines = []
337 + with open(file) as f:
338 + for line in f:
339 + try:
340 + e = json.loads(line.strip())
341 + if e.get('client') == identifier or e.get('src_ip') == identifier:
342 + continue
343 + lines.append(line)
344 + except:
345 + lines.append(line)
346 + with open(file, 'w') as f:
347 + f.writelines(lines)
348 + except Exception as e:
349 + print(f"Error: {e}", file=sys.stderr)
350 + sys.exit(1)
351 +
352 + def follow_logs(fw_file, wg_file, filter_ip, filter_type, clients_dir, filter_peers=""):
353 + """Follow both log files and output formatted events"""
354 + import glob, time, select
355 +
356 + proto_map = {1: 'icmp', 6: 'tcp', 17: 'udp'}
357 + peer_filter = set(filter_peers.split(',')) if filter_peers else set()
358 + import sys
359 + print(f"DEBUG follow_logs: peer_filter={peer_filter}", file=sys.stderr, flush=True)
360 +
361 + # Build ip->name map
362 + ip_to_name = {}
363 + for conf in glob.glob(f"{clients_dir}/*.conf"):
364 + name = os.path.basename(conf).replace('.conf', '')
365 + try:
366 + with open(conf) as f:
367 + for l in f:
368 + if l.startswith('Address'):
369 + ip = l.split('=')[1].strip().split('/')[0]
370 + ip_to_name[ip] = name
371 + except:
372 + pass
373 +
374 + # Open files and seek to end
375 + files = {}
376 + for label, path in [('fw', fw_file), ('wg', wg_file)]:
377 + if path and os.path.exists(path):
378 + f = open(path)
379 + f.seek(0, 2) # seek to end
380 + files[label] = f
381 +
382 + dedup = {}
383 +
384 + try:
385 + while True:
386 + for label, f in files.items():
387 + line = f.readline()
388 + if not line:
389 + continue
390 + try:
391 + e = json.loads(line.strip())
392 + except:
393 + continue
394 +
395 + if label == 'fw':
396 + src = e.get('src_ip', '')
397 + if not src:
398 + continue
399 + if filter_ip and src != filter_ip:
400 + continue
401 +
402 + # Filter by peer names if specified
403 + if peer_filter:
404 + client_name = ip_to_name.get(src, '')
405 + if client_name not in peer_filter:
406 + continue
407 + dst = e.get('dest_ip', '—')
408 + port = e.get('dest_port', '')
409 + proto_num = e.get('ip.protocol', 0)
410 + proto = proto_map.get(proto_num, str(proto_num))
411 +
412 + # Dedup
413 + key = (src, dst, port, proto_num)
414 + windows = {1: 5, 6: 30, 17: 10}
415 + window = windows.get(proto_num, 10)
416 + now = time.time()
417 + if key in dedup and (now - dedup[key]) < window:
418 + continue
419 + dedup[key] = now
420 +
421 + client = ip_to_name.get(src, src)
422 + if filter_type and not client.startswith(filter_type + '-'):
423 + continue
424 + dst_str = f"{dst}:{port}" if port else dst
425 + ts = e.get('timestamp', '')[:16].replace('T', ' ')
426 + print(f"fw|{ts}|{client}|{dst_str}|{proto}", flush=True)
427 +
428 + elif label == 'wg':
429 + client = e.get('client', '')
430 + if not client:
431 + continue
432 + if filter_ip:
433 + ip = ip_to_name.get(filter_ip, '')
434 + if client != ip and client != filter_ip:
435 + continue
436 +
437 + if peer_filter and client not in peer_filter:
438 + continue
439 + if filter_type and not client.startswith(filter_type + '-'):
440 + continue
441 + ts = e.get('timestamp', '')[:16].replace('T', ' ')
442 + endpoint = e.get('endpoint', '—')
443 + event = e.get('event', '—')
444 + print(f"wg|{ts}|{client}|{endpoint}|{event}", flush=True)
445 +
446 + time.sleep(0.1)
447 + except KeyboardInterrupt:
448 + pass
449 +
450 + def count(file, key):
451 + try:
452 + with open(file) as f:
453 + data = json.load(f)
454 + val = data.get(key, [])
455 + print(len(val) if isinstance(val, list) else 0)
456 + except:
457 + print(0)
458 +
459 + def audit_fw_counts(clients_dir):
460 + """Return peer_name:fw_count pairs from iptables and client configs"""
461 + import glob, subprocess
462 +
463 + # Get iptables output once
464 + try:
465 + result = subprocess.run(
466 + ['iptables', '-L', 'FORWARD', '-n'],
467 + capture_output=True, text=True
468 + )
469 + fw_output = result.stdout
470 + except:
471 + fw_output = ""
472 +
473 + # Build ip->name and count rules
474 + for conf in glob.glob(f"{clients_dir}/*.conf"):
475 + name = os.path.basename(conf).replace('.conf', '')
476 + try:
477 + with open(conf) as f:
478 + for line in f:
479 + if line.startswith('Address'):
480 + ip = line.split('=')[1].strip().split('/')[0]
481 + count = fw_output.count(ip)
482 + print(f"{name}:{count}")
483 + break
484 + except:
485 + pass
486 +
487 + def peer_group_map(groups_dir):
488 + """Return peer:group pairs for all groups"""
489 + import glob
490 + try:
491 + for group_file in glob.glob(f"{groups_dir}/*.group"):
492 + try:
493 + with open(group_file) as f:
494 + g = json.load(f)
495 + name = g.get('name', '')
496 + for peer in g.get('peers', []):
497 + if peer:
498 + print(f"{peer}:{name}")
499 + except:
500 + pass
501 + except:
502 + pass
503 +
504 + def peer_groups(groups_dir, peer_name):
505 + """Find all groups containing a peer"""
506 + import glob
507 + try:
508 + for group_file in glob.glob(f"{groups_dir}/*.group"):
509 + try:
510 + with open(group_file) as f:
511 + g = json.load(f)
512 + if peer_name in g.get('peers', []):
513 + print(g.get('name', ''))
514 + except:
515 + pass
516 + except:
517 + pass
518 +
519 + def peer_data(clients_dir, meta_dir, events_log):
520 + import glob
521 +
522 + meta = {}
523 + for f in glob.glob(f"{meta_dir}/*.meta"):
524 + name = os.path.basename(f).replace('.meta', '')
525 + try:
526 + with open(f) as mf:
527 + meta[name] = json.load(mf)
528 + except:
529 + meta[name] = {}
530 +
531 + last_events = {}
532 + try:
533 + with open(events_log) as f:
534 + for line in f:
535 + try:
536 + e = json.loads(line.strip())
537 + client = e.get('client', '')
538 + if client:
539 + last_events[client] = e
540 + except:
541 + pass
542 + except:
543 + pass
544 +
545 + for conf in sorted(glob.glob(f"{clients_dir}/*.conf")):
546 + name = os.path.basename(conf).replace('.conf', '')
547 + ip = ''
548 + try:
549 + with open(conf) as f:
550 + for line in f:
551 + if line.startswith('Address'):
552 + ip = line.split('=')[1].strip().split('/')[0]
553 + break
554 + except:
555 + pass
556 +
557 + m = meta.get(name, {})
558 + rule = m.get('rule', '')
559 + subtype = m.get('subtype', '')
560 +
561 + last_event = last_events.get(name, {})
562 + last_ts = last_event.get('timestamp', '') # raw ISO, no formatting
563 + last_evt = last_event.get('event', '') # fixed: was last_event
564 +
565 + print(f"{name}|{ip}|{rule}|{subtype}|{last_ts}|{last_evt}")
566 +
567 + def iso_to_ts(iso_str):
568 + """Convert ISO timestamp to unix timestamp"""
569 + try:
570 + from datetime import datetime, timezone
571 + dt = datetime.fromisoformat(iso_str)
572 + if dt.tzinfo is None:
573 + dt = dt.replace(tzinfo=timezone.utc)
574 + print(int(dt.timestamp()))
575 + except:
576 + print(0)
577 +
578 + def rule_list_data(rules_dir, meta_dir):
579 + """Return all rule data for list display in one call"""
580 + import glob
581 +
582 + # Count peers per rule from meta files
583 + rule_peer_counts = {}
584 + for f in glob.glob(f"{meta_dir}/*.meta"):
585 + try:
586 + with open(f) as mf:
587 + meta = json.load(mf)
588 + rule = meta.get('rule', '')
589 + if rule:
590 + rule_peer_counts[rule] = rule_peer_counts.get(rule, 0) + 1
591 + except:
592 + pass
593 +
594 + # Read each rule file
595 + for rule_file in sorted(glob.glob(f"{rules_dir}/*.rule")):
596 + try:
597 + with open(rule_file) as f:
598 + r = json.load(f)
599 + name = r.get('name', '')
600 + desc = r.get('desc', '')
601 + n_allows = len(r.get('allow_ips', [])) + len(r.get('allow_ports', []))
602 + n_blocks = len(r.get('block_ips', [])) + len(r.get('block_ports', []))
603 + peer_count = rule_peer_counts.get(name, 0)
604 + print(f"{name}|{desc}|{n_allows}|{n_blocks}|{peer_count}")
605 + except:
606 + pass
607 +
608 + def group_list_data(groups_dir, blocks_dir):
609 + """Return group summary data in one call"""
610 + import glob
611 +
612 + # Get all block files
613 + blocked_peers = set()
614 + for f in glob.glob(f"{blocks_dir}/*.block"):
615 + name = os.path.basename(f).replace('.block', '')
616 + blocked_peers.add(name)
617 +
618 + for group_file in sorted(glob.glob(f"{groups_dir}/*.group")):
619 + try:
620 + with open(group_file) as f:
621 + g = json.load(f)
622 + name = g.get('name', '')
623 + desc = g.get('desc', '')
624 + peers = [p for p in g.get('peers', []) if p]
625 + total = len(peers)
626 + blocked = sum(1 for p in peers if p in blocked_peers)
627 + print(f"{name}|{desc}|{total}|{blocked}")
628 + except:
629 + pass
630 +
631 + def fmt_datetime(iso_str, fmt):
632 + """Format ISO timestamp with given strftime format"""
633 + try:
634 + from datetime import datetime
635 + dt = datetime.fromisoformat(iso_str)
636 + print(dt.strftime(fmt))
637 + except:
638 + print(iso_str)
639 +
640 + def create_rule(file, name, desc, dns_redirect, allow_ips, block_ips, block_ports):
641 + rule = {
642 + 'name': name,
643 + 'desc': desc,
644 + 'dns_redirect': dns_redirect == 'true',
645 + 'allow_ips': [x for x in allow_ips.split(',') if x] if allow_ips else [],
646 + 'block_ips': [x for x in block_ips.split(',') if x] if block_ips else [],
647 + 'block_ports': [x for x in block_ports.split(',') if x] if block_ports else [],
648 + 'allow_ports': []
649 + }
650 + with open(file, 'w') as f:
651 + json.dump(rule, f, indent=2)
652 +
653 + def cleanup_config(config_file):
654 + """Normalize blank lines in WireGuard config"""
655 + import re
656 + try:
657 + with open(config_file) as f:
658 + config = f.read()
659 + config = re.sub(r'\n{3,}', '\n\n', config)
660 + config = config.rstrip('\n') + '\n'
661 + with open(config_file, 'w') as f:
662 + f.write(config)
663 + except Exception as e:
664 + print(f"Error: {e}", file=sys.stderr)
665 + sys.exit(1)
666 +
667 + def remove_peer_block(config_file, name):
668 + """Remove a peer block from WireGuard config by name"""
669 + import re
670 + try:
671 + with open(config_file) as f:
672 + config = f.read()
673 + pattern = r'\n\[Peer\]\n# ' + re.escape(name) + r'\n[^\n]+\n[^\n]+\n'
674 + result = re.sub(pattern, '\n', config)
675 + with open(config_file, 'w') as f:
676 + f.write(result)
677 + except Exception as e:
678 + print(f"Error: {e}", file=sys.stderr)
679 + sys.exit(1)
680 +
681 + def create_group(file, name, desc):
682 + """Create a new group JSON file"""
683 + try:
684 + group = {'name': name, 'desc': desc, 'peers': []}
685 + with open(file, 'w') as f:
686 + json.dump(group, f, indent=2)
687 + except Exception as e:
688 + print(f"Error: {e}", file=sys.stderr)
689 + sys.exit(1)
690 +
691 + def parse_event(line):
692 + """Parse a single JSON event line"""
693 + try:
694 + e = json.loads(line)
695 + print(f"{e.get('timestamp','')}|{e.get('client','')}|{e.get('endpoint','')}|{e.get('event','')}")
696 + except:
697 + pass
698 +
699 + def parse_fw_event(line):
700 + """Parse a single fw_events.log JSON line"""
701 + try:
702 + e = json.loads(line)
703 + ts = e.get('timestamp', '')
704 + src = e.get('src_ip', '')
705 + dst = e.get('dest_ip', '')
706 + port = e.get('dest_port', '')
707 + proto_map = {1: 'icmp', 6: 'tcp', 17: 'udp'}
708 + proto_num = e.get('ip.protocol', 0)
709 + proto = proto_map.get(proto_num, str(proto_num))
710 + print(f"{ts}|{src}|{dst}|{port}|{proto}")
711 + except:
712 + pass
713 +
714 + def peer_transfer(wg_interface):
715 + """Get transfer bytes per peer from wg show"""
716 + import subprocess
717 + try:
718 + result = subprocess.run(
719 + ['wg', 'show', wg_interface, 'transfer'],
720 + capture_output=True, text=True
721 + )
722 + for line in result.stdout.strip().split('\n'):
723 + if not line:
724 + continue
725 + parts = line.split('\t')
726 + if len(parts) == 3:
727 + pubkey, rx, tx = parts
728 + total = int(rx) + int(tx)
729 + if total == 0:
730 + level = 'none'
731 + elif total < 1_000_000:
732 + level = 'low'
733 + elif total < 10_000_000:
734 + level = 'medium'
735 + elif total < 100_000_000:
736 + level = 'high'
737 + else:
738 + level = 'very high'
739 + print(f"{pubkey}|{rx}|{tx}|{level}")
740 + except:
741 + pass
742 +
743 + commands = {
744 + 'get': lambda args: get(args[0], args[1]),
745 + 'set': lambda args: set_key(args[0], args[1], args[2]),
746 + 'delete': lambda args: delete_key(args[0], args[1]),
747 + 'append': lambda args: append(args[0], args[1], args[2]),
748 + 'remove': lambda args: remove_value(args[0], args[1], args[2]),
749 + 'cat': lambda args: cat(args[0]),
750 + 'has_key': lambda args: has_key(args[0], args[1]),
751 + 'filter_values': lambda args: filter_values(args[0], args[1], args[2]),
752 + 'last_event': lambda args: last_event(args[0], args[1], args[2], args[3]),
753 + 'events_for': lambda args: events_for(args[0], args[1], args[2]),
754 + 'fw_events': lambda args: fw_events(args[0], args[1], args[2], args[3], args[4]),
755 + 'wg_events': lambda args: wg_events(args[0], args[1], args[2], args[3]),
756 + 'format_fw_event': lambda args: format_fw_event(sys.stdin.read(), args[0]),
757 + 'format_wg_event': lambda args: format_wg_event(sys.stdin.read()),
758 + 'remove_events': lambda args: remove_events(args[0], args[1]),
759 + 'follow_logs': lambda args: follow_logs(args[0], args[1], args[2], args[3], args[4], args[5]),
760 + 'count': lambda args: count(args[0], args[1]),
761 + 'audit_fw_counts': lambda args: audit_fw_counts(args[0]),
762 + 'peer_group_map': lambda args: peer_group_map(args[0]),
763 + 'peer_groups': lambda args: peer_groups(args[0], args[1]),
764 + 'peer_data': lambda args: peer_data(args[0], args[1], args[2]),
765 + 'iso_to_ts': lambda args: iso_to_ts(args[0]),
766 + 'rule_list_data': lambda args: rule_list_data(args[0], args[1]),
767 + 'group_list_data': lambda args: group_list_data(args[0], args[1]),
768 + 'fmt_datetime': lambda args: fmt_datetime(args[0], args[1]),
769 + 'create_rule': lambda args: create_rule(args[0], args[1], args[2], args[3], args[4], args[5], args[6]),
770 + 'cleanup_config': lambda args: cleanup_config(args[0]),
771 + 'remove_peer_block': lambda args: remove_peer_block(args[0], args[1]),
772 + 'create_group': lambda args: create_group(args[0], args[1], args[2]),
773 + 'parse_event': lambda args: parse_event(args[0]),
774 + 'parse_fw_event': lambda args: parse_fw_event(args[0]),
775 + 'peer_transfer': lambda args: peer_transfer(args[0]),
776 + }
777 +
778 + if __name__ == '__main__':
779 + if len(sys.argv) < 2:
780 + print("Usage: json_helper.py <command> <file> [key] [value]", file=sys.stderr)
781 + sys.exit(1)
782 +
783 + cmd = sys.argv[1]
784 + args = sys.argv[2:]
785 +
786 + if cmd not in commands:
787 + print(f"Unknown command: {cmd}", file=sys.stderr)
788 + sys.exit(1)
789 +
790 + commands[cmd](args)
上一页 下一页