最終更新 1 month ago

nuno revised this gist 1 month ago. Go to revision

1 file changed, 96 insertions

gistfile1.txt(file created)

@@ -0,0 +1,96 @@
1 + def accept_aggregate(file, net_file, clients_dir, since='',
2 + filter_peer='', external_only='0'):
3 + """
4 + Aggregate accept events per peer — total bytes, packets, top destinations.
5 + Used by wgctl activity to show accepted traffic alongside drops.
6 +
7 + external_only='1': only show traffic to external IPs (non-private)
8 + external_only='0': only show traffic to internal IPs (default)
9 +
10 + Output:
11 + peer|peer_name|bytes_in|bytes_out|packets_in|packets_out|conn_count
12 + dest|peer_name|dst_ip|dst_port|proto|bytes_total|conn_count
13 + """
14 + from collections import defaultdict
15 + from itertools import groupby
16 +
17 + since_dt = parse_since(since) if since else None
18 + show_external = str(external_only) == '1'
19 +
20 + peer_stats = defaultdict(lambda: {
21 + 'bytes_in': 0, 'bytes_out': 0,
22 + 'packets_in': 0, 'packets_out': 0,
23 + 'conn_count': 0
24 + })
25 + # dest_stats = defaultdict(lambda: {'bytes': 0, 'count': 0})
26 + dest_stats = defaultdict(lambda: {'bytes_orig': 0, 'bytes_reply': 0, 'count': 0})
27 +
28 + try:
29 + with open(file) as f:
30 + for line in f:
31 + try:
32 + e = json.loads(line.strip())
33 + peer = e.get('peer', '')
34 + if not peer:
35 + continue
36 + if filter_peer and peer != filter_peer:
37 + continue
38 +
39 + # Filter by external/internal
40 + is_external = e.get('external', False)
41 + if show_external and not is_external:
42 + continue
43 + if not show_external and is_external:
44 + continue
45 +
46 + if since_dt:
47 + ts_str = e.get('ts', '')
48 + try:
49 + from datetime import timezone
50 + ev_dt = datetime.fromisoformat(
51 + ts_str.replace('Z', '+00:00'))
52 + if ev_dt < since_dt:
53 + continue
54 + except Exception:
55 + pass
56 +
57 + dst_ip = e.get('dst_ip', '')
58 + dst_port = str(e.get('dst_port', ''))
59 + proto = e.get('proto', '')
60 + b_orig = e.get('bytes_orig', 0)
61 + b_reply = e.get('bytes_reply', 0)
62 + p_orig = e.get('packets_orig', 0)
63 + p_reply = e.get('packets_reply', 0)
64 +
65 + ps = peer_stats[peer]
66 + ps['bytes_out'] += b_orig
67 + ps['bytes_in'] += b_reply
68 + ps['packets_out'] += p_orig
69 + ps['packets_in'] += p_reply
70 + ps['conn_count'] += 1
71 +
72 + dest_key = (peer, dst_ip, dst_port, proto)
73 + dest_stats[dest_key]['bytes_orig'] += b_orig
74 + dest_stats[dest_key]['bytes_reply'] += b_reply
75 + dest_stats[dest_key]['count'] += 1
76 +
77 + except Exception:
78 + pass
79 + except Exception:
80 + pass
81 +
82 + # Output peer summaries
83 + for peer, ps in sorted(peer_stats.items()):
84 + print(f"peer|{peer}|{ps['bytes_in']}|{ps['bytes_out']}|"
85 + f"{ps['packets_in']}|{ps['packets_out']}|{ps['conn_count']}")
86 +
87 + # Output top 5 destinations per peer sorted by byte count
88 + dest_items = sorted(
89 + dest_stats.items(),
90 + key=lambda x: (x[0][0], -x[1]['bytes'])
91 + )
92 + for peer, group in groupby(dest_items, key=lambda x: x[0][0]):
93 + top = list(group)[:20]
94 + for (p, dst_ip, dst_port, proto), stats in top:
95 + print(f"dest|{p}|{dst_ip}|{dst_port}|{proto}|"
96 + f"{stats['bytes_orig']}|{stats['bytes_reply']}|{stats['count']}")
Newer Older