wgctl/commands/fw.command.sh

154 lines
No EOL
4.3 KiB
Bash

#!/usr/bin/env bash
# ============================================
# Lifecycle
# ============================================
function cmd::fw::on_load() {
flag::register --peer
flag::register --type
flag::register --no-nflog
flag::register --no-accept
flag::register --no-drop
}
function cmd::fw::run() {
local subcmd="${1:-list}"
# If first arg is a flag, default to list
if [[ "$subcmd" == --* ]]; then
subcmd="list"
else
shift || true
fi
case "$subcmd" in
list) cmd::fw::list "$@" ;;
nat) cmd::fw::nat "$@" ;;
flush-nat) cmd::fw::flush_nat "$@" ;;
clean) cmd::fw::clean ;;
count) cmd::fw::count ;;
help) cmd::fw::help ;;
*) log::error "Unknown subcommand: $subcmd"; return 1 ;;
esac
}
function cmd::fw::list() {
local peer="" type=""
local show_nflog=true show_accept=true show_drop=true
while [[ $# -gt 0 ]]; do
case "$1" in
--peer) peer="$2"; shift 2 ;;
--type) type="$2"; shift 2 ;;
--no-nflog) show_nflog=false; shift ;;
--no-accept) show_accept=false; shift ;;
--no-drop) show_drop=false; shift ;;
*) shift ;;
esac
done
log::section "Firewall Rules (FORWARD)"
printf "\n"
if [[ -n "$peer" ]]; then
local ip
ip=$(peers::get_ip "$peer")
[[ -z "$ip" ]] && log::error "Peer not found: $peer" && return 1
iptables -L FORWARD -n -v | grep -F "$ip" \
| cmd::fw::_print_filtered "$show_nflog" "$show_accept" "$show_drop"
elif [[ -n "$type" ]]; then
local subnet
subnet=$(config::subnet_for "$type")
[[ -z "$subnet" ]] && log::error "Unknown type: $type" && return 1
iptables -L FORWARD -n -v | grep -F "$subnet" \
| cmd::fw::_print_filtered "$show_nflog" "$show_accept" "$show_drop"
else
iptables -L FORWARD -n -v \
| grep -v "^Chain\|^target\|^$\|ACCEPT.*0\.0\.0\.0.*0\.0\.0\.0" \
| cmd::fw::_print_filtered "$show_nflog" "$show_accept" "$show_drop"
fi
printf "\n"
}
function cmd::fw::nat() {
log::section "NAT Rules (PREROUTING)"
printf "\n"
iptables -t nat -L PREROUTING -n -v | while IFS= read -r rule; do
[[ -z "$rule" ]] && continue
ui::firewall_rule "$rule"
done
printf "\n"
}
function cmd::fw::flush_nat() {
local type=""
while [[ $# -gt 0 ]]; do
case "$1" in
--type) type="$2"; shift 2 ;;
*) shift ;;
esac
done
if [[ -z "$type" ]]; then
log::error "Missing required flag: --type"
return 1
fi
local subnet
subnet=$(config::subnet_for "$type")
if [[ -z "$subnet" ]]; then
log::error "Unknown type: $type"
return 1
fi
local nat_linenums=()
while IFS= read -r linenum; do
[[ -n "$linenum" ]] && nat_linenums+=("$linenum")
done < <(iptables -t nat -L PREROUTING -n --line-numbers | grep -F "${subnet}" | awk '{print $1}')
local count=0
for (( i=${#nat_linenums[@]}-1; i>=0; i-- )); do
iptables -t nat -D PREROUTING "${nat_linenums[$i]}" 2>/dev/null || true
(( count++ )) || true
done
log::wg_success "Flushed ${count} NAT rules for type '${type}' (${subnet}.0/24)"
}
function cmd::fw::stats() {
log::section "Firewall Stats"
iptables -L FORWARD -n -v | grep -v "^Chain\|^target\|^$" | \
awk 'NR>1 {printf " %8s pkts %8s bytes %s\n", $1, $2, $0}'
}
function cmd::fw::count() {
log::section "Firewall Rule Counts"
local drop accept nflog total
drop=$(iptables -L FORWARD -n | grep -c "^DROP" || echo 0)
accept=$(iptables -L FORWARD -n | grep -c "^ACCEPT" || echo 0)
nflog=$(iptables -L FORWARD -n | grep -c "^NFLOG" || echo 0)
total=$(( drop + accept + nflog ))
printf "\n %-10s %s\n" "DROP:" "$drop"
printf " %-10s %s\n" "ACCEPT:" "$accept"
printf " %-10s %s\n" "NFLOG:" "$nflog"
printf " %-10s %s\n" "TOTAL:" "$total"
printf "\n"
}
function cmd::fw::clean() {
log::section "Duplicate Rule Report"
iptables-save | sort | uniq -d | grep "^-A FORWARD"
}
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
ui::firewall_rule "$rule"
done
}