Files
kubernetes/riscv/kubernetes/iptables-detect.sh
2025-11-23 18:58:51 +01:00

252 lines
7.8 KiB
Bash
Executable File

#!/bin/sh
# Copyright 2019 The Kubernetes Authors.
# Copyright 2020 Rancher Labs
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This script is only meant for use when operating in a non-containerized
# environment but using non-host binaries (i.e. K3s with k3s-root), but
# will fall back to operating in a containerized environment if necessary.
# It relies on the underlying host system not having cgroups set up for PID
# 1, as this is how it detects whether it is operating in a containerized
# environment or not.
# Four step process to inspect for which version of iptables we're operating
# with.
# 1. Detect whether we are operating in a containerized environment by inspecting cgroups for PID 1.
# 2. Run iptables-nft-save and iptables-legacy-save to inspect for rules. If
# no rules are found from either binaries, then
# 3. Check /etc/alternatives/iptables on the host to see if there is a symlink
# pointing towards the iptables binary we are using, if there is, run the
# binary and grep it's output for version higher than 1.8 and "legacy" to see
# if we are operating in legacy
# 4. Last chance is to do a rough check of the operating system, to make an
# educated guess at which mode we can operate in.
# Bugs in iptables-nft 1.8.3 may cause it to get stuck in a loop in
# some circumstances, so we have to run the nft check in a timeout. To
# avoid hitting that timeout, we only bother to even check nft if
# legacy iptables was empty / mostly empty.
mode=unknown
detected_via=unknown
containerized=false
# Check to see if the nf_tables kernel module is loaded, if it is, we should operate in nft mode, else just fall back to legacy. This should only be run when in a container, ideally the klipper-lb container.
nft_module_check() {
lsmod | grep "nf_tables" 2> /dev/null
if [ $? = 0 ]; then
detected_via=modules
mode=nft
else
detected_via=modules
mode=legacy
fi
}
# Check to see if we are containerized -- essentially look at the cgroup for PID 1 and check for things at the end of the "/" which indicates we are in a container (PID 1 shouldn't necessarily have a cgroup)
# there are two cases when we are containerized -- k3d and things that aren't k3s
is_containerized() {
CGT=$(cat /proc/1/cgroup | grep "cpuset" | awk -F: '{print $3}' | sed 's/\///g');
if [ -z $CGT ]; then
containerized=false
else
containerized=true
fi
}
rule_check() {
num_legacy_lines=$( (
iptables-legacy-save || true
ip6tables-legacy-save || true
) 2>/dev/null | grep '^-' | wc -l)
if [ "${num_legacy_lines}" -ge 10 ]; then
detected_via=rules
mode=legacy
else
num_nft_lines=$( (timeout 5 sh -c "iptables-nft-save; ip6tables-nft-save" || true) 2>/dev/null | grep '^-' | wc -l)
if [ "${num_legacy_lines}" -gt "${num_nft_lines}" ]; then
detected_via=rules
mode=legacy
elif [ "${num_nft_lines}" = 0 ]; then
mode=unknown
else
detected_via=rules
mode=nft
fi
fi
}
alternatives_check() {
readlink /etc/alternatives/iptables >/dev/null
if [ $? = 0 ]; then
readlink /etc/alternatives/iptables | grep -q "nft"
if [ $? = 0 ]; then
detected_via=alternatives
mode=nft
else
detected_via=alternatives
mode=legacy
fi
fi
}
# we should not run os-detect if we're being run inside of a container
os_detect() {
# perform some very rudimentary platform detection
lsb_dist=''
dist_version=''
if [ -z "$lsb_dist" ] && [ -r /etc/lsb-release ]; then
lsb_dist="$(. /etc/lsb-release && echo "$DISTRIB_ID")"
fi
if [ -z "$lsb_dist" ] && [ -r /etc/debian_version ]; then
lsb_dist='debian'
fi
if [ -z "$lsb_dist" ] && [ -r /etc/fedora-release ]; then
lsb_dist='fedora'
fi
if [ -z "$lsb_dist" ] && [ -r /etc/oracle-release ]; then
lsb_dist='oracleserver'
fi
if [ -z "$lsb_dist" ] && [ -r /etc/centos-release ]; then
lsb_dist='centos'
fi
if [ -z "$lsb_dist" ] && [ -r /etc/redhat-release ]; then
lsb_dist='redhat'
fi
if [ -z "$lsb_dist" ] && [ -r /etc/os-release ]; then
lsb_dist="$(. /etc/os-release && echo "$ID")"
fi
lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')"
# Special case redhatenterpriseserver
if [ "${lsb_dist}" = "redhatenterpriseserver" ]; then
# Set it to redhat, it will be changed to centos below anyways
lsb_dist='redhat'
fi
case "$lsb_dist" in
alpine)
# Alpine is using iptables-legacy by default when you apk add iptables. There exists a iptables-nft subset of commands but they are not
# used by default.
detected_via=os
mode=legacy
;;
ubuntu)
# By default, Ubuntu is using iptables in legacy mode. Ideally, this should have been already caught by the alternatives check.
detected_via=os
mode=legacy
;;
debian | raspbian)
dist_version="$(cat /etc/debian_version | sed 's/\/.*//' | sed 's/\..*//')"
# If Debian >= 10 (Buster is 10), then NFT. otherwise, assume it is legacy
if [ "$dist_version" -ge 10 ]; then
detected_via=os
mode=nft
else
detected_via=os
mode=legacy
fi
;;
oracleserver)
dist_version="$(. /etc/os-release && echo "$VERSION_ID")"
maj_ver=$(echo $dist_version | sed -E -e "s/^([0-9]+)\.?[0-9]*$/\1/")
if [ "$maj_ver" -ge 8 ]; then
detected_via=os
mode=nft
else
detected_via=os
mode=legacy
fi
;;
fedora)
# As of 05/15/2020, all Fedora packages appeared to be still `legacy` by default although there is a `iptables-nft` package that installs the nft iptables, so look for that package.
rpm -qa | grep -q "iptables-nft"
if [ $? = 0 ]; then
detected_via=os
mode=nft
else
detected_via=os
mode=legacy
fi
;;
centos | redhat)
dist_version="$(. /etc/os-release && echo "$VERSION_ID")"
maj_ver=$(echo $dist_version | sed -E -e "s/^([0-9]+)\.?[0-9]*$/\1/")
if [ "$maj_ver" -ge 8 ]; then
detected_via=os
mode=nft
else
detected_via=os
mode=legacy
fi
;;
# We are running an operating system we don't know, default to nf_tables.
*)
detected_via=unknownos
mode=nft
;;
esac
}
if [ ! -z "$IPTABLES_MODE" ]; then
mode=${IPTABLES_MODE}
else
rule_check
if [ "${mode}" = "unknown" ]; then
is_containerized
# If we're containerized, then just fall back to legacy, in hopes `ip_tables` is loaded.
if [ "${containerized}" = "true" ]; then
mode=legacy
else
alternatives_check
if [ "${mode}" = "unknown" ]; then
os_detect
fi
fi
fi
fi
if [ "${mode}" = "unknown" ]; then
exit 1
fi
if [ "$(basename $0)" = "iptables-detect.sh" ]; then
echo mode is $mode detected via $detected_via and containerized is $containerized
exit 0
fi
xtables-set-mode.sh -m ${mode} >/dev/null
if [ $? = 0 ]; then
exec "$0" "$@"
else
exit 1
fi