Wren Linux

wren-linux / tools / test-ping.sh

#!/bin/bash
# Checks that this laptop doesn't answer pings (data/sysctl-hardening.conf):
# the file's ICMP settings are loaded into a network namespace of its own
# (unshare -rn, no sudo), where 127.0.0.1 and ::1 must stop answering. Without
# ping or user namespaces, only the file itself is checked.
# Run by test.sh, or:  bash tools/test-ping.sh
# shellcheck disable=SC2016  # the sh -c and eval lines expand their own variables
HERE=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
CONF=$HERE/data/sysctl-hardening.conf

fails=0
check() { # DESCRIPTION CONDITION-COMMAND...
    local what=$1
    shift
    if "$@" >/dev/null 2>&1; then printf '  ok    %s\n' "$what"; else printf '  FAIL  %s\n' "$what"; fails=$((fails + 1)); fi
}

check "pings over IPv4 go unanswered" grep -qxE 'net\.ipv4\.icmp_echo_ignore_all *= *1' "$CONF"
check "pings over IPv6 go unanswered" grep -qxE 'net\.ipv6\.icmp\.echo_ignore_all *= *1' "$CONF"

if ! command -v ping >/dev/null || ! unshare -rn true 2>/dev/null; then
    printf '  ok    skipped: no ping, or no user namespaces here, for the real check\n'
    exit $((fails > 0))
fi

# In the namespace: does loopback answer before, and after the file's ICMP
# settings? Prints one word per ping.
out=$(unshare -rn sh -c '
    ip link set lo up
    ping -c1 -W1 127.0.0.1 >/dev/null 2>&1 && echo v4-before
    grep -E "^net\.ipv[46]\.icmp" "$1" | while read -r key _ value; do
        echo "$value" > "/proc/sys/$(echo "$key" | tr . /)"
    done
    ping -c1 -W1 127.0.0.1 >/dev/null 2>&1 && echo v4-after
    ping -6 -c1 -W1 ::1 >/dev/null 2>&1 && echo v6-after
    exit 0' sh "$CONF" 2>&1)

check "a ping is answered without the settings (the check can see one)" grep -qx v4-before <<<"$out"
check "with the settings, 127.0.0.1 doesn't answer a ping" eval '! grep -qx v4-after <<<"$out"'
check "with the settings, ::1 doesn't answer a ping" eval '! grep -qx v6-after <<<"$out"'

exit $((fails > 0))