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)
This commit is contained in:
Executable
+155
@@ -0,0 +1,155 @@
|
||||
#!/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"
|
||||
Executable
+134
@@ -0,0 +1,134 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Check if running as root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "This script must be run with sudo"
|
||||
echo "Usage: sudo make install"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SERVICE_NAME="dhcp-whitelist"
|
||||
SERVICE_FILE="systemd/${SERVICE_NAME}.service"
|
||||
SYSTEMD_DIR="/etc/systemd/system"
|
||||
CONFIG_DIR="/etc/dhcp-whitelist"
|
||||
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
echo "=== Installing DHCP Whitelist Service ==="
|
||||
echo
|
||||
|
||||
# Check if Docker is installed
|
||||
if ! command -v docker &> /dev/null; then
|
||||
echo "Error: Docker is not installed"
|
||||
echo "Please install Docker first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if docker-compose is installed
|
||||
if ! command -v docker-compose &> /dev/null; then
|
||||
echo "Error: docker-compose is not installed"
|
||||
echo "Please install docker-compose first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create config directory
|
||||
echo "Creating configuration directory: ${CONFIG_DIR}"
|
||||
mkdir -p "${CONFIG_DIR}"
|
||||
|
||||
# Copy configuration files
|
||||
echo "Copying configuration files..."
|
||||
if [ -f "${PROJECT_DIR}/config/interface.conf" ]; then
|
||||
cp "${PROJECT_DIR}/config/interface.conf" "${CONFIG_DIR}/"
|
||||
echo " Copied interface.conf"
|
||||
else
|
||||
echo "Warning: config/interface.conf not found"
|
||||
echo " Creating default interface.conf"
|
||||
echo "enp0s13f0u3" > "${CONFIG_DIR}/interface.conf"
|
||||
fi
|
||||
|
||||
if [ -f "${PROJECT_DIR}/config/whitelist.conf" ]; then
|
||||
cp "${PROJECT_DIR}/config/whitelist.conf" "${CONFIG_DIR}/"
|
||||
echo " Copied whitelist.conf"
|
||||
else
|
||||
echo "Warning: config/whitelist.conf not found"
|
||||
echo " Creating empty whitelist.conf"
|
||||
touch "${CONFIG_DIR}/whitelist.conf"
|
||||
fi
|
||||
|
||||
# Set proper permissions
|
||||
chmod 644 "${CONFIG_DIR}"/*.conf
|
||||
echo "Configuration files installed to: ${CONFIG_DIR}"
|
||||
|
||||
# Create service file from template
|
||||
echo
|
||||
echo "Creating systemd service file..."
|
||||
cat > "${SYSTEMD_DIR}/${SERVICE_NAME}.service" << EOF
|
||||
[Unit]
|
||||
Description=DHCP Whitelist Service
|
||||
After=network.target docker.service
|
||||
Requires=docker.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
WorkingDirectory=${PROJECT_DIR}
|
||||
Environment="CONFIG_DIR=${CONFIG_DIR}"
|
||||
|
||||
# Pre-start: Build the image
|
||||
ExecStartPre=/usr/bin/docker-compose build
|
||||
|
||||
# Start the service
|
||||
ExecStart=/usr/bin/docker-compose up
|
||||
|
||||
# Stop the service
|
||||
ExecStop=/usr/bin/docker-compose down
|
||||
|
||||
# Reload config by restarting containers
|
||||
ExecReload=/usr/bin/docker-compose restart
|
||||
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
echo "Service file created: ${SYSTEMD_DIR}/${SERVICE_NAME}.service"
|
||||
|
||||
# Create docker-compose override for service mode
|
||||
echo
|
||||
echo "Creating docker-compose override for service mode..."
|
||||
cat > "${PROJECT_DIR}/docker-compose.override.yml" << EOF
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
dhcp-server:
|
||||
volumes:
|
||||
- ${CONFIG_DIR}:/config:ro
|
||||
EOF
|
||||
|
||||
# Reload systemd
|
||||
echo
|
||||
echo "Reloading systemd daemon..."
|
||||
systemctl daemon-reload
|
||||
|
||||
echo
|
||||
echo "=== Installation Complete ==="
|
||||
echo
|
||||
echo "Configuration files location: ${CONFIG_DIR}"
|
||||
echo " - ${CONFIG_DIR}/interface.conf"
|
||||
echo " - ${CONFIG_DIR}/whitelist.conf"
|
||||
echo
|
||||
echo "Service management commands:"
|
||||
echo " Start service: systemctl start ${SERVICE_NAME}"
|
||||
echo " Stop service: systemctl stop ${SERVICE_NAME}"
|
||||
echo " Enable on boot: systemctl enable ${SERVICE_NAME}"
|
||||
echo " Check status: systemctl status ${SERVICE_NAME}"
|
||||
echo " View logs: journalctl -u ${SERVICE_NAME} -f"
|
||||
echo
|
||||
echo "Or use make targets:"
|
||||
echo " make service_up - Enable and start service"
|
||||
echo " make service_down - Stop and disable service"
|
||||
echo
|
||||
echo "To start the service now, run: make service_up"
|
||||
Reference in New Issue
Block a user