The repo was committed from WSL with core.filemode=false, so the exec bit was never recorded. After actions/checkout the entry script comes down as 100644 and tests/test_cli.sh fails with Permission denied. Set mode 100755 on every script that is invoked directly (entry, installer, test suite, mock binaries). Sourced helpers under lib/ keep 100644 per convention. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
110 lines
2.2 KiB
Bash
Executable File
110 lines
2.2 KiB
Bash
Executable File
#!/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
|