#!/usr/bin/env bash # ============================================ # IP Assignment # ============================================ function ip::assigned() { grep -h "^Address" "$(ctx::clients)"/*.conf 2>/dev/null \ | awk '{print $3}' \ | cut -d'/' -f1 } function ip::is_assigned() { local candidate="$1" ip::assigned | grep -q "^${candidate}$" } function ip::next_for_type() { local type="$1" local subnet subnet=$(config::subnet_for "$type") if [[ -z "$subnet" ]]; then log::error "Unknown device type: ${type}" return 1 fi for i in $(seq 1 254); do local candidate="${subnet}.${i}" if ! ip::is_assigned "$candidate"; then echo "$candidate" return 0 fi done log::error "No available IPs in subnet ${subnet}.0/24" return 1 } # ============================================ # Validation # ============================================ function ip::is_valid() { local ip="$1" [[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}(/([0-9]|[1-2][0-9]|3[0-2]))?$ ]] } function ip::is_cidr() { [[ "$1" == *"/"* ]] } function ip::validate() { local ip="$1" if ! ip::is_valid "$ip"; then log::error "Invalid IP or CIDR: ${ip}" return 1 fi return 0 } function ip::require_valid() { local ip="$1" ip::validate "$ip" || exit 1 }