#!/usr/bin/env bash # Create transparent bridge between two interfaces # Usage: setup_bridge.sh # No IP assigned — invisible on network # # This script creates a Layer 2 bridge for inline packet capture and # 802.1X bypass. The bridge has NO IP address, making it undetectable # via network scanning. STP/BPDU/CDP/LLDP frames are suppressed via # ebtables to avoid triggering network monitoring systems. set -euo pipefail BRIDGE="br0" # -------------------------------------------------------------------------- # Validate arguments # -------------------------------------------------------------------------- if [[ $# -ne 2 ]]; then echo "Usage: $0 " >&2 exit 1 fi IF1="$1" IF2="$2" # Verify interfaces exist for iface in "$IF1" "$IF2"; do if ! ip link show "$iface" &>/dev/null; then echo "Error: interface $iface does not exist" >&2 exit 1 fi done # -------------------------------------------------------------------------- # Cleanup any existing bridge # -------------------------------------------------------------------------- if ip link show "$BRIDGE" &>/dev/null; then echo "Removing existing bridge $BRIDGE" ip link set down dev "$BRIDGE" 2>/dev/null || true ip link del "$BRIDGE" 2>/dev/null || true fi # -------------------------------------------------------------------------- # Create bridge # -------------------------------------------------------------------------- echo "Creating bridge $BRIDGE: $IF1 <-> $IF2" # Create the bridge device ip link add name "$BRIDGE" type bridge # Disable Spanning Tree Protocol ip link set "$BRIDGE" type bridge stp_state 0 # Zero forwarding delay — start forwarding immediately ip link set "$BRIDGE" type bridge forward_delay 0 # Disable ageing to keep all MACs in forwarding table ip link set "$BRIDGE" type bridge ageing_time 0 # -------------------------------------------------------------------------- # Configure interfaces # -------------------------------------------------------------------------- # Flush any existing IP addresses — bridge must have no L3 presence ip addr flush dev "$IF1" 2>/dev/null || true ip addr flush dev "$IF2" 2>/dev/null || true # Set promiscuous mode — capture all frames ip link set "$IF1" promisc on ip link set "$IF2" promisc on # Disable multicast snooping (avoid IGMP interference) echo 0 > /sys/devices/virtual/net/"$BRIDGE"/bridge/multicast_snooping 2>/dev/null || true # Add interfaces to bridge ip link set "$IF1" master "$BRIDGE" ip link set "$IF2" master "$BRIDGE" # Bring everything up ip link set up dev "$IF1" ip link set up dev "$IF2" ip link set up dev "$BRIDGE" # Ensure bridge has NO IP address ip addr flush dev "$BRIDGE" 2>/dev/null || true # -------------------------------------------------------------------------- # ebtables rules — suppress discovery protocols # -------------------------------------------------------------------------- # Check if ebtables is available if command -v ebtables &>/dev/null; then echo "Applying ebtables suppression rules" # Flush existing rules ebtables -F 2>/dev/null || true # STP/BPDU — 01:80:C2:00:00:00 ebtables -A FORWARD -d 01:80:C2:00:00:00 -j DROP ebtables -A OUTPUT -d 01:80:C2:00:00:00 -j DROP # CDP/VTP — 01:00:0C:CC:CC:CC ebtables -A FORWARD -d 01:00:0C:CC:CC:CC -j DROP ebtables -A OUTPUT -d 01:00:0C:CC:CC:CC -j DROP # LLDP — 01:80:C2:00:00:0E ebtables -A FORWARD -d 01:80:C2:00:00:0E -j DROP ebtables -A OUTPUT -d 01:80:C2:00:00:0E -j DROP # Cisco PVST+ — 01:00:0C:CC:CC:CD ebtables -A FORWARD -d 01:00:0C:CC:CC:CD -j DROP ebtables -A OUTPUT -d 01:00:0C:CC:CC:CD -j DROP # LLDP alternate — 01:80:C2:00:00:03 ebtables -A FORWARD -d 01:80:C2:00:00:03 -j DROP ebtables -A OUTPUT -d 01:80:C2:00:00:03 -j DROP # 802.1X EAP passthrough — allow EAP frames across the bridge # (default FORWARD policy is ACCEPT, so EAP frames pass unless # we explicitly blocked them above — we only block management protos) else echo "Warning: ebtables not installed — protocol suppression skipped" >&2 fi # -------------------------------------------------------------------------- # Disable IPv6 on bridge (prevent RA/NS/NA leakage) # -------------------------------------------------------------------------- sysctl -qw "net.ipv6.conf.${BRIDGE}.disable_ipv6=1" 2>/dev/null || true sysctl -qw "net.ipv6.conf.${IF1}.disable_ipv6=1" 2>/dev/null || true sysctl -qw "net.ipv6.conf.${IF2}.disable_ipv6=1" 2>/dev/null || true # -------------------------------------------------------------------------- # Verify bridge is active # -------------------------------------------------------------------------- if ip link show "$BRIDGE" | grep -q "state UP"; then echo "Bridge $BRIDGE is UP: $IF1 <-> $IF2 (no IP, STP disabled)" bridge link show exit 0 else echo "Error: bridge $BRIDGE failed to come up" >&2 exit 1 fi