diff --git a/commands/fw.command.sh b/commands/fw.command.sh index 8912a8f..384a07e 100644 --- a/commands/fw.command.sh +++ b/commands/fw.command.sh @@ -205,9 +205,9 @@ function cmd::fw::_print_filtered() { local show_nflog="$1" show_accept="$2" show_drop="$3" while IFS= read -r rule; do [[ -z "$rule" ]] && continue - ! $show_nflog && [[ "$rule" =~ NFLOG ]] && continue - ! $show_accept && [[ "$rule" =~ ACCEPT ]] && continue - ! $show_drop && [[ "$rule" =~ DROP ]] && continue + if ! $show_nflog && [[ "$rule" =~ NFLOG ]]; then continue; fi + if ! $show_accept && [[ "$rule" =~ ACCEPT ]]; then continue; fi + if ! $show_drop && [[ "$rule" =~ DROP ]]; then continue; fi ui::firewall_rule "$rule" done } \ No newline at end of file diff --git a/commands/inspect.command.sh b/commands/inspect.command.sh index 44c5fe5..17ead60 100644 --- a/commands/inspect.command.sh +++ b/commands/inspect.command.sh @@ -37,39 +37,50 @@ function cmd::inspect::_section() { printf "\n \033[0;37m── %s ──────────────────────────────────\033[0m\n" "$title" } -function cmd::inspect::_row() { - local label="$1" value="$2" - printf " %-20s %s\n" "${label}:" "$value" -} - function cmd::inspect::_peer_info() { - local name="$1" - local ip type rule status endpoint last_seen tunnel public_key + local name="${1:-}" + local ip type rule public_key allowed_ips ip=$(peers::get_ip "$name") type=$(peers::get_type "$name") rule=$(peers::get_meta "$name" "rule") - public_key=$(keys::public "$name" 2>/dev/null) + public_key=$(keys::public "$name" 2>/dev/null || echo "") + allowed_ips=$(grep "^AllowedIPs" "$(ctx::clients)/${name}.conf" \ + 2>/dev/null | cut -d'=' -f2- | xargs) - # Status + endpoint + last seen — reuse list helpers - status=$(cmd::list::format_status "$name" "$public_key" "$ip") - last_seen=$(cmd::list::format_last_seen "$name" "$public_key" "$ip") + # Status + local handshake_ts is_blocked last_ts + handshake_ts=$(monitor::get_handshake_ts "$public_key") + peers::is_blocked "$name" && is_blocked="true" || is_blocked="false" + last_ts=$(monitor::last_attempt "$name") + + local status last_seen endpoint + status=$(peers::format_status "$name" "$public_key" \ + "$is_blocked" "false" "$handshake_ts" "$last_ts") + last_seen=$(peers::format_last_seen "$name" "$public_key" \ + "$is_blocked" "$last_ts" "" "$handshake_ts") endpoint=$(monitor::get_cached_endpoint "$name") - # Tunnel mode from AllowedIPs in conf - local allowed_ips - allowed_ips=$(grep "^AllowedIPs" "$(ctx::clients)/${name}.conf" 2>/dev/null | cut -d'=' -f2- | xargs) + local activity_total + activity_total=$(peers::format_activity_total "$public_key") + + local activity_current + activity_current=$(peers::format_activity_current "$public_key") + + local subtype + subtype=$(peers::get_meta "$name" "subtype") cmd::inspect::_section "Client" - cmd::inspect::_row "Name" "$name" - cmd::inspect::_row "IP" "$ip" - cmd::inspect::_row "Type" "$(cmd::list::display_type "$name" "$type")" - cmd::inspect::_row "Rule" "${rule:-—}" - cmd::inspect::_row "Status" "$(echo -e "$status")" - cmd::inspect::_row "Endpoint" "${endpoint:-—}" - cmd::inspect::_row "Last seen" "$last_seen" - cmd::inspect::_row "AllowedIPs" "$allowed_ips" - cmd::inspect::_row "Public key" "${public_key:-—}" + ui::row "Name" "$name" + ui::row "IP" "$ip" + ui::row "Type" "$(peers::display_type "$type" "$subtype")" + ui::row "Rule" "${rule:-—}" + ui::row "Status" "$(echo -e "$status")" + ui::row "Endpoint" "${endpoint:-—}" + ui::row "Last seen" "$last_seen" + ui::row "AllowedIPs" "$allowed_ips" + ui::row "Public key" "${public_key:-—}" + ui::row "Activity" "Total: $activity_total | Current: $activity_current" } function cmd::inspect::_rule_info() { diff --git a/commands/list.command.sh b/commands/list.command.sh index 1980828..5e47535 100644 --- a/commands/list.command.sh +++ b/commands/list.command.sh @@ -51,125 +51,6 @@ Examples: EOF } -# ============================================ -# Status / Display helpers -# ============================================ - -function cmd::list::_is_connected() { - local ts="$1" - [[ -z "$ts" || "$ts" == "0" ]] && return 1 - local now diff - now=$(date +%s) - diff=$(( now - ts )) - (( diff < 180 )) -} - -function cmd::list::_is_attempting() { - local last_ts="$1" - [[ -z "$last_ts" ]] && return 1 - local now attempt_ts diff - now=$(date +%s) - attempt_ts=$(json::iso_to_ts "$last_ts") - [[ -z "$attempt_ts" || "$attempt_ts" == "0" ]] && return 1 - diff=$(( now - attempt_ts )) - (( diff < 180 )) -} - -function cmd::list::_format_last_seen() { - local name="$1" - local pubkey="$2" - local is_blocked="${3:-0}" - local last_ts="${4:-0}" - local last_evt="${5:-0}" - local handshake_ts="${6:-0}" - - if [[ "$is_blocked" == "true" ]]; then - if [[ -n "$last_ts" && "$last_ts" != "0" && "$last_ts" != "null" ]]; then - local formatted - formatted=$(fmt::datetime_iso "$last_ts") - echo "${formatted} (dropped)" - else - echo "—" - fi - else - if [[ -z "$handshake_ts" || "$handshake_ts" == "0" ]]; then - echo "—" - else - local formatted - formatted=$(fmt::datetime "$handshake_ts") - echo "${formatted} (handshake)" - fi - fi -} - -function cmd::list::_format_status() { - local name="$1" - local pubkey="$2" - local is_blocked="${3:-false}" - local is_restricted="${4:-false}" - local handshake_ts="${5:-0}" - local last_ts="${6:-}" - local connected=false modifier="" color - - if [[ "$is_blocked" == "true" ]]; then - cmd::list::_is_attempting "$last_ts" && connected=true - modifier=" (blocked)" - color="\033[1;31m" - elif [[ "$is_restricted" == "true" ]]; then - cmd::list::_is_connected "$handshake_ts" && connected=true - modifier=" (restricted)" - color="\033[1;33m" - else - cmd::list::_is_connected "$handshake_ts" && connected=true - modifier="" - if $connected; then - color="\033[1;32m" - else - color="\033[0;37m" - fi - fi - - local conn_str - $connected && conn_str="online" || conn_str="offline" - echo -e "${color}${conn_str}${modifier}\033[0m" -} - -function peers::get_type() { - local ip="$1" - local type="unknown" - for t in $(config::device_types); do - local subnet - subnet=$(config::subnet_for "$t") - if string::starts_with "$ip" "${subnet}."; then - type="$t" - break - fi - done - echo "$type" -} - -function cmd::list::display_type() { - local name="${1:-0}" - local type="${2:-0}" - local subtype="${3:-}" - if config::is_guest_type "$type" && [[ -n "$subtype" ]]; then - echo "guest/${subtype}" - elif config::is_guest_type "$type"; then - echo "guest" - else - echo "$type" - fi -} - -function cmd::list::pad_status() { - local status="$1" - local width="${2:-25}" - local visible - visible=$(echo -e "$status" | sed 's/\x1b\[[0-9;]*m//g') - local pad=$(( width - ${#visible} )) - printf "%b%${pad}s" "$status" "" -} - # ============================================ # Header / Footer # ============================================ @@ -224,7 +105,7 @@ function cmd::list::_render_summary() { # ============================================ function cmd::list::show_client() { - local name="$1" + local name="${1:-}" local conf conf="$(ctx::clients)/${name}.conf" @@ -233,16 +114,26 @@ function cmd::list::show_client() { return 1 fi - local ip allowed_ips public_key + local ip ip=$(grep "^Address" "$conf" | awk '{print $3}' | cut -d'/' -f1) + + local allowed_ips allowed_ips=$(grep "^AllowedIPs" "$conf" | cut -d'=' -f2- | xargs) + + local public_key public_key=$(keys::public "$name" 2>/dev/null || echo "unknown") local type - type=$(peers::get_type "$ip") + type=$(peers::get_type_from_ip "$ip") + + local subtype + subtype=$(peers::get_meta "$name" "subtype") local endpoint="—" - if peers::is_blocked "$name"; then + local is_blocked="false" + peers::is_blocked "$name" && is_blocked="true" + + if [[ "$is_blocked" == "true" ]]; then local ep ep=$(monitor::last_endpoint "$name") [[ -n "$ep" ]] && endpoint="$ep" @@ -252,22 +143,18 @@ function cmd::list::show_client() { [[ -n "$ep" ]] && endpoint="$ep" fi - # Get handshake and last attempt for status/last_seen local handshake_ts - handshake_ts=$(wg show "$(config::interface)" latest-handshakes 2>/dev/null \ - | grep "^${public_key}" | awk '{print $2}') - handshake_ts="${handshake_ts:-0}" + handshake_ts=$(monitor::get_handshake_ts "$public_key") local last_ts last_ts=$(monitor::last_attempt "$name") - local is_blocked="false" - peers::is_blocked "$name" && is_blocked="true" - - local status last_seen - status=$(cmd::list::_format_status "$name" "$public_key" \ + local status + status=$(peers::format_status "$name" "$public_key" \ "$is_blocked" "false" "$handshake_ts" "$last_ts") - last_seen=$(cmd::list::_format_last_seen "$name" "$public_key" \ + + local last_seen + last_seen=$(peers::format_last_seen "$name" "$public_key" \ "$is_blocked" "$last_ts" "" "$handshake_ts") local block_file @@ -286,13 +173,13 @@ function cmd::list::show_client() { fi ui::section "Client: ${name}" - ui::row "IP" "$ip" - ui::row "Type" "$type" - ui::row "Status" "$(echo -e "$status")" - ui::row "Endpoint" "$endpoint" - ui::row "Last seen" "$last_seen" - ui::row "AllowedIPs" "$allowed_ips" - ui::row "Public key" "$public_key" + ui::row "IP" "$ip" + ui::row "Type" "$(peers::display_type "$type" "$subtype")" + ui::row "Status" "$(echo -e "$status")" + ui::row "Endpoint" "$endpoint" + ui::row "Last seen" "$last_seen" + ui::row "AllowedIPs" "$allowed_ips" + ui::row "Public key" "$public_key" if [[ -z "$blocks" ]]; then ui::row "Blocks" "none" @@ -305,14 +192,6 @@ function cmd::list::show_client() { printf "\n" } -# Keep old format_status/format_last_seen for backward compat -function cmd::list::format_status() { cmd::list::_format_status "$@"; } -function cmd::list::format_last_seen() { cmd::list::_format_last_seen "$@"; } -function cmd::list::is_blocked() { peers::is_blocked "$1"; } -function cmd::list::is_restricted() { [[ -f "$(ctx::block::path "${1}.block")" ]]; } -function cmd::list::is_connected() { cmd::list::_is_connected "$@"; } -function cmd::list::is_attempting() { cmd::list::_is_attempting "$@"; } - # ============================================ # Run # ============================================ @@ -404,7 +283,7 @@ function cmd::list::_iter_confs() { ip=$(grep "^Address" "$conf" | awk '{print $3}' | cut -d'/' -f1) fi local type - type=$(peers::get_type "$ip") + type=$(peers::get_type_from_ip "$ip") [[ -n "$filter_type" && "$type" != "$filter_type" ]] && continue "$callback" "$client_name" "$ip" "$type" done @@ -420,8 +299,8 @@ function cmd::list::_render_row() { local last_ts="${p_last_ts[$client_name]:-}" # Apply status filters - if $online_only; then cmd::list::_is_connected "$handshake_ts" || return 0; fi - if $offline_only; then cmd::list::_is_connected "$handshake_ts" && return 0; fi + if $online_only; then peers::is_online "$client_name" "$handshake_ts" "$last_ts" || return 0; fi + if $offline_only; then peers::is_offline "$client_name" "$handshake_ts" "$last_ts" || return 0; fi if $restricted_only && [[ "$is_restricted" != "true" ]]; then return 0; fi if $blocked_only && [[ "$is_blocked" != "true" ]]; then return 0; fi if $allowed_only && { [[ "$is_blocked" == "true" ]] || \ @@ -434,12 +313,11 @@ function cmd::list::_render_row() { # Format display values local status last_seen display_type rule group_display - status=$(cmd::list::_format_status "$client_name" "$pubkey" \ + status=$(peers::format_status "$client_name" "$pubkey" \ "$is_blocked" "$is_restricted" "$handshake_ts" "$last_ts") - last_seen=$(cmd::list::_format_last_seen "$client_name" "$pubkey" \ + last_seen=$(peers::format_last_seen "$client_name" "$pubkey" \ "$is_blocked" "$last_ts" "" "$handshake_ts") - display_type=$(cmd::list::display_type "$client_name" "$type" \ - "${p_subtypes[$client_name]:-}") + display_type=$(peers::display_type "$type" "${p_subtypes[$client_name]:-}") rule="${p_rules[$client_name]:-—}" if [[ -n "$filter_rule" && "$rule" != "$filter_rule" ]]; then return 0; fi @@ -456,7 +334,7 @@ function cmd::list::_render_row() { # Pad status local padded_status - padded_status=$(cmd::list::pad_status "$status" 25) + padded_status=$(ui::pad_status "$status" 25) # Render row if $has_groups; then @@ -545,6 +423,15 @@ function cmd::list::_precompute_all() { [[ -n "$peer_name" ]] && peer_group_map["$peer_name"]="$group_name" done < <(json::peer_group_map "$groups_dir") fi + + # Transfer/activity data — keyed by pubkey + declare -gA p_rx=() p_tx=() p_activity=() + while IFS="|" read -r pubkey rx tx level; do + [[ -z "$pubkey" ]] && continue + p_rx["$pubkey"]="$rx" + p_tx["$pubkey"]="$tx" + p_activity["$pubkey"]="$level" + done < <(json::peer_transfer "$(config::interface)") } function cmd::list::_build_filter_desc() { diff --git a/commands/logs.command.sh b/commands/logs.command.sh index 5627740..8fa17c8 100644 --- a/commands/logs.command.sh +++ b/commands/logs.command.sh @@ -11,35 +11,51 @@ function cmd::logs::on_load() { flag::register --fw flag::register --wg flag::register --follow + flag::register --all + flag::register --before + flag::register --force } function cmd::logs::help() { cat < Filter by client name --type Filter by device type - --since