Implement iptables forward manager core

This commit is contained in:
2026-04-17 09:36:40 +08:00
parent d1a5392476
commit 28960eee03
20 changed files with 2047 additions and 0 deletions

View File

@@ -0,0 +1,109 @@
#!/usr/bin/env bash
set -euo pipefail
: "${IPTABLES_MOCK_DIR:=/tmp/iptables-mock}"
: "${IPTABLES_MOCK_LOG:=${IPTABLES_MOCK_DIR}/calls.log}"
mkdir -p "${IPTABLES_MOCK_DIR}"
touch "${IPTABLES_MOCK_LOG}"
base=$(basename -- "$0")
case ${base} in
iptables|iptables-save) family=4 ;;
ip6tables|ip6tables-save) family=6 ;;
*) family=${IPTABLES_MOCK_FAMILY:-4} ;;
esac
state_file="${IPTABLES_MOCK_DIR}/state.v${family}"
counter_file="${IPTABLES_MOCK_DIR}/add-counter"
touch "${state_file}" "${counter_file}"
serialize_args() {
local out=''
local arg
for arg in "$@"; do
out+="${arg}"$'\t'
done
printf '%s' "${out}"
}
line_key() {
local table=$1
local chain=$2
shift 2
printf '%s|%s|%s' "${table}" "${chain}" "$(serialize_args "$@")"
}
log_call() {
printf '%s %s\n' "${base}" "$*" >>"${IPTABLES_MOCK_LOG}"
}
load_rule_exists() {
local key=$1
grep -Fqx -- "${key}" "${state_file}"
}
save_emit() {
local table chain serialized
while IFS='|' read -r table chain serialized || [[ -n ${table:-} ]]; do
[[ -n ${table:-} ]] || continue
IFS=$'\t' read -r -a args <<<"${serialized}"
printf -- '-A %s' "${chain}"
local arg
for arg in "${args[@]}"; do
[[ -n ${arg} ]] || continue
printf ' %s' "${arg}"
done
printf '\n'
done <"${state_file}"
}
increment_add_counter() {
local count=0
count=$(cat "${counter_file}")
count=$((count + 1))
printf '%s\n' "${count}" >"${counter_file}"
printf '%s\n' "${count}"
}
if [[ ${base} == *save ]]; then
save_emit
exit 0
fi
log_call "$@"
table='filter'
if (($# >= 2)) && [[ $1 == -t ]]; then
table=$2
shift 2
fi
operation=${1-}
chain=${2-}
shift 2 || true
key=$(line_key "${table}" "${chain}" "$@")
case ${operation} in
-A)
current=$(increment_add_counter)
if [[ -n ${IPTABLES_MOCK_FAIL_ON_N:-} && ${current} == "${IPTABLES_MOCK_FAIL_ON_N}" ]]; then
exit 1
fi
printf '%s\n' "${key}" >>"${state_file}"
;;
-D)
if ! load_rule_exists "${key}"; then
exit 1
fi
grep -Fvx -- "${key}" "${state_file}" >"${state_file}.tmp" || true
mv "${state_file}.tmp" "${state_file}"
;;
-C)
load_rule_exists "${key}"
;;
*)
printf 'unsupported operation: %s\n' "${operation}" >&2
exit 2
;;
esac