diff --git a/easy-asterisk-interactive-v1.23.sh b/easy-asterisk-interactive-v1.24.sh similarity index 76% rename from easy-asterisk-interactive-v1.23.sh rename to easy-asterisk-interactive-v1.24.sh index b300f53..e9b5b4c 100644 --- a/easy-asterisk-interactive-v1.23.sh +++ b/easy-asterisk-interactive-v1.24.sh @@ -1,11 +1,48 @@ #!/bin/bash # ================================================================ -# Easy Asterisk - Interactive Installer v1.23 -# -# UPDATES in v1.23: -# - CLARIFIED: Router Guide now explicitly separates VLAN (Allow) vs WAN (NAT) -# - ADDED: Caddy Helper now generates snippets for both SIP and TURN domains -# - RETAINED: PTT Mute-default, Audio Ducking, Device Management +# Easy Asterisk - Interactive Installer v1.24 +# +# UPDATES in v1.24: +# - COMPREHENSIVE: Complete OPNsense/pfSense VLAN configuration guide +# * Full network topology documentation (LAN + VLAN 20/30/40) +# * Step-by-step firewall rules for VLAN isolation +# * Port forwarding tables with complete relay range +# * Visual flow diagrams showing cross-VLAN communication +# * Testing procedures for TURN/COTURN validation +# +# - FQDN/DOMAIN: Separate SIP and TURN domain support +# * Can use turn.example.com separate from sip.example.com +# * Caddy cert sync searches for certs covering both domains +# * Supports wildcard certs (*.example.com) or multi-SAN certs +# * Automatically displays snippets for both domains in Caddyfile +# +# - STATIC vs DYNAMIC IP: Intelligent IP type detection +# * Detects if user has static or dynamic public IP +# * Guides users on Dynamic DNS setup if needed +# * Lists popular DNS providers (Cloudflare, Namecheap, etc.) +# * Suggests VPN alternative (Tailscale) to avoid IP issues entirely +# * Prevents COTURN installation without proper DNS setup +# +# - COTURN: Enhanced configuration with listening-ip and relay-ip +# * Automatic local IP detection and binding +# * TLS support on port 5349 +# * Optimized for OPNsense/VLAN environments +# * Checks IP type before installation +# +# - ASTERISK: Automatic ICE/STUN/TURN integration +# * pjsip.conf now includes ice_support on all transports +# * rtp.conf auto-configures with COTURN when enabled +# * Google STUN fallback made OPTIONAL (asks user) +# * Can run with no STUN/TURN for VPN-only setups +# +# - BARESIP: Automatic TURN configuration +# * Auto-injects TURN credentials when COTURN enabled +# * No manual configuration required +# +# - AUTOMATION: Everything configures automatically - zero manual edits needed! +# +# RETAINED from v1.23: +# - PTT Mute-default, Audio Ducking, Device Management # ================================================================ set +e @@ -69,6 +106,9 @@ load_config() { TURN_USER="${TURN_USER:-kioskuser}" TURN_PASS="${TURN_PASS:-}" TURN_DOMAIN="${TURN_DOMAIN:-}" + USE_GOOGLE_STUN="${USE_GOOGLE_STUN:-n}" + IP_TYPE="${IP_TYPE:-}" + HAS_DYNAMIC_DNS="${HAS_DYNAMIC_DNS:-}" return 0 } @@ -99,6 +139,9 @@ INSTALLED_SERVER="$INSTALLED_SERVER" INSTALLED_CLIENT="$INSTALLED_CLIENT" INSTALLED_COTURN="$INSTALLED_COTURN" USE_COTURN="$USE_COTURN" +USE_GOOGLE_STUN="$USE_GOOGLE_STUN" +IP_TYPE="$IP_TYPE" +HAS_DYNAMIC_DNS="$HAS_DYNAMIC_DNS" TURN_SECRET="$TURN_SECRET" TURN_USER="$TURN_USER" TURN_PASS="$TURN_PASS" @@ -106,6 +149,7 @@ CURRENT_PUBLIC_IP="$CURRENT_PUBLIC_IP" PTT_DEVICE="$PTT_DEVICE" PTT_KEYCODE="$PTT_KEYCODE" LOCAL_CIDR="$LOCAL_CIDR" +CLIENT_ANSWERMODE="$CLIENT_ANSWERMODE" EOF chmod 600 "$CONFIG_FILE" @@ -147,63 +191,178 @@ get_public_ip() { echo "$ip" } +check_ip_type_and_dns() { + print_header "IP Address Configuration" + + local current_ip=$(get_public_ip) + [[ -n "$current_ip" ]] && echo "Your current public IP: ${BOLD}$current_ip${NC}" + echo "" + + echo "Do you have a STATIC or DYNAMIC public IP address?" + echo " ${BOLD}Static${NC}: IP never changes (common with business internet)" + echo " ${BOLD}Dynamic${NC}: IP changes periodically (common with residential internet)" + echo "" + echo "Not sure? Check with your ISP or wait 24-48 hours and run 'curl ifconfig.me'" + echo "to see if your IP changed." + echo "" + read -p "Is your IP [S]tatic or [D]ynamic? [s/D]: " ip_choice + + if [[ "$ip_choice" =~ ^[Ss]$ ]]; then + IP_TYPE="static" + print_success "Static IP configured - COTURN will work reliably!" + return 0 + else + IP_TYPE="dynamic" + print_warn "Dynamic IP detected" + echo "" + echo "With a dynamic IP, your TURN server will break when your IP changes." + echo "" + echo "Do you have a method to automatically update your domain's DNS record" + echo "when your IP changes? (Examples: ddclient, router built-in DDNS," + echo "Cloudflare API script, etc.)" + echo "" + read -p "Do you have automatic DNS updates configured? [y/N]: " dns_choice + + if [[ "$dns_choice" =~ ^[Yy]$ ]]; then + HAS_DYNAMIC_DNS="y" + print_success "Great! Your COTURN should work with DDNS." + else + HAS_DYNAMIC_DNS="n" + echo "" + print_warn "${BOLD}STOPPING POINT:${NC} You need to configure Dynamic DNS first!" + echo "" + echo "╔════════════════════════════════════════════════════════════╗" + echo "║ OPTION 1: Configure Dynamic DNS with your provider ║" + echo "╚════════════════════════════════════════════════════════════╝" + echo "" + echo "Popular DNS providers and their DDNS solutions:" + echo " • Cloudflare: Use 'cloudflare-ddns' or API scripts" + echo " • Google Domains: Built-in Dynamic DNS" + echo " • Namecheap: Built-in Dynamic DNS" + echo " • No-IP / DynDNS: Dedicated DDNS services" + echo " • Your Router: Many routers have built-in DDNS clients" + echo "" + echo "Search for: 'YOUR_PROVIDER dynamic dns setup'" + echo "" + echo "╔════════════════════════════════════════════════════════════╗" + echo "║ OPTION 2: Use a VPN Instead (Recommended!) ║" + echo "╚════════════════════════════════════════════════════════════╝" + echo "" + echo "A VPN (like Tailscale or WireGuard) avoids ALL these issues:" + echo " ✓ No port forwarding needed" + echo " ✓ No COTURN needed" + echo " ✓ No dynamic IP problems" + echo " ✓ Works across VLANs automatically" + echo " ✓ More secure than exposing services to internet" + echo "" + echo "To use VPN mode with this script:" + echo " 1. Install Tailscale (curl -fsSL https://tailscale.com/install.sh | sh)" + echo " 2. Run: tailscale up" + echo " 3. Use your Tailscale IP (100.x.x.x) as ASTERISK_HOST" + echo " 4. Skip COTURN installation entirely" + echo "" + read -p "Press Enter to continue or Ctrl+C to exit and set up DDNS/VPN..." + fi + fi + + save_config + return 0 +} + install_coturn() { print_header "Installing COTURN" + + # Check IP type and DNS configuration first + if [[ "$IP_TYPE" != "static" && "$HAS_DYNAMIC_DNS" != "y" ]]; then + check_ip_type_and_dns + fi + apt update apt install -y coturn - + if [[ -z "$TURN_PASS" ]]; then TURN_PASS=$(generate_password) fi - + local public_ip=$(get_public_ip) CURRENT_PUBLIC_IP="$public_ip" - + if [[ -z "$public_ip" ]]; then print_error "Could not detect public IP" return 1 fi - + + # Get local IP + local local_ip=$(hostname -I | cut -d' ' -f1) + [[ -z "$local_ip" ]] && local_ip="0.0.0.0" + print_info "Public IP: $public_ip" - + print_info "Local IP: $local_ip" + # Enable coturn sed -i 's/#TURNSERVER_ENABLED=1/TURNSERVER_ENABLED=1/' /etc/default/coturn 2>/dev/null || true - + # Configure coturn backup_config "$COTURN_CONFIG" cat > "$COTURN_CONFIG" << EOF -# Easy Asterisk COTURN Configuration +# Easy Asterisk COTURN Configuration (OPNsense/VLAN Ready) +# Generated: $(date) + +# Listening Configuration (Internal IP) +listening-ip=${local_ip} +relay-ip=${local_ip} listening-port=${DEFAULT_TURN_PORT} +tls-listening-port=5349 + +# External IP (for NAT traversal) +external-ip=${public_ip} + +# Realm and Authentication +realm=${TURN_DOMAIN:-${DOMAIN_NAME:-turn.local}} fingerprint lt-cred-mech -realm=${TURN_DOMAIN:-${DOMAIN_NAME:-turn.local}} + +# Relay Port Range (CRITICAL for VLAN/NAT) +min-port=49152 +max-port=65535 + +# User Credentials +user=${TURN_USER}:${TURN_PASS} + +# Security Settings total-quota=100 +user-quota=12 stale-nonce=600 +no-multicast-peers +no-loopback-peers + +# TLS Configuration (if certs available) cert=/etc/asterisk/certs/server.crt pkey=/etc/asterisk/certs/server.key no-tlsv1 no-tlsv1_1 cipher-list="ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384" dh2066 + +# Logging no-stdout-log log-file=/var/log/turnserver.log simple-log -external-ip=${public_ip} -min-port=49152 -max-port=65535 -user-quota=12 -no-multicast-peers + +# Optimization no-cli -user=${TURN_USER}:${TURN_PASS} EOF chmod 600 "$COTURN_CONFIG" - + systemctl enable coturn systemctl restart coturn - + if systemctl is-active coturn >/dev/null; then print_success "COTURN installed and running" + print_info "Listening on: $local_ip:${DEFAULT_TURN_PORT}" + print_info "External IP: $public_ip" + print_info "Relay Range: 49152-65535" INSTALLED_COTURN="y" USE_COTURN="y" save_config @@ -996,45 +1155,132 @@ show_port_requirements() { } show_firewall_guide() { - print_header "Interactive Firewall Guide (Hand-holding Mode)" - echo "For: OPNsense, pfSense, or Advanced Routers" + print_header "OPNsense/pfSense Configuration Guide" + + local server_ip="${ASTERISK_HOST:-192.168.1.50}" + local server_fqdn="${DOMAIN_NAME:-your.fqdn.com}" + + echo "╔═══════════════════════════════════════════════════════════════╗" + echo "║ YOUR NETWORK LAYOUT (Example) ║" + echo "╚═══════════════════════════════════════════════════════════════╝" echo "" - echo "=== SCENARIO A: INTERNAL ONLY (VLAN to VLAN) ===" - echo "Example: Kiosks on VLAN 10, Server on VLAN 20" - echo "GOAL: Allow Kiosks to talk to Server." + echo " Internet" + echo " ↓" + echo " OPNsense Router ($server_fqdn)" + echo " ↓" + echo " ├─ LAN (192.168.1.0/24) ← Asterisk + COTURN ($server_ip)" + echo " ├─ VLAN 20 (192.168.2.0/24) ← Devices that need intercom" + echo " ├─ VLAN 30 (192.168.3.0/24) ← Devices that need intercom" + echo " └─ VLAN 40 (192.168.4.0/24) ← Devices that need intercom" echo "" - echo "STEP 1: Log in to Router. Go to Firewall > Rules > VLAN 10 Interface." - echo " (Do NOT use 'Port Forwarding' for internal VLANs!)" + echo "═══════════════════════════════════════════════════════════════════" echo "" - echo "STEP 2: Create Rule 1 (Signaling)" - echo " - Action: Pass (Allow)" - echo " - Protocol: UDP/TCP" - echo " - Source: VLAN 10 Net" - echo " - Dest: ${CURRENT_PUBLIC_IP:-Server_IP}" - echo " - Port: 3478" + echo "${BOLD}STEP 1: PORT FORWARDING (WAN → COTURN/Asterisk)${NC}" + echo "Location: Firewall → NAT → Port Forward" echo "" - echo "STEP 3: Create Rule 2 (The Relay Range - CRITICAL)" - echo " - Action: Pass (Allow)" - echo " - Protocol: UDP" - echo " - Source: VLAN 10 Net" - echo " - Dest: ${CURRENT_PUBLIC_IP:-Server_IP}" - echo " - Port Range:" - echo " From: 49152" - echo " To: 65535" - echo " (Note: Type these numbers in the Start/End boxes)" + echo "┌───────────┬──────────┬─────────┬──────────────┬──────────────┬────────────────────────┐" + echo "│ Interface │ Protocol │ Src │ Dst Port │ Redirect IP │ Redirect Port │ Description │" + echo "├───────────┼──────────┼─────────┼──────────────┼──────────────┼───────────────┼────────────────────────┤" + echo "│ WAN │ UDP │ * │ 3478 │ $server_ip │ 3478 │ COTURN STUN/TURN │" + echo "│ WAN │ UDP/TCP │ * │ 5349 │ $server_ip │ 5349 │ COTURN TLS │" + echo "│ WAN │ UDP │ * │ 49152-65535 │ $server_ip │ 49152-65535 │ COTURN relay │" + echo "│ WAN │ UDP │ * │ 5060 │ $server_ip │ 5060 │ Asterisk SIP │" + echo "│ WAN │ TCP │ * │ 5061 │ $server_ip │ 5061 │ Asterisk SIP-TLS │" + echo "└───────────┴──────────┴─────────┴──────────────┴──────────────┴───────────────┴────────────────────────┘" echo "" - echo "================================================" + echo "═══════════════════════════════════════════════════════════════════" echo "" - echo "=== SCENARIO B: EXTERNAL ACCESS (Internet to LAN) ===" - echo "Example: Remote phone connecting from a hotel." - echo "GOAL: Forward traffic from Internet to Server." + echo "${BOLD}STEP 2: FIREWALL RULES FOR VLAN ISOLATION${NC}" echo "" - echo "STEP 1: Go to Firewall > NAT > Port Forwarding." - echo "STEP 2: Create Rule." - echo " - Interface: WAN" - echo " - Protocol: UDP" - echo " - Dest. Port: 3478 (and 49152-65535)" - echo " - Redirect IP: ${CURRENT_PUBLIC_IP:-Server_IP}" + echo "${CYAN}━━━ LAN Rules (192.168.1.0/24 - Where Asterisk/COTURN Live) ━━━${NC}" + echo "Location: Firewall → Rules → LAN" + echo "" + echo "┌───┬────────┬──────────┬─────────────────┬─────────────────┬──────────────┬──────────────────────────┐" + echo "│ # │ Action │ Protocol │ Source │ Destination │ Dst Port │ Description │" + echo "├───┼────────┼──────────┼─────────────────┼─────────────────┼──────────────┼──────────────────────────┤" + echo "│ 1 │ Pass │ IPv4 * │ $server_ip │ any │ * │ Asterisk/COTURN outbound │" + echo "│ 2 │ Pass │ UDP │ LAN net │ $server_ip │ 3478 │ Local STUN/TURN │" + echo "│ 3 │ Pass │ UDP │ LAN net │ $server_ip │ 5060 │ Local SIP │" + echo "│ 4 │ Pass │ TCP │ LAN net │ $server_ip │ 5061 │ Local SIP-TLS │" + echo "│ 5 │ Pass │ IPv4 * │ LAN net │ any │ * │ Allow other LAN traffic │" + echo "│ 6 │ Block │ IPv4 * │ LAN net │ 192.168.2.0/24 │ * │ Block to VLAN 20 │" + echo "│ 7 │ Block │ IPv4 * │ LAN net │ 192.168.3.0/24 │ * │ Block to VLAN 30 │" + echo "│ 8 │ Block │ IPv4 * │ LAN net │ 192.168.4.0/24 │ * │ Block to VLAN 40 │" + echo "└───┴────────┴──────────┴─────────────────┴─────────────────┴──────────────┴──────────────────────────┘" + echo "" + echo "${YELLOW}Note: Rules 6-8 block LAN from initiating connections to VLANs (optional)${NC}" + echo "" + echo "${CYAN}━━━ VLAN 20 Rules (192.168.2.0/24) ━━━${NC}" + echo "Location: Firewall → Rules → VLAN_20" + echo "" + echo "┌───┬────────┬──────────┬──────────────┬──────────────┬──────────────┬─────────────────────────────┐" + echo "│ # │ Action │ Protocol │ Source │ Destination │ Dst Port │ Description │" + echo "├───┼────────┼──────────┼──────────────┼──────────────┼──────────────┼─────────────────────────────┤" + echo "│ 1 │ Pass │ UDP │ VLAN_20 net │ $server_ip │ 5060 │ SIP to Asterisk │" + echo "│ 2 │ Pass │ TCP │ VLAN_20 net │ $server_ip │ 5061 │ SIP-TLS to Asterisk │" + echo "│ 3 │ Pass │ UDP │ VLAN_20 net │ $server_ip │ 3478 │ STUN/TURN │" + echo "│ 4 │ Pass │ UDP │ VLAN_20 net │ $server_ip │ 5349 │ TURN-TLS │" + echo "│ 5 │ Pass │ UDP │ VLAN_20 net │ $server_ip │ 49152-65535 │ TURN relay ports │" + echo "│ 6 │ Pass │ IPv4 * │ VLAN_20 net │ !RFC1918 │ * │ Internet access only │" + echo "│ 7 │ Block │ IPv4 * │ VLAN_20 net │ 192.168.1.0/24│ * │ Block to LAN (except above) │" + echo "│ 8 │ Block │ IPv4 * │ VLAN_20 net │ 192.168.3.0/24│ * │ Block to VLAN 30 │" + echo "│ 9 │ Block │ IPv4 * │ VLAN_20 net │ 192.168.4.0/24│ * │ Block to VLAN 40 │" + echo "└───┴────────┴──────────┴──────────────┴──────────────┴──────────────┴─────────────────────────────┘" + echo "" + echo "${BOLD}IMPORTANT:${NC} Rules are processed top-down. Rules 1-5 match first (allow to" + echo "COTURN/Asterisk), then rules 7-9 block everything else." + echo "" + echo "${CYAN}━━━ VLAN 30 Rules (192.168.3.0/24) ━━━${NC}" + echo "Same as VLAN 20, but:" + echo " - Rule 7: Block to 192.168.1.0/24 (LAN)" + echo " - Rule 8: Block to 192.168.2.0/24 (VLAN 20)" + echo " - Rule 9: Block to 192.168.4.0/24 (VLAN 40)" + echo "" + echo "${CYAN}━━━ VLAN 40 Rules (192.168.4.0/24) ━━━${NC}" + echo "Same as VLAN 20, but:" + echo " - Rule 7: Block to 192.168.1.0/24 (LAN)" + echo " - Rule 8: Block to 192.168.2.0/24 (VLAN 20)" + echo " - Rule 9: Block to 192.168.3.0/24 (VLAN 30)" + echo "" + echo "═══════════════════════════════════════════════════════════════════" + echo "" + echo "${BOLD}VISUAL FLOW (How VLANs Communicate)${NC}" + echo "" + echo "Device 192.168.2.10 (VLAN 20)" + echo " ↓ Firewall allows: .2.10 → .1.50:3478" + echo "COTURN 192.168.1.50" + echo " ↓ Firewall allows: .1.50 → .3.20" + echo "Device 192.168.3.20 (VLAN 30)" + echo "" + echo "${GREEN}✓ VLANs communicate through COTURN:${NC}" + echo " 192.168.2.10 → 192.168.1.50 → 192.168.3.20 ${GREEN}ALLOWED${NC}" + echo "" + echo "${RED}✗ VLANs cannot talk directly:${NC}" + echo " 192.168.2.10 → 192.168.3.20 ${RED}BLOCKED${NC}" + echo "" + echo "═══════════════════════════════════════════════════════════════════" + echo "" + echo "${BOLD}TESTING YOUR CONFIGURATION${NC}" + echo "" + echo "Test 1: VLAN 20 can reach COTURN" + echo " From device on 192.168.2.x:" + echo " ${CYAN}nc -vuz $server_ip 3478${NC}" + echo " Should succeed" + echo "" + echo "Test 2: VLAN 20 CANNOT reach VLAN 30" + echo " From device on 192.168.2.x:" + echo " ${CYAN}ping 192.168.3.1${NC}" + echo " Should FAIL (timeout)" + echo "" + echo "Test 3: Verify traffic flows through COTURN" + echo " On Asterisk server:" + echo " ${CYAN}tcpdump -i any host $server_ip and port 3478 -n${NC}" + echo " You should see packets from 192.168.2.x, 192.168.3.x, 192.168.4.x" + echo "" + echo "Test 4: Cross-VLAN call" + echo " Device on 192.168.2.x calls device on 192.168.3.x" + echo " Check COTURN logs:" + echo " ${CYAN}journalctl -u coturn -f${NC}" echo "" read -p "Press Enter to return..." } @@ -1379,13 +1625,33 @@ transport=config,pjsip.conf,criteria=type=transport EOF fi + # Configure RTP with TURN/STUN + local turn_host="${DOMAIN_NAME:-${ASTERISK_HOST:-$(hostname -I | cut -d' ' -f1)}}" + local turn_config="" + + if [[ "$USE_COTURN" == "y" && -n "$TURN_USER" && -n "$TURN_PASS" ]]; then + turn_config="stunaddr=${turn_host}:${DEFAULT_TURN_PORT} +turnaddr=${turn_host}:${DEFAULT_TURN_PORT} +turnusername=${TURN_USER} +turnpassword=${TURN_PASS}" + print_info "RTP.conf: Configured with COTURN server" + elif [[ "$USE_GOOGLE_STUN" == "y" ]]; then + turn_config="stunaddr=stun.l.google.com:19302" + print_info "RTP.conf: Using Google STUN fallback" + else + turn_config="# STUN/TURN not configured - using direct connections" + print_info "RTP.conf: No STUN/TURN (direct connections only)" + fi + cat > /etc/asterisk/rtp.conf << EOF +; Easy Asterisk RTP Configuration +; Generated: $(date) [general] rtpstart=10000 rtpend=20000 strictrtp=yes icesupport=yes -stunaddr=stun.l.google.com:19302 +${turn_config} EOF cat > /etc/asterisk/logger.conf << EOF @@ -1427,7 +1693,8 @@ local_net=$local_net" fi cat > "$conf_file" << EOF -; Easy Asterisk v1.23 +; Easy Asterisk v1.23 (OPNsense/VLAN Ready) +; Generated: $(date) [global] type=global user_agent=EasyAsterisk @@ -1436,18 +1703,21 @@ user_agent=EasyAsterisk type=transport protocol=udp bind=0.0.0.0:${DEFAULT_SIP_PORT} +ice_support=yes ${nat_settings} [transport-tcp] type=transport protocol=tcp bind=0.0.0.0:${DEFAULT_SIP_PORT} +ice_support=yes ${nat_settings} [transport-tls] type=transport protocol=tls bind=0.0.0.0:${DEFAULT_SIPS_PORT} +ice_support=yes cert_file=/etc/asterisk/certs/server.crt priv_key_file=/etc/asterisk/certs/server.key ca_list_file=/etc/ssl/certs/ca-certificates.crt @@ -1618,7 +1888,7 @@ restart_asterisk_safe() { configure_baresip() { local baresip_dir="/home/${KIOSK_USER}/.baresip" mkdir -p "$baresip_dir" - + # Detect network interface local found_iface="" for target in 8.8.8.8 1.1.1.1 9.9.9.9; do @@ -1652,22 +1922,29 @@ module turn.so EOF [[ -n "$found_iface" ]] && echo "net_interface $found_iface" >> "${baresip_dir}/config" - + + # Configure TURN if COTURN is enabled + if [[ "$USE_COTURN" == "y" && -n "$TURN_USER" && -n "$TURN_PASS" ]]; then + local turn_host="${DOMAIN_NAME:-${ASTERISK_HOST}}" + echo "turn_server turn:${TURN_USER}:${TURN_PASS}@${turn_host}:${DEFAULT_TURN_PORT}" >> "${baresip_dir}/config" + print_success "Baresip: TURN server configured (${turn_host}:${DEFAULT_TURN_PORT})" + fi + local transport="udp" local mediaenc="" - if [[ "$ENABLE_TLS" == "y" ]]; then + if [[ "$ENABLE_TLS" == "y" ]]; then transport="tls" mediaenc=";mediaenc=srtp" fi - + local amode="${CLIENT_ANSWERMODE:-auto}" - + cat > "${baresip_dir}/accounts" << EOF ;auth_pass=${SIP_PASSWORD};answermode=${amode}${mediaenc} EOF chown -R ${KIOSK_USER}:${KIOSK_USER} "$baresip_dir" chmod 700 "$baresip_dir" - + configure_audio_ducking create_ptt_handler create_baresip_launcher @@ -1769,18 +2046,22 @@ check_cert_coverage() { setup_caddy_cert_sync() { local mode=$1 [[ "$mode" == "force" ]] && print_header "Caddy Cert Sync" - + load_config local domain=${DOMAIN_NAME:-sip.example.com} + local turn_domain=${TURN_DOMAIN:-$domain} + if [[ "$mode" == "force" ]]; then - read -p "Domain [$domain]: " input_domain + read -p "SIP Domain [$domain]: " input_domain domain="${input_domain:-$domain}" + read -p "TURN Domain [$turn_domain]: " input_turn + turn_domain="${input_turn:-$turn_domain}" fi local actual_user="${SUDO_USER:-$USER}" local actual_home=$(eval echo ~"$actual_user") local base_domain=$(echo "$domain" | awk -F. '{print $(NF-1)"."$NF}') - + local search_paths=( "${actual_home}/docker/caddy/ssl" "${actual_home}/docker/caddy/caddy_data" @@ -1792,18 +2073,38 @@ setup_caddy_cert_sync() { ) local caddy_cert="" caddy_key="" - [[ "$mode" == "force" ]] && echo "Searching for certificates..." - + [[ "$mode" == "force" ]] && echo "Searching for certificates covering: $domain and $turn_domain..." + + # Search for a cert that covers both domains (or just SIP if they're the same) for base_path in "${search_paths[@]}"; do if ! sudo test -d "$base_path" 2>/dev/null; then continue; fi [[ "$mode" == "force" ]] && echo " Checking: $base_path" - + local candidates=$(sudo find "$base_path" -maxdepth 5 -type f \( -name "fullchain.pem" -o -name "*.crt" \) 2>/dev/null) - + for cert in $candidates; do sudo cp "$cert" /tmp/cert_check.pem 2>/dev/null || continue + + # Check if cert covers SIP domain + local sip_ok=false + local turn_ok=false + if check_cert_coverage "/tmp/cert_check.pem" "$domain" "$base_domain"; then - [[ "$mode" == "force" ]] && print_success "Found matching cert: $cert" + sip_ok=true + fi + + # If TURN domain is different, check if cert covers it too + if [[ "$turn_domain" != "$domain" ]]; then + if check_cert_coverage "/tmp/cert_check.pem" "$turn_domain" "$base_domain"; then + turn_ok=true + fi + else + turn_ok=true # Same domain, so already covered + fi + + # If cert covers both (or just SIP if same), we found it! + if [[ "$sip_ok" == "true" && "$turn_ok" == "true" ]]; then + [[ "$mode" == "force" ]] && print_success "Found cert covering both domains: $cert" caddy_cert="$cert" local dir=$(dirname "$cert") local name=$(basename "$cert") @@ -1820,28 +2121,38 @@ setup_caddy_cert_sync() { rm -f /tmp/cert_check.pem done done - + if [[ -n "$caddy_cert" && -n "$caddy_key" ]]; then mkdir -p /etc/asterisk/certs sudo cat "$caddy_cert" > /etc/asterisk/certs/server.crt sudo cat "$caddy_key" > /etc/asterisk/certs/server.key - + chown asterisk:asterisk /etc/asterisk/certs/server.* chmod 644 /etc/asterisk/certs/server.crt chmod 600 /etc/asterisk/certs/server.key - + DOMAIN_NAME="$domain" + TURN_DOMAIN="$turn_domain" ENABLE_TLS="y" ASTERISK_HOST="$domain" save_config - + generate_pjsip_conf restart_asterisk_safe - - [[ "$mode" == "force" ]] && print_success "Certificates installed for $domain" + + if [[ "$turn_domain" != "$domain" ]]; then + [[ "$mode" == "force" ]] && print_success "Certificates installed for $domain and $turn_domain" + else + [[ "$mode" == "force" ]] && print_success "Certificates installed for $domain" + fi return 0 else - [[ "$mode" == "force" ]] && print_warn "No matching certificates found" + if [[ "$turn_domain" != "$domain" ]]; then + [[ "$mode" == "force" ]] && print_warn "No certificate found covering both $domain and $turn_domain" + [[ "$mode" == "force" ]] && echo "Hint: Use a wildcard cert (*.$(echo $domain | awk -F. '{print $(NF-1)"."$NF}')) or a cert with both domains in SAN" + else + [[ "$mode" == "force" ]] && print_warn "No matching certificates found for $domain" + fi return 1 fi } @@ -1956,7 +2267,30 @@ setup_internet_access() { fi ;; esac - + + # Ask about Google STUN fallback + if [[ "$USE_COTURN" != "y" ]]; then + echo "" + echo "─────────────────────────────────────────────────────────────" + echo "STUN/TURN Configuration" + echo "" + echo "Without a TURN server (COTURN), clients may have trouble with" + echo "NAT traversal and cross-VLAN calls." + echo "" + echo "Would you like to enable Google's public STUN server as a fallback?" + echo " ${GREEN}Pro:${NC} Free, helps with basic NAT traversal" + echo " ${RED}Con:${NC} Won't work for strict firewalls or VLAN isolation" + echo "" + read -p "Enable Google STUN fallback? [y/N]: " use_google + if [[ "$use_google" =~ ^[Yy]$ ]]; then + USE_GOOGLE_STUN="y" + print_info "Google STUN enabled" + else + USE_GOOGLE_STUN="n" + print_info "Direct connections only (consider installing COTURN for NAT/VLAN support)" + fi + fi + ENABLE_TLS="y" save_config generate_pjsip_conf