Marcus Penate 141ac1c9dd Initial commit: DHCP whitelist service for direct link connections
Features:
- Docker-based DHCP server with MAC address whitelisting
- Binds to specific ethernet interface only
- NO DNS/gateway advertised (direct link only, not a router)
- Configurable network parameters (subnet, DHCP range, lease times)
- Systemd service integration for Arch/Manjaro
- Test environment with isolated network (172.20.0.0/24)
- Auto-configuration script to detect network settings
- Complete Makefile with management targets

Security:
- Only responds to whitelisted MAC addresses
- deny unknown-clients configuration
- Runs in Docker container for isolation

Configuration:
- Copy .example files to create your config
- interface.conf: Network interface to bind to
- whitelist.conf: Allowed MAC addresses
- network.conf: Network parameters (optional)
2025-08-27 20:46:29 -04:00

155 lines
4.8 KiB
Bash
Executable File

#!/bin/bash
set -e
CONFIG_DIR="./config"
INTERFACE_CONF="${CONFIG_DIR}/interface.conf"
WHITELIST_CONF="${CONFIG_DIR}/whitelist.conf"
NETWORK_CONF="${CONFIG_DIR}/network.conf"
echo "=== DHCP Whitelist Auto-Configuration ==="
echo
# Create config directory if it doesn't exist
mkdir -p "${CONFIG_DIR}"
# Find ethernet interfaces (excluding loopback and virtual interfaces)
echo "Detecting ethernet interfaces..."
INTERFACES=$(ip link show | grep -E "^[0-9]+: en" | awk -F': ' '{print $2}' | head -1)
if [ -z "$INTERFACES" ]; then
echo "Error: No ethernet interface found"
echo "Please configure manually by editing ${INTERFACE_CONF}"
exit 1
fi
echo "Found ethernet interface: $INTERFACES"
# Get the interface with an IP in 192.168.x.x range (common for local networks)
SELECTED_INTERFACE=""
for IFACE in $INTERFACES; do
IP_INFO=$(ip -4 addr show "$IFACE" 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' || true)
if [ -n "$IP_INFO" ]; then
echo " Interface $IFACE has IP: $IP_INFO"
if [[ "$IP_INFO" =~ ^192\.168\. ]] || [[ "$IP_INFO" =~ ^10\. ]] || [[ "$IP_INFO" =~ ^172\. ]]; then
SELECTED_INTERFACE="$IFACE"
break
fi
fi
done
if [ -z "$SELECTED_INTERFACE" ]; then
# Fall back to first interface with any IP
for IFACE in $INTERFACES; do
if ip -4 addr show "$IFACE" 2>/dev/null | grep -q "inet "; then
SELECTED_INTERFACE="$IFACE"
break
fi
done
fi
if [ -z "$SELECTED_INTERFACE" ]; then
echo "Error: No ethernet interface with IP address found"
echo "Using first available interface: $INTERFACES"
SELECTED_INTERFACE="$INTERFACES"
fi
echo
echo "Selected interface: $SELECTED_INTERFACE"
echo "$SELECTED_INTERFACE" > "${INTERFACE_CONF}"
# Find MAC addresses of devices on the network
echo
echo "Scanning for devices on the network..."
# Get the network range
NETWORK_INFO=$(ip -4 addr show "$SELECTED_INTERFACE" | grep -oP '(?<=inet\s)\d+(\.\d+){3}/\d+' | head -1)
if [ -z "$NETWORK_INFO" ]; then
echo "Warning: Could not determine network range for $SELECTED_INTERFACE"
echo "Creating empty whitelist file. Please add MAC addresses manually."
touch "${WHITELIST_CONF}"
else
NETWORK=$(echo "$NETWORK_INFO" | cut -d'/' -f1 | sed 's/\.[0-9]*$/\.0/')
NETMASK=$(echo "$NETWORK_INFO" | cut -d'/' -f2)
echo "Network: ${NETWORK}/${NETMASK}"
# Try to ping the network to populate ARP table (just a few addresses)
echo "Discovering devices (this may take a moment)..."
BASE_NET=$(echo "$NETWORK" | sed 's/\.0$//')
for i in {1..10}; do
ping -c 1 -W 1 "${BASE_NET}.${i}" >/dev/null 2>&1 &
done
wait
# Get MAC addresses from ARP table
echo
echo "Found devices:"
MACS=$(ip neigh show dev "$SELECTED_INTERFACE" | grep -E "lladdr" | awk '{print $5}' | sort -u)
if [ -z "$MACS" ]; then
echo " No devices found in ARP table"
echo " Creating empty whitelist. Please add MAC addresses manually."
touch "${WHITELIST_CONF}"
else
echo "$MACS" | while read -r MAC; do
IP=$(ip neigh show dev "$SELECTED_INTERFACE" | grep "$MAC" | awk '{print $1}')
echo " $MAC (IP: $IP)"
done
echo
echo "Writing MAC addresses to whitelist..."
echo "$MACS" > "${WHITELIST_CONF}"
echo "Added $(echo "$MACS" | wc -l) MAC address(es) to whitelist"
fi
fi
echo
echo "=== Configuration Summary ==="
echo "Interface: $(cat "${INTERFACE_CONF}")"
echo "Whitelist entries:"
if [ -f "${WHITELIST_CONF}" ] && [ -s "${WHITELIST_CONF}" ]; then
cat "${WHITELIST_CONF}" | sed 's/^/ /'
else
echo " (empty - please add MAC addresses manually)"
fi
echo
# Create or update network.conf with defaults (can be customized)
if [ ! -f "${NETWORK_CONF}" ]; then
echo
echo "Creating default network configuration..."
cat > "${NETWORK_CONF}" << EOF
# Network configuration for DHCP server
# These values override automatic detection
# Network subnet (leave empty for auto-detection from interface)
SUBNET=
# Netmask in dotted notation (leave empty for auto-detection)
NETMASK=
# DHCP range start offset from network base (default: 10)
RANGE_START_OFFSET=10
# DHCP range end offset from network base (default: 100)
RANGE_END_OFFSET=100
# Lease time in seconds (default: 43200 = 12 hours)
LEASE_TIME=43200
# Max lease time in seconds (default: 86400 = 24 hours)
MAX_LEASE_TIME=86400
EOF
echo "Network configuration created with defaults"
else
echo "Network configuration already exists, keeping current settings"
fi
echo
echo "Configuration files created:"
echo " ${INTERFACE_CONF}"
echo " ${WHITELIST_CONF}"
echo " ${NETWORK_CONF}"
echo
echo "You can now start the DHCP server with: make up"
echo "Or install as a service with: sudo make install"