Created
July 3, 2025 15:38
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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