Skip to content

Instantly share code, notes, and snippets.

@popmonkey
Created July 3, 2025 15:38
Show Gist options
  • Save popmonkey/b06f2b58f053a316c3de910ed2dae374 to your computer and use it in GitHub Desktop.
Save popmonkey/b06f2b58f053a316c3de910ed2dae374 to your computer and use it in GitHub Desktop.
generates routing policy to ensure network replies go across same interface when 2 are present
#!/bin/bash
# ====================================================================================
#
# Dual-Homed Policy-Based Routing Setup Script
#
# This script provides a general solution for a device connected to two
# networks simultaneously (e.g., eth0 and wlan0). It solves asymmetric
# routing problems by ensuring that network replies are always sent out
# of the same interface that the original request arrived on.
#
# What it does:
# 1. Prompts for the IP configuration of eth0 and wlan0.
# 2. Intelligently suggests default gateways and infers network addresses.
# 3. Creates a routing setup script in /usr/local/sbin/.
# 4. Creates a systemd service file to run the script on every boot.
# 5. Reloads, enables, and starts the new service.
#
# Usage:
# 1. Save this file as "install_dual_homed_routing.sh".
# 2. Make it executable: chmod +x install_dual_homed_routing.sh
# 3. Run it with sudo: sudo ./install_dual_homed_routing.sh
#
# ====================================================================================
# --- Sanity Check: Ensure the script is run as root ---
if [ "$(id -u)" -ne 0 ]; then
echo "This script must be run as root. Please use 'sudo'." >&2
exit 1
fi
echo "--- Dual-Homed Routing Installer ---"
echo "This script will configure your device to handle traffic correctly across two networks."
echo
# --- Gather Network Information from User ---
# For eth0
read -p "Enter the IP address for the eth0 interface: " ETH0_IP
ETH0_PREFIX=${ETH0_IP%.*}
ETH0_NETWORK="${ETH0_PREFIX}.0/24"
read -p "Enter the gateway IP for the eth0 network [${ETH0_PREFIX}.1]: " -i "${ETH0_PREFIX}.1" -e ETH0_GW
echo
# For wlan0
read -p "Enter the IP address for the wlan0 interface: " WLAN0_IP
WLAN0_PREFIX=${WLAN0_IP%.*}
WLAN0_NETWORK="${WLAN0_PREFIX}.0/24"
read -p "Enter the gateway IP for the wlan0 network [${WLAN0_PREFIX}.1]: " -i "${WLAN0_PREFIX}.1" -e WLAN0_GW
# --- Define File Paths and Table Names ---
ROUTING_SCRIPT_PATH="/usr/local/sbin/setup-routing.sh"
SERVICE_FILE_PATH="/etc/systemd/system/policy-routing.service"
ROUTING_TABLES_FILE="/etc/iproute2/rt_tables"
TABLE_ETH0="T1"
TABLE_WLAN0="T2"
# --- Step 1: Add Custom Routing Tables ---
echo
echo "--> Step 1: Adding custom routing tables..."
if ! grep -q "$TABLE_ETH0" "$ROUTING_TABLES_FILE"; then
echo -e "\n100 ${TABLE_ETH0}\n101 ${TABLE_WLAN0}" >> "$ROUTING_TABLES_FILE"
echo "Added routing tables '${TABLE_ETH0}' and '${TABLE_WLAN0}'."
else
echo "Routing tables already exist."
fi
# --- Step 2: Create the Routing Setup Script ---
echo "--> Step 2: Creating the routing script at $ROUTING_SCRIPT_PATH..."
cat << EOF > "$ROUTING_SCRIPT_PATH"
#!/bin/bash
# This script is auto-generated. Do not edit directly.
# Wait for network interfaces to be fully ready
sleep 15
# Flush existing tables to ensure a clean state
ip route flush table ${TABLE_ETH0}
ip route flush table ${TABLE_WLAN0}
# --- Configure table for eth0 ---
# Route for the local subnet
ip route add ${ETH0_NETWORK} dev eth0 table ${TABLE_ETH0}
# Default route for all other traffic
ip route add default via ${ETH0_GW} dev eth0 table ${TABLE_ETH0}
# --- Configure table for wlan0 ---
# Route for the local subnet
ip route add ${WLAN0_NETWORK} dev wlan0 table ${TABLE_WLAN0}
# Default route for all other traffic
ip route add default via ${WLAN0_GW} dev wlan0 table ${TABLE_WLAN0}
# Flush the route cache
ip route flush cache
# --- Create the rules ---
# Delete old rules if they exist to prevent duplicates
ip rule del from ${ETH0_IP} table ${TABLE_ETH0} &>/dev/null
ip rule del from ${WLAN0_IP} table ${TABLE_WLAN0} &>/dev/null
# Add new rules: any traffic originating from a specific IP uses the corresponding table
ip rule add from ${ETH0_IP} table ${TABLE_ETH0}
ip rule add from ${WLAN0_IP} table ${TABLE_WLAN0}
EOF
# Make the script executable
chmod +x "$ROUTING_SCRIPT_PATH"
echo "Routing script created successfully."
# --- Step 3: Create the systemd Service File ---
echo "--> Step 3: Creating the systemd service at $SERVICE_FILE_PATH..."
cat << EOF > "$SERVICE_FILE_PATH"
[Unit]
Description=Policy-Based Routing for Dual-Homed Interfaces
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=$ROUTING_SCRIPT_PATH
[Install]
WantedBy=multi-user.target
EOF
echo "Systemd service file created successfully."
# --- Step 4: Enable and Start the Service ---
echo "--> Step 4: Reloading systemd and starting the service..."
systemctl daemon-reload
systemctl enable --now policy-routing.service
# --- Final Check ---
# For oneshot services, we check the result of the last run, not if it is currently "active".
echo
SERVICE_RESULT=$(systemctl show policy-routing.service -p Result --value)
if [ "$SERVICE_RESULT" == "success" ]; then
echo "✅ Success! Policy-based routing is now active and enabled on boot."
else
echo "❌ Error! The policy-routing service failed." >&2
echo "Result: $SERVICE_RESULT" >&2
echo "Please check the status with: systemctl status policy-routing.service" >&2
exit 1
fi
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment