diff --git a/ipfn1.0 b/ipfn1.0 index 4633835..b536d74 100755 --- a/ipfn1.0 +++ b/ipfn1.0 @@ -1,8 +1,7 @@ #!/bin/bash # Name: ipfn -# Version: 1.0.9 +# Version: 1.1.0 # Date: 2026-01-22 -# Description: Supports range deletion (e.g., -d 80-85) and complex handle lists. if [ "$(id -u)" -ne 0 ]; then exec sudo "$0" "$@" @@ -41,99 +40,112 @@ list_rules() { done } -perform_delete() { - local handle=$1 - local rule_info=$(nft -a list chain inet ${TABLE_NAME} prerouting | grep "handle $handle") - [[ -z "$rule_info" ]] && return # 存在しないハンドルは静かにスルー - local uuid=$(echo "$rule_info" | grep -o 'ipf-id:[a-z0-9-]*' | head -n 1) - for chain in prerouting output forward postrouting; do - nft -a list chain inet ${TABLE_NAME} "$chain" | grep "$uuid" | grep -o 'handle [0-9]*' | awk '{print $2}' | while read -r h; do - nft delete rule inet ${TABLE_NAME} "$chain" handle "$h" - done - done - echo "ipfn: Handle $handle deleted." -} - -# --- メインパース部分の強化 --- -parse_handles() { - local input=$1 - local -a result=() - # カンマで分割 - IFS=',' read -r -a parts <<< "$input" - for part in "${parts[@]}"; do - if [[ "$part" =~ ^([0-9]+)-([0-9]+)$ ]]; then - # 範囲指定 (start-end) の処理 - start=${BASH_REMATCH[1]} - end=${BASH_REMATCH[2]} - for ((i=start; i<=end; i++)); do result+=("$i"); done - else - # 単一指定 - result+=("$part") - fi - done - echo "${result[@]}" -} - -# (add_rule, test_rule_by_port は前バージョンと同じ) test_rule_by_port() { local lp=$1 echo -n "Testing connectivity to :$lp... " - if nc -z -v -w 2 127.0.0.1 "$lp" 2>&1 | grep -E "succeeded|connected|open" >/dev/null; then + if nc -z -v -w 2 127.0.0.1 "$lp" 2>&1 | grep -iqE "succeeded|connected|open"; then echo -e "\e[32mOK\e[0m" else echo -e "\e[31mFAILED\e[0m" fi } +get_port_by_handle() { + local h=$1 + nft -a list chain inet ${TABLE_NAME} prerouting | grep "handle $h" | grep -o 'dport [0-9]*' | awk '{print $2}' +} + +parse_handles() { + local input=$1 + local -a result=() + IFS=',' read -r -a parts <<< "$input" + for part in "${parts[@]}"; do + if [[ "$part" =~ ^([0-9]+)-([0-9]+)$ ]]; then + for ((i=${BASH_REMATCH[1]}; i<=${BASH_REMATCH[2]}; i++)); do result+=("$i"); done + else + result+=("$part") + fi + done + echo "${result[@]}" +} + add_rule() { init_nft - local port_ip_port=$1 - local lp=$(echo "$port_ip_port" | cut -d':' -f1) - local tip=$(echo "$port_ip_port" | cut -d':' -f2) - local tp=$(echo "$port_ip_port" | cut -d':' -f3) - [[ -n "$lp" ]] && nft list chain inet ${TABLE_NAME} prerouting | grep -q "dport $lp" && echo -e "\e[33mWarning: Port :$lp is already in use.\e[0m" + local lp=$(echo "$1" | cut -d':' -f1) + local tip=$(echo "$1" | cut -d':' -f2) + local tp=$(echo "$1" | cut -d':' -f3) + nft list chain inet ${TABLE_NAME} prerouting | grep -q "dport $lp" && echo -e "\e[33mWarning: Port :$lp is already in use.\e[0m" local raw_uuid=$(cat /proc/sys/kernel/random/uuid) local uuid="ipf-id:$raw_uuid" - local comment="comment \"$uuid\"" local family="ip"; [[ "$tip" =~ : ]] && family="ip6" - nft add rule inet ${TABLE_NAME} prerouting "$PROTO" dport "$lp" dnat $family to "$tip:$tp" "$comment" - nft add rule inet ${TABLE_NAME} output "$PROTO" dport "$lp" dnat $family to "$tip:$tp" "$comment" - nft add rule inet ${TABLE_NAME} forward iifname "lo" accept "$comment" - nft add rule inet ${TABLE_NAME} forward $family daddr "$tip" "$PROTO" dport "$tp" ct state new,established,related accept "$comment" - nft add rule inet ${TABLE_NAME} forward $family saddr "$tip" "$PROTO" sport "$tp" ct state established,related accept "$comment" - nft add rule inet ${TABLE_NAME} postrouting $family daddr "$tip" "$PROTO" dport "$tp" masquerade "$comment" - echo "ipfn: Rule added."; echo ""; list_rules "$raw_uuid" + nft add rule inet ${TABLE_NAME} prerouting "$PROTO" dport "$lp" dnat $family to "$tip:$tp" comment "\"$uuid\"" + nft add rule inet ${TABLE_NAME} output "$PROTO" dport "$lp" dnat $family to "$tip:$tp" comment "\"$uuid\"" + nft add rule inet ${TABLE_NAME} forward iifname "lo" accept comment "\"$uuid\"" + nft add rule inet ${TABLE_NAME} forward $family daddr "$tip" "$PROTO" dport "$tp" ct state new,established,related accept comment "\"$uuid\"" + nft add rule inet ${TABLE_NAME} forward $family saddr "$tip" "$PROTO" sport "$tp" ct state established,related accept comment "\"$uuid\"" + nft add rule inet ${TABLE_NAME} postrouting $family daddr "$tip" "$PROTO" dport "$tp" masquerade comment "\"$uuid\"" + list_rules "$raw_uuid" [[ "$SKIP_TEST" == false ]] && { echo ""; test_rule_by_port "$lp"; } } -for arg in "$@"; do [[ "$arg" == "-f" ]] && FORCE_FLAG=true && SKIP_TEST=true; done +# --- メインロジック --- if [[ $# -eq 0 ]]; then list_rules; exit 0; fi +# フラグ先読み +for arg in "$@"; do + [[ "$arg" == "-f" ]] && FORCE_FLAG=true && SKIP_TEST=true +done + while [[ $# -gt 0 ]]; do case "$1" in -L|-l) list_rules; exit 0 ;; -df*|-d*) [[ "$1" == -df* ]] && FORCE_FLAG=true - raw_h="${1#-df}"; raw_h="${raw_h#-d}" - [[ -z "$raw_h" ]] && { raw_h="$2"; shift; } - - # 範囲指定を含むハンドルリストを解析 - handles=($(parse_handles "$raw_h")) - + h_str="${1#-df}"; h_str="${h_str#-d}" + [[ -z "$h_str" ]] && { h_str="$2"; shift; } + handles=($(parse_handles "$h_str")) if [[ "$FORCE_FLAG" == false ]]; then echo "Review handles to delete:" - for h in "${handles[@]}"; do - rule=$(nft -a list chain inet ${TABLE_NAME} prerouting | grep "handle $h") - [[ -n "$rule" ]] && echo " $rule" - done - echo -n "Delete these rules? (y/N): " - read -r confirm - [[ ! "$confirm" =~ ^[yY]$ ]] && { echo "Aborted."; exit 0; } + for h in "${handles[@]}"; do nft -a list table inet ${TABLE_NAME} | grep "handle $h" | sed 's/^/ /'; done + read -p "Delete these rules? (y/N): " confirm + [[ ! "$confirm" =~ ^[yY]$ ]] && exit 0 fi - for h in "${handles[@]}"; do perform_delete "$h"; done + for h in "${handles[@]}"; do + rule_info=$(nft -a list chain inet ${TABLE_NAME} prerouting | grep "handle $h") + [[ -z "$rule_info" ]] && continue + uuid=$(echo "$rule_info" | grep -o 'ipf-id:[a-z0-9-]*' | head -n 1) + for c in prerouting output forward postrouting; do + nft -a list chain inet ${TABLE_NAME} "$c" | grep "$uuid" | grep -o 'handle [0-9]*' | awk '{print $2}' | while read -r rh; do + nft delete rule inet ${TABLE_NAME} "$c" handle "$rh" + done + done + echo "Handle $h deleted." + done echo ""; list_rules; exit 0 ;; - -f) [[ $# -eq 1 ]] && { sysctl -w net.ipv4.ip_forward=1 >/dev/null; sysctl -w net.ipv4.conf.all.route_localnet=1 >/dev/null; echo "Kernel parameters updated."; exit 0; } ;; - *) [[ "$1" =~ ^[0-9]+: ]] && { add_rule "$1"; exit 0; } ;; + -t*) + h_str="${1#-t}" + if [[ -z "$h_str" && ( "$2" =~ ^[0-9,-]+$ ) ]]; then h_str="$2"; shift; fi + + if [[ -z "$h_str" ]]; then + # ハンドル指定がない場合、ルールが1つならそれを採用 + count=$(nft list chain inet ${TABLE_NAME} prerouting | grep -c "dnat") + if [ "$count" -eq 1 ]; then + h_str=$(nft -a list chain inet ${TABLE_NAME} prerouting | grep "handle" | awk '{print $NF}') + else + echo "Error: Multiple rules exist. Specify a handle."; exit 1 + fi + fi + lp=$(get_port_by_handle "$h_str") + [[ -n "$lp" ]] && test_rule_by_port "$lp" || echo "Error: Handle $h_str not found." + exit 0 ;; + -f) + if [[ $# -eq 1 ]]; then + sysctl -w net.ipv4.ip_forward=1 >/dev/null + sysctl -w net.ipv4.conf.all.route_localnet=1 >/dev/null + echo "Kernel parameters updated."; exit 0 + fi ;; + *) + if [[ "$1" =~ ^[0-9]+: ]]; then add_rule "$1"; exit 0; fi ;; esac shift done