Commit graph

87 commits

Author SHA1 Message Date
Nuno Duque Nunes
290ac24d88 refactor: core directory restructure
- core/framework/: flag.sh, hook.sh, help.sh, command.sh, mixin.sh
- core/app/: wgctl-specific context.sh, json.sh
- core/framework/mixins/: json_output, no_color mixins
- core/core.sh: sources framework/core.sh + app/core.sh
- PYTHONPATH exported in app/core.sh for lib/ module resolution
- command::_load_mixins: uses _FRAMEWORK_DIR for mixin path
2026-05-30 02:50:43 +00:00
Nuno Duque Nunes
e4545a400b feat: --exclude-service/--include-service, --ports flags
- activity: --exclude-service (repeatable), --include-service override
- activity: --ports flag shows dim raw IP:port on accept and drop rows
- activity_aggregate: dst_ip/dst_port/proto in service row output
- activity_aggregate: exclude_services filtering for drop rows
- ui::activity::_visible_len: ANSI-aware padding for --ports alignment
- service_row/accept_dest_row: correct padding with ANSI suffixes
- accept_dest_row: fix ↓/↑ swap (bytes_reply=download, bytes_orig=upload)
- command defaults: activity defaults with pihole exclusions
2026-05-29 23:34:13 +00:00
Nuno Duque Nunes
10ea174e44 Merge feature/command-defaults: defaults, aliases, exclusive flags 2026-05-29 15:52:41 +00:00
Nuno Duque Nunes
9c11152682 feat: command defaults, aliases, exclusive flag groups
- wgctl.json: commands section with defaults and aliases
- command_mixins.sh: flag::exclusive, command::_resolve_conflicts
- command::run: two-pass defaults+user with conflict resolution
- load_command: _CURRENT_LOADING_CMD for flag::exclusive context
- list: flag::exclusive --online --offline --blocked --restricted --allowed
- logs: flag::exclusive --ascending --descending
- logs: fix --fw --wg together treated as neither (show both)
- dispatch: config alias resolution before load_command
- wgctl ls/peers/act: aliases via wgctl.json
2026-05-29 04:31:07 +00:00
Nuno Duque Nunes
b153f222a5 perf: batch resolve accept dest IPs in activity (4x speedup)
- json_helper: batch_resolve_dest() resolves all dest IPs in one Python call
- json.sh: json::batch_resolve_dest wrapper
- activity: _DEST_RESOLVE_CACHE pre-populated before render loop
- _render_peer_accept_dests: cache lookup instead of resolve::dest per row
- activity: 1.8s -> 0.48s
2026-05-29 00:27:43 +00:00
Nuno Duque Nunes
d26e67b940 Merge feature/accept-logging: conntrack daemon, activity integration 2026-05-28 23:34:12 +00:00
Nuno Duque Nunes
b892298259 feat: accept logging, conntrack daemon, activity integration
- daemon/wgctl-conntrack: Go daemon for conntrack DESTROY events
- wgctl-conntrack.service: systemd service
- core/lib/accept_events.py: accept_events(), accept_aggregate()
- ctx::accept_events_log: .wgctl/daemon/accept_events.log
- activity: ACCEPT row with bytes in/out and conn count
- activity: accept dest rows with ↓/↑ bytes at end
- activity: --accept, --drop, --external flags
- activity: unified w_count for drop/accept alignment
- activity: drop service rows in red
- activity: accept dest rows in green
- sysctl: nf_conntrack_acct=1 for byte counting
- note: --exclude-service/--include-service deferred
2026-05-28 23:31:10 +00:00
Nuno Duque Nunes
d314ba376e feat: wgctl-conntrack Go daemon
- conntrack/event.go: TrafficEvent type
- conntrack/filter.go: WG subnet filter, IsExternal, ProtoName
- conntrack/subscriber.go: netlink conntrack DESTROY subscriber
- writer/log.go: JSON line writer with mutex
- resolver/peers.go: WG IP → peer name from conf files + endpoint index
- resolver/services.go: IP:port → service name from services.json
- config/config.go: reads wgctl.json, sensible defaults
- cmd/root.go: CLI flags
- main.go: wires everything together
- DESTROY events only: full byte/packet counts per connection
- filters to WireGuard subnet, marks external traffic
2026-05-28 02:51:27 +00:00
Nuno Duque Nunes
91593b2576 Merge feature/block-history into master 2026-05-28 01:54:02 +00:00
Nuno Duque Nunes
0b9f113453 feat: block history tracking
- core/lib/block_history.py: record/unblock/list functions
- ctx::block_history: .wgctl/data/block-history/ path
- block --reason: record block event with reason, endpoint, triggered_by
- unblock --reason: update block event with unblock timestamp
- json::block_history_record/unblock/list/list_all wrappers
- json::endpoint_cache_get: get cached endpoint for peer
- export --all: include block-history in full backup
- import --all: restore block-history files
- tests: section_block_unblock with fixture peer, history field validation
2026-05-28 01:51:37 +00:00
Nuno Duque Nunes
79769667fb add json core functions 2026-05-27 23:08:21 +00:00
Nuno Duque Nunes
ddd705aa87 Merge feature/export-import: wgctl export/import commands (v0.8.0) 2026-05-27 16:47:41 +00:00
Nuno Duque Nunes
00d6be0766 add export,import features/add tests 2026-05-27 16:46:09 +00:00
Nuno Duque Nunes
8f3360c631 feat: wgctl export command
- export --peer: single peer export with conf/meta/identity/groups/blocks
- export --identity: identity export
- export --all: full backup with all sections
- export --conf-only, --meta-only: selective peer export
- export --no-config, --no-peers: selective full export
- export --out: write to file
- json_helper: export_full(), _export_peer_data() Python functions
- base64 encoding for conf and block files
- valid JSON output via Python for full backup
2026-05-27 04:11:59 +00:00
Nuno Duque Nunes
a7b05547f5 Merge feature/display-config: display config system, table/compact toggle 2026-05-27 03:32:44 +00:00
Nuno Duque Nunes
1a78dcf5da feat: display config, table layouts for all commands
- display.module.sh: style toggle per view (compact/table)
- display.json: default config with all views set to compact
- ctx::display: points to .wgctl/config/display.json
- list: _render_table with dynamic widths, colors, shared row_color/status_color
- group/identity/net/hosts/activity: _render_table added
- rule/subnet/policy: table UI functions + _render_table
- ui::peer::status_color: \033[2m for offline (dimmer, more readable)
- note: individual table layout refinements pending cleanup pass
- note: configurable colors per field deferred to display config v2
2026-05-27 03:32:31 +00:00
Nuno Duque Nunes
7a544f9019 feat: display config system, table/compact toggle
- modules/display.module.sh: display config loader
- .wgctl/config/display.json: per-view style configuration
- ctx::display: points to .wgctl/config/display.json
- json_helper: display_load() reads view styles
- list: display::render dispatcher, _render_table with dynamic widths/colors
- ui::peer::_row_color/status_color: shared by both table and compact
- table layout: aligned columns, colored status/rows, dynamic separator
2026-05-27 02:48:51 +00:00
Nuno Duque Nunes
dda8e408e8 merge master 2026-05-27 02:05:32 +00:00
Nuno Duque Nunes
74644e547c Merge refactor/config-restructure: JSON config, data/ layout 2026-05-27 01:37:39 +00:00
Nuno Duque Nunes
2a6648735e refactor: config restructure, wgctl.json, data/ directory layout
- context.sh: .wgctl/{config,data,daemon} directory structure
- ctx::config_file: points to .wgctl/config/wgctl.json
- ctx::data: points to .wgctl/data/ (rules, identities, groups, etc.)
- ctx::peer_history: .wgctl/data/peer-history/
- config.module.sh: loads from wgctl.json via json::config_load
- config::_load_legacy: fallback for old wgctl.conf with migration warning
- json_helper.py: config_load() outputs KEY=value pairs from wgctl.json
- cmd::config::migrate: converts wgctl.conf → wgctl.json, moves data files
- cmd::config::_show: renamed from run body
- daemon/wgctl-monitor.py: updated PEER_HISTORY_DIR path
2026-05-27 01:37:28 +00:00
Nuno Duque Nunes
50013d8ede add remaining tests related to json api 2026-05-27 01:04:30 +00:00
Nuno Duque Nunes
1fa40c1e25 Merge feature/json-output: --json output, command mixin system (v0.6.0) 2026-05-27 00:52:47 +00:00
Nuno Duque Nunes
0e3f281519 feat: --json for hosts/subnet/policy list commands
- cmd::hosts::_output_json: hosts with type/tags array
- cmd::subnet::_output_json: subnets with is_group bool
- cmd::policy::_output_json: policies with proper booleans
2026-05-27 00:52:45 +00:00
Nuno Duque Nunes
087f735790 feat: --json output for group/rule/identity/net/activity
- cmd::group::_output_json: groups array with peer/blocked counts
- cmd::rule::_output_json: rules with extends array, is_base bool fix
- cmd::identity::_output_json: identities with types/rules as arrays
- cmd::net::_output_json: services with tags array and port count
- cmd::activity::_output_json: peers with nested services array
- all commands: command::mixin json_output registered in on_load
2026-05-27 00:36:30 +00:00
Nuno Duque Nunes
fae088f61a commands/mixin/MIXIN_TEMPLATE.mixin.sh 2026-05-27 00:01:53 +00:00
Nuno Duque Nunes
14d2a78b78 feat: command mixin system, --json for list/inspect, tests
- core/command_mixins.sh: mixin infrastructure with auto-loader
- core/mixins/json_output.mixin.sh, no_color.mixin.sh
- commands/mixins/MIXIN_TEMPLATE.mixin.sh
- command::run: mixin preprocess with nameref, empty array guard
- list --json, inspect --json: structured JSON with envelope
- json::envelope, json::error_envelope
- tests: json output unit tests, group purge-stale, logs clean
2026-05-27 00:01:06 +00:00
Nuno Duque Nunes
a3fe7f5986 feat: command mixin system, --json output for list/inspect
- core/command_mixins.sh: mixin infrastructure with auto-loader
- core/mixins/json_output.mixin.sh: --json flag mixin
- core/mixins/no_color.mixin.sh: --no-color flag mixin
- commands/mixins/MIXIN_TEMPLATE.mixin.sh: template for new mixins
- command::run: reset mixin state, preprocess flags before dispatch
- command::_preprocess_flags: nameref-based flag stripping, empty array fix
- command::mixin: opt-in registration from on_load
- list --json: structured JSON output with envelope
- inspect --json: structured JSON peer detail output
- json::envelope, json::error_envelope helpers
2026-05-26 23:18:56 +00:00
Nuno Duque Nunes
adab623f3f feat: group purge-stale, peer endpoint history, resolve improvements
- group purge-stale: remove stale peers from group(s), --all, --dry-run
- daemon: update_peer_history() tracks all endpoints per peer
- daemon: endpoint_index.json for O(1) IP -> peer name lookup
- json_helper: peer_history_lookup() with index + scan fallback
- resolve::endpoint_parts: peer history as step 3 in resolution chain
- resolve::service_name: returns service name only, no raw fallback
- resolve::endpoint_parts: removed stale cache, always fresh
- watch: ui::wg_row/fw_row use shared primitives
- ui: ui::_render_endpoint_col, ui::_build_dest shared primitives
- shell: peer/hosts/identity/subnet/policy/activity in known commands
2026-05-26 20:51:40 +00:00
Nuno Duque Nunes
8b47e55b4a feat: peer endpoint history tracking and resolution
- daemon: update_peer_history() tracks all endpoints per peer
- daemon: endpoint_index.json for O(1) IP -> peer name lookup
- daemon: poll_handshakes updates history on every cycle
- json_helper: peer_history_lookup() uses index, falls back to scan
- resolve::endpoint_parts: step 3 checks peer history index
- json.sh: json::peer_history_lookup wrapper
- resolve: mobile peer IPs now resolve to peer name via history
2026-05-26 15:51:53 +00:00
Nuno Duque Nunes
c3cf5bc572 feat: watch/logs endpoint annotation, shared row primitives
- ui::_render_endpoint_col: shared endpoint padding primitive
- ui::_build_dest: shared destination display primitive
- ui::wg_row/fw_row: endpoint annotation (raw_ip → resolved)
- resolve::endpoint_parts: fresh resolution, no stale cache
- resolve::service_name: returns service name or empty (no raw fallback)
- monitor::live: pre-measure w_client from peer names
- watch: fixed w_endpoint=30 for consistent live alignment
- shell: add peer/hosts/identity/subnet/policy/activity to known commands
- shell: updated banner with new commands
- identity/rule help: updated with new features
2026-05-26 15:16:33 +00:00
Nuno Duque Nunes
c6883c6801 fix: --ascending/--descending flag parsing in logs show
- cmd::logs::show: parse --ascending and --descending flags
- sort_order defaults to desc
2026-05-26 12:40:35 +00:00
Nuno Duque Nunes
7120199004 feat: logs --resolved flag, logs clean, performance improvements
- logs --resolved: show only resolved names, hide raw IPs
- logs clean: remove keepalive handshakes via json::clean_handshakes
- batch_resolve: single Python call for all endpoint resolutions
- fw_row/wg_row: native bash padding replaces ui::pad_mb (5x speedup)
- fw_row/wg_row: correct arrow byte counting (→ = 3 bytes, 1 visible)
- help: updated with new subcommands and flags
- on_load: --resolved, --ascending, --descending registered
2026-05-26 04:34:39 +00:00
Nuno Duque Nunes
fb33aa1b6d feat: logs endpoint annotation, alignment, descending sort
- fw/wg events: raw_ip → resolved_name annotation (dim)
- fw events: endpoint column with pre-resolved names (two-pass render)
- fw events: raw IP:port dim suffix after service name
- wg events: endpoint annotation in logs (same as watch)
- fw/wg: descending sort default, --ascending/--descending flags
- wg events: gap/offline indicator, threshold * 2 for offline label
- fw_row: no-endpoint rows show dim — placeholder for alignment
- section headers: dynamic width via tput cols
2026-05-26 03:07:57 +00:00
Nuno Duque Nunes
d5de344d99 add ctx::endpoint_cache as arg to wrapper 2026-05-26 01:47:13 +00:00
Nuno Duque Nunes
3c3f870427 feat: logs descending sort, gap/offline indicator, endpoint resolution
- wg_events: sort_order param (desc default), --ascending/--descending flags
- wg_events: endpoint cache fallback via _endpoint() helper
- wg_events: gap computed ascending always, then sliced/reversed correctly
- fw_events: sort_order param, descending default
- ui::logs::wg_row: gap suffix with 'offline' label when gap > threshold
- logs.command.sh: --ascending/--descending flags, pass sort_order to both functions
- daemon: endpoint cache fallback in poll_handshakes
- json.sh: json::wg_events passes ctx::endpoint_cache as arg
2026-05-26 01:34:48 +00:00
Nuno Duque Nunes
cf71e9f51a test: add tests for all new features, fix bugs found by tests
- integration: logs query flags, hosts command, peer command sections
- unit: fmt::bytes, config::dns_string, parse_since, ui::group::status
- destructive: duplicate rule validation, peer update-dns/tunnel
- fix: config::allowed_ips_for used $2 instead of $1
- fix: identity rule assign exit_code unbound variable
- fix: ctx::identity → ctx::identities in peers::get_identity
- fix: peers::get_identity restored (needed for rule assign duplicate check)
- rule assign: blocks if rule already in peer's identity via peers::get_identity
- identity rule assign: --migrate removes conflicting direct peer rules
2026-05-26 00:09:30 +00:00
Nuno Duque Nunes
794e75bc9b feat: duplicate rule validation, peer command, fallback DNS
- rule assign: block if rule already in peer's identity
- identity rule assign: --migrate flag to remove conflicting direct peer rules
- commands/peer.command.sh: update-dns and update-tunnel subcommands
- config.sh: config::dns_fallback, config::dns_string
- peers.module.sh: peers::get_display_subnet extraction
- wgctl peer update-dns --all: retrofits existing peer configs with fallback DNS
- wgctl.conf: WG_DNS_FALLBACK support
2026-05-25 21:39:17 +00:00
Nuno Duque Nunes
d14db5e85c remove hardcoded policies 2026-05-25 18:47:48 +00:00
Nuno Duque Nunes
a003e3b753 fix: policy_read accidental defaults merge from module split
- _policy_read: remove erroneous _POLICY_DEFAULTS merge (introduced during split)
- fmt.sh: fmt::bytes extracted from cmd::activity::_fmt_bytes
- identity/subnet/policy list: ui::sort_rows applied
- ctx::policies moved from policy.module.sh to context.sh
2026-05-25 18:45:23 +00:00
Nuno Duque Nunes
86220850c1 fix: handshake session detection, endpoint cache, watch ordering
- wgctl-monitor: update _hs_last_logged on ALL handshakes not just new sessions
- wgctl-monitor: fix endpoint_cache.json absolute path
- wgctl-monitor: move script to wgctl/daemon/ (correct location)
- watch: _poll_handshakes sorts by ts descending, endpoint cache fallback
- watch: empty endpoint uses - not em dash (alignment fix)
- logs: newline between fw and wg sections
- monitor::live extracted, cmd::logs::follow no longer calls cmd::run
- ui.sh: UTF-8 extra byte constants
2026-05-25 16:19:13 +00:00
Nuno Duque Nunes
3058750c3d cleanup: ui::pad_mb removal, watch alignment fixes, endpoint cache fallback
- ui::rule::list_row: inline padding math replaces ui::pad_mb (major perf gain)
- ui::fw_row/wg_row: drop ui::pad_mb for fw/wg labels (always 2 chars)
- watch: endpoint fallback via monitor::get_cached_endpoint
- watch: _poll_handshakes sorts by ts descending (most recent first)
- watch: empty endpoint uses - not — (avoids multi-byte padding issues)
- ui.sh: UTF-8 extra byte constants (_UI_EMDASH_EXTRA, _UI_ARROW_EXTRA, _UI_BULLET_EXTRA)
2026-05-25 15:09:13 +00:00
Nuno Duque Nunes
5c2e16e358 Merge feature/logs-query: logs query flags, json_helper module split, handshake logging (v0.5.1) 2026-05-25 14:07:52 +00:00
Nuno Duque Nunes
8b1f4e48c1 fix block_is_empty missing in dict 2026-05-25 14:07:26 +00:00
Nuno Duque Nunes
3378ec3e5e feat: logs query flags, json_helper module split, handshake logging
- wgctl logs --since: relative (2h/7d) and EU/ISO date formats
- wgctl logs --service: filter by service name, IP, or IP:port
- wgctl logs --event: filter wg events by type
- wgctl logs: no header when no logs found
- core/lib/util.py: shared utilities, parse_since, reverse_lookup
- core/lib/events.py: fw_events, wg_events with query params
- core/lib/peers.py: peer_data, peer_transfer
- core/lib/activity.py: activity_aggregate
- wgctl-monitor.py: handshake session poller thread with cache
2026-05-25 00:21:16 +00:00
Nuno Duque Nunes
1308f9e07a refactor: split json_helper.py into lib/ modules
- core/lib/util.py: shared utilities, ip_to_name, reverse_lookup, parse_since
- core/lib/events.py: fw_events, wg_events, follow_logs, event parsers
- core/lib/peers.py: peer_data, peer_transfer, peer_transfer_delta
- core/lib/activity.py: activity_aggregate
- json_helper.py: thin dispatcher importing from lib/
- events.py: --since, --filter-event, --filter-dest-ip/port query flags
- util.py: parse_since supporting relative (2h/7d) and EU/ISO date formats
2026-05-24 22:02:50 +00:00
Nuno Duque Nunes
28ee56aeff feat: identity show with rule tree, peer dimming, net/group tableless layouts
- identity show: peers, rules tree, dim offline peers
- ui::rule::identity_block --no-header flag with reduced indentation
- ui::identity::device_row: index suffix fix, offline dimming
- net list/show: tableless with port display and descriptions
- group list/show: tableless with status coloring, stale peer handling
- group list_data: filter stale peers via clients_dir
- logs: hourly collapse for attempts, --detailed for raw events
- hosts resolution in wg_events static view
- wg-quick PostDown iptables error fix (2>/dev/null)
2026-05-24 20:46:02 +00:00
Nuno Duque Nunes
a71f7a0dd9 fix fw logs not showing, add hourly structuring to logs 2026-05-24 02:13:06 +00:00
Nuno Duque Nunes
92993e6423 merge tableless-list refactors 2026-05-24 00:09:11 +00:00
Nuno Duque Nunes
689908c875 refactor: tableless design for net, group list | net, group show 2026-05-24 00:08:15 +00:00
Nuno Duque Nunes
e54ce9c417 load module policy 2026-05-23 23:30:39 +00:00