Why Kernel Hardening Matters
The Linux kernel's default network settings are optimized for maximum compatibility, not security. They accept ICMP redirects (which can be used for man-in-the-middle attacks), don't validate source IPs (allowing IP spoofing), and have permissive SYN flood handling.
These defaults made sense in the 1990s when the priority was getting networking to work at all. In a homelab where you control every host, you can lock these down without breaking anything.
The settings in this guide are the same ones recommended by CIS Benchmarks, STIG, and most Linux hardening guides. They're non-controversial, well-tested, and safe to apply on any server that isn't doing something exotic with its network stack.
Step 1: Check Current Values
Before making changes, see what your kernel is currently doing. This gives you a baseline and tells you if any of these are already set:
echo '=== IP Spoofing Protection ===' && sysctl net.ipv4.conf.all.rp_filter && sysctl net.ipv4.conf.default.rp_filter && echo '' && echo '=== ICMP Redirects ===' && sysctl net.ipv4.conf.all.accept_redirects && sysctl net.ipv4.conf.all.send_redirects && echo '' && echo '=== SYN Flood Protection ===' && sysctl net.ipv4.tcp_syncookies && echo '' && echo '=== ICMP Broadcast ===' && sysctl net.ipv4.icmp_echo_ignore_broadcasts && echo '' && echo '=== Martian Logging ===' && sysctl net.ipv4.conf.all.log_martiansInterpret the Defaults
On a fresh Ubuntu/Debian install, you'll typically see:
rp_filter = 2 (loose mode — some protection but allows asymmetric routes)
accept_redirects = 1 (ENABLED — accepts ICMP redirects)
send_redirects = 1 (ENABLED — sends ICMP redirects)
tcp_syncookies = 1 (usually already enabled — good)
icmp_echo_ignore_broadcasts = 1 (usually already enabled — good)
log_martians = 0 (DISABLED — doesn't log suspicious packets)
We're going to tighten all of these.
Step 2: Create the Hardening Config
Drop a single config file into /etc/sysctl.d/. Files in this directory are loaded automatically on boot, in alphabetical order. The 99- prefix ensures our settings are applied last and override any earlier configs:
sudo tee /etc/sysctl.d/99-hardening.conf << 'EOF'
# ===========================================
# Kernel Network Hardening — Online Ingenuity
# Apply to every VM as a baseline.
# ===========================================
# --- IP Spoofing Protection ---
# Strict reverse path filtering: drop packets where the source IP
# wouldn't route back through the same interface they arrived on.
# This prevents IP spoofing attacks.
# Use "1" (strict) unless you have asymmetric routing, then use "2" (loose).
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# --- Block ICMP Redirects ---
# ICMP redirects tell a host to use a different gateway. Legitimate on
# complex networks, but on a flat homelab LAN they're only useful for
# man-in-the-middle attacks. Disable sending and accepting.
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
# Also block IPv6 ICMP redirects (if IPv6 is still enabled)
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
# --- Ignore ICMP Redirects Sent to Routed Subnets ---
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
# --- SYN Flood Protection ---
# Enable SYN cookies: when the SYN backlog is full, the kernel uses
# cryptographic cookies instead of allocating state. This prevents
# SYN flood attacks from exhausting connection tracking.
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
# --- Ignore ICMP Broadcast Requests ---
# Prevents the machine from being used in a Smurf amplification attack.
# Someone sends a ping to your broadcast address, and every host replies.
net.ipv4.icmp_echo_ignore_broadcasts = 1
# --- Ignore Bogus ICMP Error Responses ---
# Some routers send invalid ICMP error messages. Ignoring them prevents
# log spam and potential exploits.
net.ipv4.icmp_ignore_bogus_error_responses = 1
# --- Log Martian Packets ---
# Log packets with impossible source addresses (like packets from
# 192.168.1.x arriving on a WAN interface). Useful for detecting
# misconfigurations or attacks.
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
# --- Disable Source Routing ---
# Source-routed packets specify their own route through the network.
# Almost never legitimate, commonly used in attacks.
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
EOFStep 3: Apply the Settings
Load all sysctl configs without rebooting:
sudo sysctl --system 2>&1 | grep -E '(rp_filter|redirect|syncookies|martians|source_route|broadcasts)' | sort -uValidate: What You Should See
You should see each setting listed with its value:
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.all.send_redirects = 0
net.ipv4.tcp_syncookies = 1
...
If any setting shows an error, it's likely because the kernel parameter doesn't exist on your system (possible on very old or custom kernels). Those lines can be safely commented out in the config file.
Step 4: Verify Specific Settings
Double-check the most critical settings are active:
echo '--- Spoofing Protection ---' && sysctl net.ipv4.conf.all.rp_filter && echo '--- ICMP Redirects ---' && sysctl net.ipv4.conf.all.accept_redirects && sysctl net.ipv4.conf.all.send_redirects && echo '--- SYN Cookies ---' && sysctl net.ipv4.tcp_syncookies && echo '--- Martian Logging ---' && sysctl net.ipv4.conf.all.log_martians && echo '--- Source Routing ---' && sysctl net.ipv4.conf.all.accept_source_routeExpected Output
Every value should match:
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.all.accept_source_route = 0
If any value is wrong, another config file in /etc/sysctl.d/ may be overriding ours. Check:
grep -r 'rp_filter\|accept_redirects' /etc/sysctl.d/ /etc/sysctl.conf
Our file is 99-, so it should override anything with a lower number. If not, rename it to zz-hardening.conf.
Step 5: Test Persistence
Verify the config file exists and will be loaded on next boot:
cat /etc/sysctl.d/99-hardening.conf | head -5 && echo '...' && wc -l /etc/sysctl.d/99-hardening.confDocker and Kubernetes Compatibility
Docker and Kubernetes may set their own sysctl values for container networking. Our settings are safe with Docker's default bridge networking.
Known considerations:
- rp_filter = 1 (strict) can cause issues with Docker Swarm overlay networks or Kubernetes pod networking that uses asymmetric routes. If you're running either, use rp_filter = 2 (loose mode) instead.
- Docker sets its own values on the docker0 and br-* interfaces. Our settings apply to "all" and "default" which covers new interfaces, but Docker may override on its own.
- If you notice container networking issues after applying these settings, check: sysctl -a | grep docker
Deploy to All VMs With Ansible (Optional)
If you manage multiple VMs, copy this config to all of them at once:
# In your Ansible playbook:
- name: Deploy sysctl hardening
copy:
src: files/99-hardening.conf
dest: /etc/sysctl.d/99-hardening.conf
owner: root
group: root
mode: '0644'
notify: reload sysctl
handlers:
- name: reload sysctl
command: sysctl --system
Copy the config file from this server to use as the Ansible source:
scp /etc/sysctl.d/99-hardening.conf your-ansible-host:roles/baseline/files/
How to Undo Everything
To revert to default kernel settings:
1. Remove the config file:
sudo rm /etc/sysctl.d/99-hardening.conf
2. Reload sysctl to apply defaults:
sudo sysctl --system
3. Verify defaults are restored:
sysctl net.ipv4.conf.all.accept_redirects
# Should return 1 (the default)
Or to selectively undo a single setting, comment out that line in the config file and reload:
sudo sysctl --system