config.module.sh
· 3.4 KiB · Bash
Raw
#!/usr/bin/env bash
# ============================================
# Lifecycle
# ============================================
function config::on_load() {
config::validate
}
# ============================================
# Server
# ============================================
WG_INTERFACE="wg0"
WG_CONFIG="$(ctx::wg)/${WG_INTERFACE}.conf"
WG_SERVER_PUBLIC_KEY_FILE="$(ctx::wg)/server_public.key"
WG_SERVER_PRIVATE_KEY_FILE="$(ctx::wg)/server_private.key"
WG_ENDPOINT="wg.krilio.net:51820"
WG_DNS="10.0.0.103"
WG_LISTEN_PORT="51820"
WG_SUBNET="10.1.0.0/16"
WG_LAN="10.0.0.0/24"
# ============================================
# Device Type → Subnet Mapping
# ============================================
declare -gA DEVICE_SUBNETS=(
[desktop]="10.1.1"
[laptop]="10.1.2"
[phone]="10.1.3"
[tablet]="10.1.4"
[guest]="10.1.100"
)
# ============================================
# Tunnel Modes
# ============================================
# split — route only VPN subnet + LAN through WireGuard
# full — route all traffic through WireGuard
WG_TUNNEL_SPLIT="${WG_SUBNET}, ${WG_LAN}"
WG_TUNNEL_FULL="0.0.0.0/0, ::/0"
# Default tunnel mode per device type
declare -gA DEVICE_TUNNEL_MODE=(
[desktop]="split"
[laptop]="split"
[phone]="split"
[tablet]="split"
[guest]="split"
)
# ============================================
# Accessors
# ============================================
function config::interface() { echo "$WG_INTERFACE"; }
function config::config_file() { echo "$WG_CONFIG"; }
function config::endpoint() { echo "$WG_ENDPOINT"; }
function config::dns() { echo "$WG_DNS"; }
function config::listen_port() { echo "$WG_LISTEN_PORT"; }
function config::subnet() { echo "$WG_SUBNET"; }
function config::lan() { echo "$WG_LAN"; }
function config::tunnel_split() { echo "$WG_TUNNEL_SPLIT"; }
function config::tunnel_full() { echo "$WG_TUNNEL_FULL"; }
function config::server_public_key() {
cat "$WG_SERVER_PUBLIC_KEY_FILE"
}
function config::device_types() {
local types
{ set +u; types="${!DEVICE_SUBNETS[@]}"; set -u; }
echo "$types"
}
function config::is_valid_type() {
local type="$1"
local subnet
subnet=$(config::subnet_for "$type")
[[ -n "$subnet" ]]
}
function config::subnet_for() {
local type="$1"
local result
{ set +u; result="${DEVICE_SUBNETS[$type]:-}"; set -u; }
echo "$result"
}
function config::default_tunnel_for() {
local type="$1"
local result
{ set +u; result="${DEVICE_TUNNEL_MODE[$type]:-split}"; set -u; }
echo "$result"
}
function config::allowed_ips_for() {
local type="$1"
local tunnel="${2:-}"
# If tunnel mode not specified, use device default
if [[ -z "$tunnel" ]]; then
tunnel=$(config::default_tunnel_for "$type")
fi
case "$tunnel" in
full) echo "$WG_TUNNEL_FULL" ;;
split) echo "$WG_TUNNEL_SPLIT" ;;
*)
log::error "Unknown tunnel mode: ${tunnel} (use 'split' or 'full')"
return 1
;;
esac
}
# ============================================
# Validation
# ============================================
function config::validate() {
if [[ ! -f "$WG_SERVER_PUBLIC_KEY_FILE" ]]; then
log::error "Server public key not found: ${WG_SERVER_PUBLIC_KEY_FILE}"
exit 1
fi
if [[ ! -f "$WG_SERVER_PRIVATE_KEY_FILE" ]]; then
log::error "Server private key not found: ${WG_SERVER_PRIVATE_KEY_FILE}"
exit 1
fi
if [[ ! -f "$WG_CONFIG" ]]; then
log::error "WireGuard config not found: ${WG_CONFIG}"
exit 1
fi
}
| 1 | #!/usr/bin/env bash |
| 2 | |
| 3 | # ============================================ |
| 4 | # Lifecycle |
| 5 | # ============================================ |
| 6 | |
| 7 | function config::on_load() { |
| 8 | config::validate |
| 9 | } |
| 10 | |
| 11 | # ============================================ |
| 12 | # Server |
| 13 | # ============================================ |
| 14 | |
| 15 | WG_INTERFACE="wg0" |
| 16 | WG_CONFIG="$(ctx::wg)/${WG_INTERFACE}.conf" |
| 17 | WG_SERVER_PUBLIC_KEY_FILE="$(ctx::wg)/server_public.key" |
| 18 | WG_SERVER_PRIVATE_KEY_FILE="$(ctx::wg)/server_private.key" |
| 19 | WG_ENDPOINT="wg.krilio.net:51820" |
| 20 | WG_DNS="10.0.0.103" |
| 21 | WG_LISTEN_PORT="51820" |
| 22 | WG_SUBNET="10.1.0.0/16" |
| 23 | WG_LAN="10.0.0.0/24" |
| 24 | |
| 25 | # ============================================ |
| 26 | # Device Type → Subnet Mapping |
| 27 | # ============================================ |
| 28 | |
| 29 | declare -gA DEVICE_SUBNETS=( |
| 30 | [desktop]="10.1.1" |
| 31 | [laptop]="10.1.2" |
| 32 | [phone]="10.1.3" |
| 33 | [tablet]="10.1.4" |
| 34 | [guest]="10.1.100" |
| 35 | ) |
| 36 | |
| 37 | # ============================================ |
| 38 | # Tunnel Modes |
| 39 | # ============================================ |
| 40 | |
| 41 | # split — route only VPN subnet + LAN through WireGuard |
| 42 | # full — route all traffic through WireGuard |
| 43 | WG_TUNNEL_SPLIT="${WG_SUBNET}, ${WG_LAN}" |
| 44 | WG_TUNNEL_FULL="0.0.0.0/0, ::/0" |
| 45 | |
| 46 | # Default tunnel mode per device type |
| 47 | declare -gA DEVICE_TUNNEL_MODE=( |
| 48 | [desktop]="split" |
| 49 | [laptop]="split" |
| 50 | [phone]="split" |
| 51 | [tablet]="split" |
| 52 | [guest]="split" |
| 53 | ) |
| 54 | |
| 55 | # ============================================ |
| 56 | # Accessors |
| 57 | # ============================================ |
| 58 | |
| 59 | function config::interface() { echo "$WG_INTERFACE"; } |
| 60 | function config::config_file() { echo "$WG_CONFIG"; } |
| 61 | function config::endpoint() { echo "$WG_ENDPOINT"; } |
| 62 | function config::dns() { echo "$WG_DNS"; } |
| 63 | function config::listen_port() { echo "$WG_LISTEN_PORT"; } |
| 64 | function config::subnet() { echo "$WG_SUBNET"; } |
| 65 | function config::lan() { echo "$WG_LAN"; } |
| 66 | function config::tunnel_split() { echo "$WG_TUNNEL_SPLIT"; } |
| 67 | function config::tunnel_full() { echo "$WG_TUNNEL_FULL"; } |
| 68 | |
| 69 | function config::server_public_key() { |
| 70 | cat "$WG_SERVER_PUBLIC_KEY_FILE" |
| 71 | } |
| 72 | |
| 73 | function config::device_types() { |
| 74 | local types |
| 75 | { set +u; types="${!DEVICE_SUBNETS[@]}"; set -u; } |
| 76 | echo "$types" |
| 77 | } |
| 78 | |
| 79 | function config::is_valid_type() { |
| 80 | local type="$1" |
| 81 | local subnet |
| 82 | subnet=$(config::subnet_for "$type") |
| 83 | [[ -n "$subnet" ]] |
| 84 | } |
| 85 | |
| 86 | function config::subnet_for() { |
| 87 | local type="$1" |
| 88 | local result |
| 89 | { set +u; result="${DEVICE_SUBNETS[$type]:-}"; set -u; } |
| 90 | echo "$result" |
| 91 | } |
| 92 | |
| 93 | function config::default_tunnel_for() { |
| 94 | local type="$1" |
| 95 | local result |
| 96 | { set +u; result="${DEVICE_TUNNEL_MODE[$type]:-split}"; set -u; } |
| 97 | echo "$result" |
| 98 | } |
| 99 | |
| 100 | function config::allowed_ips_for() { |
| 101 | local type="$1" |
| 102 | local tunnel="${2:-}" |
| 103 | |
| 104 | # If tunnel mode not specified, use device default |
| 105 | if [[ -z "$tunnel" ]]; then |
| 106 | tunnel=$(config::default_tunnel_for "$type") |
| 107 | fi |
| 108 | |
| 109 | case "$tunnel" in |
| 110 | full) echo "$WG_TUNNEL_FULL" ;; |
| 111 | split) echo "$WG_TUNNEL_SPLIT" ;; |
| 112 | *) |
| 113 | log::error "Unknown tunnel mode: ${tunnel} (use 'split' or 'full')" |
| 114 | return 1 |
| 115 | ;; |
| 116 | esac |
| 117 | } |
| 118 | |
| 119 | # ============================================ |
| 120 | # Validation |
| 121 | # ============================================ |
| 122 | |
| 123 | function config::validate() { |
| 124 | if [[ ! -f "$WG_SERVER_PUBLIC_KEY_FILE" ]]; then |
| 125 | log::error "Server public key not found: ${WG_SERVER_PUBLIC_KEY_FILE}" |
| 126 | exit 1 |
| 127 | fi |
| 128 | |
| 129 | if [[ ! -f "$WG_SERVER_PRIVATE_KEY_FILE" ]]; then |
| 130 | log::error "Server private key not found: ${WG_SERVER_PRIVATE_KEY_FILE}" |
| 131 | exit 1 |
| 132 | fi |
| 133 | |
| 134 | if [[ ! -f "$WG_CONFIG" ]]; then |
| 135 | log::error "WireGuard config not found: ${WG_CONFIG}" |
| 136 | exit 1 |
| 137 | fi |
| 138 | } |