#!/bin/sh # SPDX-License-Identifier: Apache-2.0 # Network Modes Dashboard RPCD backend # Copyright (C) 2024 CyberMind.fr - Gandalf . /lib/functions.sh . /usr/share/libubox/jshn.sh CONFIG_FILE="/etc/config/network-modes" BACKUP_DIR="/etc/network-modes-backup" # Get current status get_status() { json_init # Current mode local current_mode=$(uci -q get network-modes.config.current_mode || echo "router") local last_change=$(uci -q get network-modes.config.last_change || echo "Never") json_add_string "current_mode" "$current_mode" json_add_string "last_change" "$last_change" # Get mode details local mode_name=$(uci -q get network-modes.$current_mode.name || echo "$current_mode") local mode_desc=$(uci -q get network-modes.$current_mode.description || echo "") json_add_string "mode_name" "$mode_name" json_add_string "mode_description" "$mode_desc" # System info json_add_string "hostname" "$(uci -q get system.@system[0].hostname || hostname)" json_add_int "uptime" "$(cat /proc/uptime | cut -d. -f1)" # Network interfaces status json_add_array "interfaces" for iface in $(ip -o link show | awk -F': ' '{print $2}' | grep -v "^lo$"); do local state="down" ip link show $iface 2>/dev/null | grep -q "UP" && state="up" local ip=$(ip -4 addr show $iface 2>/dev/null | grep -oP 'inet \K[\d.]+' | head -1) local mac=$(ip link show $iface 2>/dev/null | grep -oP 'link/ether \K[a-f0-9:]+') json_add_object json_add_string "name" "$iface" json_add_string "state" "$state" json_add_string "ip" "${ip:-N/A}" json_add_string "mac" "${mac:-N/A}" json_close_object done json_close_array # WiFi status local wifi_enabled=0 [ -d /sys/class/net/wlan0 ] && wifi_enabled=1 json_add_boolean "wifi_available" "$wifi_enabled" # WireGuard status local wg_enabled=0 command -v wg >/dev/null 2>&1 && wg_enabled=1 json_add_boolean "wireguard_available" "$wg_enabled" # Services status json_add_object "services" json_add_boolean "firewall" "$(pgrep -x fw4 >/dev/null && echo 1 || echo 0)" json_add_boolean "dnsmasq" "$(pgrep -x dnsmasq >/dev/null && echo 1 || echo 0)" json_add_boolean "netifyd" "$(pgrep -x netifyd >/dev/null && echo 1 || echo 0)" json_add_boolean "nginx" "$(pgrep -x nginx >/dev/null && echo 1 || echo 0)" json_add_boolean "squid" "$(pgrep -x squid >/dev/null && echo 1 || echo 0)" json_close_object json_dump } # Get all modes configuration get_modes() { json_init json_add_array "modes" local current_mode=$(uci -q get network-modes.config.current_mode || echo "router") # Sniffer mode json_add_object json_add_string "id" "sniffer" json_add_string "name" "$(uci -q get network-modes.sniffer.name || echo 'Sniffer / Passthrough')" json_add_string "description" "$(uci -q get network-modes.sniffer.description)" json_add_string "icon" "🔍" json_add_boolean "active" "$([ "$current_mode" = "sniffer" ] && echo 1 || echo 0)" json_add_string "bridge_interface" "$(uci -q get network-modes.sniffer.bridge_interface)" json_add_boolean "netifyd_enabled" "$(uci -q get network-modes.sniffer.netifyd_enabled || echo 0)" json_add_boolean "promiscuous" "$(uci -q get network-modes.sniffer.promiscuous || echo 0)" json_close_object # Access Point mode json_add_object json_add_string "id" "accesspoint" json_add_string "name" "$(uci -q get network-modes.accesspoint.name || echo 'Access Point')" json_add_string "description" "$(uci -q get network-modes.accesspoint.description)" json_add_string "icon" "📶" json_add_boolean "active" "$([ "$current_mode" = "accesspoint" ] && echo 1 || echo 0)" json_add_string "wifi_channel" "$(uci -q get network-modes.accesspoint.wifi_channel)" json_add_string "wifi_htmode" "$(uci -q get network-modes.accesspoint.wifi_htmode)" json_add_int "wifi_txpower" "$(uci -q get network-modes.accesspoint.wifi_txpower || echo 20)" json_add_boolean "roaming_enabled" "$(uci -q get network-modes.accesspoint.roaming_enabled || echo 0)" json_add_boolean "band_steering" "$(uci -q get network-modes.accesspoint.band_steering || echo 0)" json_close_object # Relay mode json_add_object json_add_string "id" "relay" json_add_string "name" "$(uci -q get network-modes.relay.name || echo 'Relay / Extender')" json_add_string "description" "$(uci -q get network-modes.relay.description)" json_add_string "icon" "🔄" json_add_boolean "active" "$([ "$current_mode" = "relay" ] && echo 1 || echo 0)" json_add_boolean "wireguard_enabled" "$(uci -q get network-modes.relay.wireguard_enabled || echo 0)" json_add_string "wireguard_interface" "$(uci -q get network-modes.relay.wireguard_interface)" json_add_boolean "mtu_optimization" "$(uci -q get network-modes.relay.mtu_optimization || echo 0)" json_add_boolean "mss_clamping" "$(uci -q get network-modes.relay.mss_clamping || echo 0)" json_close_object # Router mode json_add_object json_add_string "id" "router" json_add_string "name" "$(uci -q get network-modes.router.name || echo 'Router')" json_add_string "description" "$(uci -q get network-modes.router.description)" json_add_string "icon" "🌐" json_add_boolean "active" "$([ "$current_mode" = "router" ] && echo 1 || echo 0)" json_add_string "wan_protocol" "$(uci -q get network-modes.router.wan_protocol)" json_add_boolean "nat_enabled" "$(uci -q get network-modes.router.nat_enabled || echo 1)" json_add_boolean "firewall_enabled" "$(uci -q get network-modes.router.firewall_enabled || echo 1)" json_add_boolean "proxy_enabled" "$(uci -q get network-modes.router.proxy_enabled || echo 0)" json_add_string "proxy_type" "$(uci -q get network-modes.router.proxy_type)" json_add_boolean "https_frontend" "$(uci -q get network-modes.router.https_frontend || echo 0)" json_add_string "frontend_type" "$(uci -q get network-modes.router.frontend_type)" json_close_object json_close_array json_dump } # Get sniffer mode configuration get_sniffer_config() { json_init json_add_string "mode" "sniffer" json_add_string "name" "Sniffer / Passthrough Mode" json_add_string "description" "Transparent Ethernet bridge without IP for passive network analysis" # Current settings json_add_string "bridge_interface" "$(uci -q get network-modes.sniffer.bridge_interface || echo 'br-lan')" json_add_string "capture_interface" "$(uci -q get network-modes.sniffer.capture_interface || echo 'eth0')" json_add_boolean "netifyd_enabled" "$(uci -q get network-modes.sniffer.netifyd_enabled || echo 1)" json_add_boolean "promiscuous" "$(uci -q get network-modes.sniffer.promiscuous || echo 1)" # Available interfaces for bridging json_add_array "available_interfaces" for iface in $(ls /sys/class/net/ | grep -v "^lo$"); do json_add_string "" "$iface" done json_close_array # Netifyd status local netifyd_running=0 pgrep -x netifyd >/dev/null && netifyd_running=1 json_add_boolean "netifyd_running" "$netifyd_running" # Sample config preview json_add_string "config_preview" "# /etc/config/network bridge config config interface 'lan' option proto 'none' option type 'bridge' option ifname 'eth0 eth1' option delegate '0'" json_dump } # Get access point mode configuration get_ap_config() { json_init json_add_string "mode" "accesspoint" json_add_string "name" "Access Point Mode" json_add_string "description" "WiFi Access Point with advanced optimizations" # Current settings json_add_string "upstream_interface" "$(uci -q get network-modes.accesspoint.upstream_interface || echo 'eth0')" json_add_boolean "dhcp_client" "$(uci -q get network-modes.accesspoint.dhcp_client || echo 1)" json_add_string "wifi_channel" "$(uci -q get network-modes.accesspoint.wifi_channel || echo 'auto')" json_add_string "wifi_htmode" "$(uci -q get network-modes.accesspoint.wifi_htmode || echo 'VHT80')" json_add_int "wifi_txpower" "$(uci -q get network-modes.accesspoint.wifi_txpower || echo 20)" # WiFi tweaks json_add_object "wifi_tweaks" json_add_boolean "roaming_80211r" "$(uci -q get network-modes.accesspoint.roaming_enabled || echo 0)" json_add_boolean "rrm_80211k" "$(uci -q get network-modes.accesspoint.rrm_enabled || echo 0)" json_add_boolean "wnm_80211v" "$(uci -q get network-modes.accesspoint.wnm_enabled || echo 0)" json_add_boolean "band_steering" "$(uci -q get network-modes.accesspoint.band_steering || echo 0)" json_add_boolean "airtime_fairness" "$(uci -q get network-modes.accesspoint.airtime_fairness || echo 0)" json_add_boolean "beamforming" "$(uci -q get network-modes.accesspoint.beamforming || echo 1)" json_close_object # Available channels json_add_array "available_channels_2g" for ch in 1 6 11; do json_add_int "" "$ch" done json_close_array json_add_array "available_channels_5g" for ch in 36 40 44 48 149 153 157 161; do json_add_int "" "$ch" done json_close_array # HT modes json_add_array "available_htmodes" json_add_string "" "HT20" json_add_string "" "HT40" json_add_string "" "VHT40" json_add_string "" "VHT80" json_add_string "" "VHT160" json_add_string "" "HE40" json_add_string "" "HE80" json_add_string "" "HE160" json_close_array # WiFi info local wifi_phy="" local wifi_driver="" if [ -d /sys/class/ieee80211/phy0 ]; then wifi_phy="phy0" wifi_driver=$(cat /sys/class/ieee80211/phy0/device/uevent 2>/dev/null | grep DRIVER | cut -d= -f2) fi json_add_string "wifi_phy" "$wifi_phy" json_add_string "wifi_driver" "$wifi_driver" json_dump } # Get relay mode configuration get_relay_config() { json_init json_add_string "mode" "relay" json_add_string "name" "Relay / Extender Mode" json_add_string "description" "Network relay with LAN optimization and WireGuard tunneling" # Current settings json_add_string "relay_interface" "$(uci -q get network-modes.relay.relay_interface || echo 'wlan0')" json_add_string "lan_interface" "$(uci -q get network-modes.relay.lan_interface || echo 'eth0')" # WireGuard settings json_add_object "wireguard" json_add_boolean "enabled" "$(uci -q get network-modes.relay.wireguard_enabled || echo 0)" json_add_string "interface" "$(uci -q get network-modes.relay.wireguard_interface || echo 'wg0')" json_add_int "mtu" "$(uci -q get network-modes.relay.wireguard_mtu || echo 1420)" json_add_boolean "persistent_keepalive" "$(uci -q get network-modes.relay.persistent_keepalive || echo 1)" json_close_object # Optimization settings json_add_object "optimizations" json_add_boolean "mtu_optimization" "$(uci -q get network-modes.relay.mtu_optimization || echo 1)" json_add_boolean "mss_clamping" "$(uci -q get network-modes.relay.mss_clamping || echo 1)" json_add_boolean "tcp_optimization" "$(uci -q get network-modes.relay.tcp_optimization || echo 1)" json_add_int "conntrack_max" "$(uci -q get network-modes.relay.conntrack_max || echo 16384)" json_close_object # Relayd status local relayd_installed=0 opkg list-installed 2>/dev/null | grep -q "^relayd" && relayd_installed=1 json_add_boolean "relayd_available" "$relayd_installed" # WireGuard interfaces json_add_array "wg_interfaces" if command -v wg >/dev/null 2>&1; then for wgiface in $(wg show interfaces 2>/dev/null); do json_add_string "" "$wgiface" done fi json_close_array json_dump } # Get router mode configuration get_router_config() { json_init json_add_string "mode" "router" json_add_string "name" "Router Mode" json_add_string "description" "Full router with WAN, proxy, and HTTPS frontends" # WAN settings json_add_object "wan" json_add_string "interface" "$(uci -q get network-modes.router.wan_interface || echo 'eth1')" json_add_string "protocol" "$(uci -q get network-modes.router.wan_protocol || echo 'dhcp')" json_add_boolean "nat_enabled" "$(uci -q get network-modes.router.nat_enabled || echo 1)" json_close_object # LAN settings json_add_object "lan" json_add_string "interface" "$(uci -q get network-modes.router.lan_interface || echo 'br-lan')" json_add_string "ip_address" "$(uci -q get network.lan.ipaddr || echo '192.168.1.1')" json_add_string "netmask" "$(uci -q get network.lan.netmask || echo '255.255.255.0')" json_close_object # Firewall json_add_object "firewall" json_add_boolean "enabled" "$(uci -q get network-modes.router.firewall_enabled || echo 1)" json_add_boolean "syn_flood" "$(uci -q get firewall.@defaults[0].syn_flood || echo 1)" json_add_string "input" "$(uci -q get firewall.@zone[0].input || echo 'ACCEPT')" json_add_string "output" "$(uci -q get firewall.@zone[0].output || echo 'ACCEPT')" json_add_string "forward" "$(uci -q get firewall.@zone[0].forward || echo 'REJECT')" json_close_object # Proxy settings json_add_object "proxy" json_add_boolean "enabled" "$(uci -q get network-modes.router.proxy_enabled || echo 0)" json_add_string "type" "$(uci -q get network-modes.router.proxy_type || echo 'squid')" json_add_int "port" "$(uci -q get network-modes.router.proxy_port || echo 3128)" json_add_boolean "transparent" "$(uci -q get network-modes.router.proxy_transparent || echo 0)" json_add_boolean "dns_over_https" "$(uci -q get network-modes.router.dns_over_https || echo 0)" json_close_object # HTTPS Frontend settings json_add_object "https_frontend" json_add_boolean "enabled" "$(uci -q get network-modes.router.https_frontend || echo 0)" json_add_string "type" "$(uci -q get network-modes.router.frontend_type || echo 'nginx')" json_add_int "http_port" "$(uci -q get network-modes.router.frontend_http_port || echo 80)" json_add_int "https_port" "$(uci -q get network-modes.router.frontend_https_port || echo 443)" json_add_boolean "letsencrypt" "$(uci -q get network-modes.router.letsencrypt || echo 0)" json_close_object # Virtual hosts json_add_array "virtual_hosts" local idx=0 while true; do local domain=$(uci -q get network-modes.@vhost[$idx].domain) [ -z "$domain" ] && break json_add_object json_add_string "domain" "$domain" json_add_string "backend" "$(uci -q get network-modes.@vhost[$idx].backend)" json_add_int "port" "$(uci -q get network-modes.@vhost[$idx].port || echo 80)" json_add_boolean "ssl" "$(uci -q get network-modes.@vhost[$idx].ssl || echo 0)" json_close_object idx=$((idx + 1)) done json_close_array # Available protocols json_add_array "available_wan_protocols" json_add_string "" "dhcp" json_add_string "" "static" json_add_string "" "pppoe" json_add_string "" "pptp" json_add_string "" "l2tp" json_close_array json_dump } # Apply mode change (with actual network reconfiguration and rollback timer) apply_mode() { json_init local pending_mode=$(uci -q get network-modes.config.pending_mode || echo "") if [ -z "$pending_mode" ]; then json_add_boolean "success" 0 json_add_string "error" "Aucun mode en attente. Utilisez set_mode d'abord." json_dump return fi local current_mode=$(uci -q get network-modes.config.current_mode || echo "router") # Backup current config mkdir -p "$BACKUP_DIR" local backup_file="$BACKUP_DIR/backup_$(date +%Y%m%d_%H%M%S).tar.gz" tar -czf "$backup_file" /etc/config/network /etc/config/wireless /etc/config/firewall /etc/config/dhcp 2>/dev/null # Apply network configuration based on mode case "$pending_mode" in router) # Router mode: NAT, DHCP server, firewall # WAN interface uci delete network.wan 2>/dev/null uci set network.wan=interface uci set network.wan.proto='dhcp' uci set network.wan.device='eth1' # LAN interface uci set network.lan=interface uci set network.lan.proto='static' uci set network.lan.device='eth0' uci set network.lan.ipaddr='192.168.1.1' uci set network.lan.netmask='255.255.255.0' # DHCP server uci set dhcp.lan=dhcp uci set dhcp.lan.interface='lan' uci set dhcp.lan.start='100' uci set dhcp.lan.limit='150' uci set dhcp.lan.leasetime='12h' # Firewall zones uci set firewall.@zone[0]=zone uci set firewall.@zone[0].name='lan' uci set firewall.@zone[0].input='ACCEPT' uci set firewall.@zone[0].output='ACCEPT' uci set firewall.@zone[0].forward='ACCEPT' uci set firewall.@zone[1]=zone uci set firewall.@zone[1].name='wan' uci set firewall.@zone[1].input='REJECT' uci set firewall.@zone[1].output='ACCEPT' uci set firewall.@zone[1].forward='REJECT' uci set firewall.@zone[1].masq='1' uci set firewall.@zone[1].mtu_fix='1' ;; accesspoint) # Access Point mode: Bridge, no NAT, DHCP client # Delete WAN uci delete network.wan 2>/dev/null # Bridge LAN uci set network.lan=interface uci set network.lan.proto='dhcp' uci set network.lan.type='bridge' uci set network.lan.ifname='eth0 eth1' # Disable DHCP server uci set dhcp.lan.ignore='1' # Disable firewall uci set firewall.@zone[0].input='ACCEPT' uci set firewall.@zone[0].forward='ACCEPT' uci delete firewall.@zone[1] 2>/dev/null ;; relay) # Repeater mode: STA + AP relay # Client interface (sta) uci set network.wwan=interface uci set network.wwan.proto='dhcp' # AP interface uci set network.lan=interface uci set network.lan.proto='static' uci set network.lan.ipaddr='192.168.2.1' uci set network.lan.netmask='255.255.255.0' # Relay with relayd uci set network.stabridge=interface uci set network.stabridge.proto='relay' uci set network.stabridge.network='lan wwan' ;; bridge) # Pure L2 bridge: all interfaces bridged, DHCP client uci delete network.wan 2>/dev/null # Bridge all interfaces uci set network.lan=interface uci set network.lan.proto='dhcp' uci set network.lan.type='bridge' uci set network.lan.bridge_empty='1' # Disable DHCP server uci set dhcp.lan.ignore='1' # Disable firewall uci delete firewall.@zone[1] 2>/dev/null ;; esac # Commit all changes uci commit network uci commit dhcp uci commit firewall # Update current mode uci set network-modes.config.current_mode="$pending_mode" uci set network-modes.config.last_change="$(date '+%Y-%m-%d %H:%M:%S')" uci set network-modes.config.rollback_timer="120" uci commit network-modes # Start rollback timer (2 minutes) in background ( for i in $(seq 120 -1 0); do echo "$i" > /tmp/network-mode-rollback.remaining sleep 1 done # Timer expired, rollback logger -t network-modes "Rollback timer expired, reverting to $current_mode" cd / tar -xzf "$backup_file" 2>/dev/null /etc/init.d/network reload 2>&1 /etc/init.d/firewall reload 2>&1 /etc/init.d/dnsmasq reload 2>&1 uci set network-modes.config.current_mode="$current_mode" uci delete network-modes.config.pending_mode 2>/dev/null uci set network-modes.config.last_change="$(date '+%Y-%m-%d %H:%M:%S') (auto-rollback)" uci commit network-modes rm -f /tmp/network-mode-rollback.pid rm -f /tmp/network-mode-rollback.remaining ) & echo $! > /tmp/network-mode-rollback.pid # Apply network changes NOW (async to not block RPC) ( sleep 2 /etc/init.d/network reload 2>&1 /etc/init.d/firewall reload 2>&1 /etc/init.d/dnsmasq reload 2>&1 ) & json_add_boolean "success" 1 json_add_string "mode" "$pending_mode" json_add_string "previous_mode" "$current_mode" json_add_string "message" "Mode $pending_mode appliqué. Confirmez dans les 2 minutes ou rollback automatique." json_add_string "backup" "$backup_file" json_add_int "rollback_seconds" 120 json_dump } # Update mode settings update_settings() { read input json_load "$input" json_get_var mode mode json_init case "$mode" in sniffer) json_get_var bridge_interface bridge_interface json_get_var netifyd_enabled netifyd_enabled json_get_var promiscuous promiscuous [ -n "$bridge_interface" ] && uci set network-modes.sniffer.bridge_interface="$bridge_interface" [ -n "$netifyd_enabled" ] && uci set network-modes.sniffer.netifyd_enabled="$netifyd_enabled" [ -n "$promiscuous" ] && uci set network-modes.sniffer.promiscuous="$promiscuous" ;; accesspoint) json_get_var wifi_channel wifi_channel json_get_var wifi_htmode wifi_htmode json_get_var wifi_txpower wifi_txpower json_get_var roaming_enabled roaming_enabled json_get_var band_steering band_steering [ -n "$wifi_channel" ] && uci set network-modes.accesspoint.wifi_channel="$wifi_channel" [ -n "$wifi_htmode" ] && uci set network-modes.accesspoint.wifi_htmode="$wifi_htmode" [ -n "$wifi_txpower" ] && uci set network-modes.accesspoint.wifi_txpower="$wifi_txpower" [ -n "$roaming_enabled" ] && uci set network-modes.accesspoint.roaming_enabled="$roaming_enabled" [ -n "$band_steering" ] && uci set network-modes.accesspoint.band_steering="$band_steering" ;; relay) json_get_var wireguard_enabled wireguard_enabled json_get_var wireguard_interface wireguard_interface json_get_var mtu_optimization mtu_optimization json_get_var mss_clamping mss_clamping [ -n "$wireguard_enabled" ] && uci set network-modes.relay.wireguard_enabled="$wireguard_enabled" [ -n "$wireguard_interface" ] && uci set network-modes.relay.wireguard_interface="$wireguard_interface" [ -n "$mtu_optimization" ] && uci set network-modes.relay.mtu_optimization="$mtu_optimization" [ -n "$mss_clamping" ] && uci set network-modes.relay.mss_clamping="$mss_clamping" ;; router) json_get_var wan_protocol wan_protocol json_get_var nat_enabled nat_enabled json_get_var firewall_enabled firewall_enabled json_get_var proxy_enabled proxy_enabled json_get_var proxy_type proxy_type json_get_var https_frontend https_frontend json_get_var frontend_type frontend_type [ -n "$wan_protocol" ] && uci set network-modes.router.wan_protocol="$wan_protocol" [ -n "$nat_enabled" ] && uci set network-modes.router.nat_enabled="$nat_enabled" [ -n "$firewall_enabled" ] && uci set network-modes.router.firewall_enabled="$firewall_enabled" [ -n "$proxy_enabled" ] && uci set network-modes.router.proxy_enabled="$proxy_enabled" [ -n "$proxy_type" ] && uci set network-modes.router.proxy_type="$proxy_type" [ -n "$https_frontend" ] && uci set network-modes.router.https_frontend="$https_frontend" [ -n "$frontend_type" ] && uci set network-modes.router.frontend_type="$frontend_type" ;; *) json_add_boolean "success" 0 json_add_string "error" "Invalid mode" json_dump return ;; esac uci commit network-modes json_add_boolean "success" 1 json_add_string "message" "Settings updated for $mode mode" json_dump } # Add virtual host add_vhost() { read input json_load "$input" json_get_var domain domain json_get_var backend backend json_get_var port port json_get_var ssl ssl json_init if [ -z "$domain" ] || [ -z "$backend" ]; then json_add_boolean "success" 0 json_add_string "error" "Domain and backend are required" json_dump return fi uci add network-modes vhost uci set network-modes.@vhost[-1].domain="$domain" uci set network-modes.@vhost[-1].backend="$backend" uci set network-modes.@vhost[-1].port="${port:-80}" uci set network-modes.@vhost[-1].ssl="${ssl:-0}" uci commit network-modes json_add_boolean "success" 1 json_add_string "message" "Virtual host $domain added" json_dump } # Generate config for current mode generate_config() { read input json_load "$input" json_get_var mode mode json_init local config="" case "$mode" in sniffer) local bridge=$(uci -q get network-modes.sniffer.bridge_interface || echo "br-lan") config="# Sniffer Mode Configuration # /etc/config/network config interface 'loopback' option proto 'static' option ipaddr '127.0.0.1' option netmask '255.0.0.0' option device 'lo' config device option name '$bridge' option type 'bridge' list ports 'eth0' list ports 'eth1' config interface 'lan' option device '$bridge' option proto 'none' # Disable DHCP # /etc/config/dhcp config dhcp 'lan' option ignore '1' # Enable promiscuous mode # Run: ip link set eth0 promisc on # Run: ip link set eth1 promisc on" ;; accesspoint) local channel=$(uci -q get network-modes.accesspoint.wifi_channel || echo "auto") local htmode=$(uci -q get network-modes.accesspoint.wifi_htmode || echo "VHT80") local txpower=$(uci -q get network-modes.accesspoint.wifi_txpower || echo "20") config="# Access Point Mode Configuration # /etc/config/network config interface 'lan' option proto 'dhcp' option device 'eth0' # /etc/config/wireless config wifi-device 'radio0' option type 'mac80211' option channel '$channel' option htmode '$htmode' option txpower '$txpower' option country 'FR' config wifi-iface 'default_radio0' option device 'radio0' option network 'lan' option mode 'ap' option ssid 'OpenWrt-AP' option encryption 'sae-mixed' option key 'your_password' option ieee80211r '1' option ft_over_ds '1' option ieee80211k '1' option ieee80211v '1' option bss_transition '1'" ;; relay) local wg_iface=$(uci -q get network-modes.relay.wireguard_interface || echo "wg0") config="# Relay Mode Configuration # /etc/config/network config interface 'lan' option proto 'static' option ipaddr '192.168.1.1' option netmask '255.255.255.0' option device 'br-lan' config interface 'wwan' option proto 'dhcp' option device 'wlan0' config interface '$wg_iface' option proto 'wireguard' option listen_port '51820' list addresses '10.0.0.1/24' # /etc/config/firewall - MSS clamping config rule option name 'MSS-Clamping' option src '*' option dest '*' option proto 'tcp' option extra '-m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu'" ;; router) local wan_proto=$(uci -q get network-modes.router.wan_protocol || echo "dhcp") config="# Router Mode Configuration # /etc/config/network config interface 'wan' option proto '$wan_proto' option device 'eth1' config interface 'lan' option proto 'static' option device 'br-lan' option ipaddr '192.168.1.1' option netmask '255.255.255.0' # /etc/config/firewall config defaults option syn_flood '1' option input 'ACCEPT' option output 'ACCEPT' option forward 'REJECT' config zone option name 'wan' option input 'REJECT' option output 'ACCEPT' option forward 'REJECT' option masq '1' option mtu_fix '1' list network 'wan' config zone option name 'lan' option input 'ACCEPT' option output 'ACCEPT' option forward 'ACCEPT' list network 'lan' config forwarding option src 'lan' option dest 'wan'" ;; esac json_add_string "config" "$config" json_add_string "mode" "$mode" json_dump } # Get current mode details get_current_mode() { json_init local current_mode=$(uci -q get network-modes.config.current_mode || echo "router") local last_change=$(uci -q get network-modes.config.last_change || echo "Never") local pending_mode=$(uci -q get network-modes.config.pending_mode || echo "") local rollback_timer=$(uci -q get network-modes.config.rollback_timer || echo "0") json_add_string "current_mode" "$current_mode" json_add_string "mode_name" "$(uci -q get network-modes.$current_mode.name || echo "$current_mode")" json_add_string "description" "$(uci -q get network-modes.$current_mode.description || echo "")" json_add_string "last_change" "$last_change" json_add_string "pending_mode" "$pending_mode" json_add_int "rollback_timer" "$rollback_timer" # Check if rollback is active if [ -f "/tmp/network-mode-rollback.pid" ]; then json_add_boolean "rollback_active" 1 local remaining=$(cat /tmp/network-mode-rollback.remaining 2>/dev/null || echo "0") json_add_int "rollback_remaining" "$remaining" else json_add_boolean "rollback_active" 0 json_add_int "rollback_remaining" 0 fi json_dump } # Get available modes get_available_modes() { json_init json_add_array "modes" local current_mode=$(uci -q get network-modes.config.current_mode || echo "router") # Router mode json_add_object json_add_string "id" "router" json_add_string "name" "Router" json_add_string "description" "Mode routeur complet avec NAT, DHCP et firewall" json_add_string "icon" "🌐" json_add_boolean "current" "$([ "$current_mode" = "router" ] && echo 1 || echo 0)" json_add_array "features" json_add_string "" "NAT activé" json_add_string "" "Serveur DHCP" json_add_string "" "Firewall (zones WAN/LAN)" json_add_string "" "Proxy optionnel" json_close_array json_close_object # Access Point mode json_add_object json_add_string "id" "accesspoint" json_add_string "name" "Access Point" json_add_string "description" "Point d'accès WiFi en mode bridge, pas de NAT" json_add_string "icon" "📶" json_add_boolean "current" "$([ "$current_mode" = "accesspoint" ] && echo 1 || echo 0)" json_add_array "features" json_add_string "" "Bridge WAN+LAN" json_add_string "" "Pas de DHCP (mode client)" json_add_string "" "Pas de firewall" json_add_string "" "Optimisations WiFi 802.11r/k/v" json_close_array json_close_object # Repeater/Relay mode json_add_object json_add_string "id" "relay" json_add_string "name" "Repeater" json_add_string "description" "Client WiFi + Répéteur AP avec optimisations" json_add_string "icon" "🔄" json_add_boolean "current" "$([ "$current_mode" = "relay" ] && echo 1 || echo 0)" json_add_array "features" json_add_string "" "Client WiFi (sta0)" json_add_string "" "AP répéteur (ap0)" json_add_string "" "WireGuard optionnel" json_add_string "" "Optimisations MTU/MSS" json_close_array json_close_object # Bridge mode json_add_object json_add_string "id" "bridge" json_add_string "name" "Bridge" json_add_string "description" "Bridge Layer 2 pur, DHCP client" json_add_string "icon" "🔗" json_add_boolean "current" "$([ "$current_mode" = "bridge" ] && echo 1 || echo 0)" json_add_array "features" json_add_string "" "Bridge transparent L2" json_add_string "" "Toutes interfaces bridgées" json_add_string "" "DHCP client" json_add_string "" "Pas de firewall" json_close_array json_close_object json_close_array json_dump } # Set mode (prepare for switch) set_mode() { read input json_load "$input" json_get_var target_mode mode json_init # Validate mode case "$target_mode" in router|accesspoint|relay|bridge) ;; *) json_add_boolean "success" 0 json_add_string "error" "Mode invalide: $target_mode" json_dump return ;; esac local current_mode=$(uci -q get network-modes.config.current_mode || echo "router") if [ "$current_mode" = "$target_mode" ]; then json_add_boolean "success" 0 json_add_string "error" "Déjà en mode $target_mode" json_dump return fi # Store pending mode uci set network-modes.config.pending_mode="$target_mode" uci set network-modes.config.pending_since="$(date '+%Y-%m-%d %H:%M:%S')" uci commit network-modes json_add_boolean "success" 1 json_add_string "current_mode" "$current_mode" json_add_string "target_mode" "$target_mode" json_add_string "message" "Mode $target_mode préparé. Utilisez preview_changes puis apply_mode." json_dump } # Preview changes before applying preview_changes() { json_init local current_mode=$(uci -q get network-modes.config.current_mode || echo "router") local pending_mode=$(uci -q get network-modes.config.pending_mode || echo "") if [ -z "$pending_mode" ]; then json_add_boolean "success" 0 json_add_string "error" "Aucun changement de mode en attente" json_dump return fi json_add_boolean "success" 1 json_add_string "current_mode" "$current_mode" json_add_string "target_mode" "$pending_mode" # Changes array json_add_array "changes" case "$pending_mode" in router) json_add_object json_add_string "file" "/etc/config/network" json_add_string "change" "WAN: proto dhcp, NAT enabled" json_close_object json_add_object json_add_string "file" "/etc/config/network" json_add_string "change" "LAN: static IP, DHCP server enabled" json_close_object json_add_object json_add_string "file" "/etc/config/firewall" json_add_string "change" "Zones: WAN, LAN, forwarding rules" json_close_object ;; accesspoint) json_add_object json_add_string "file" "/etc/config/network" json_add_string "change" "Bridge: br-lan (WAN+LAN)" json_close_object json_add_object json_add_string "file" "/etc/config/network" json_add_string "change" "DHCP: client mode" json_close_object json_add_object json_add_string "file" "/etc/config/firewall" json_add_string "change" "Firewall: disabled" json_close_object ;; relay) json_add_object json_add_string "file" "/etc/config/wireless" json_add_string "change" "WiFi STA: client mode on wlan0" json_close_object json_add_object json_add_string "file" "/etc/config/wireless" json_add_string "change" "WiFi AP: repeater mode on wlan1" json_close_object json_add_object json_add_string "file" "/etc/config/network" json_add_string "change" "Relay: relayd between sta0 and ap0" json_close_object ;; bridge) json_add_object json_add_string "file" "/etc/config/network" json_add_string "change" "Bridge: all interfaces to br-lan" json_close_object json_add_object json_add_string "file" "/etc/config/network" json_add_string "change" "DHCP: client only" json_close_object json_add_object json_add_string "file" "/etc/config/firewall" json_add_string "change" "Firewall: disabled" json_close_object ;; esac json_close_array # Warnings json_add_array "warnings" json_add_string "" "La connexion réseau sera interrompue pendant la reconfiguration" json_add_string "" "Vous devrez peut-être reconnecter via la nouvelle IP" json_add_string "" "Un rollback automatique de 2 minutes sera activé" json_add_string "" "Vous devez confirmer le changement avant expiration" json_close_array json_dump } # Confirm mode change (cancel rollback timer) confirm_mode() { json_init local current_mode=$(uci -q get network-modes.config.current_mode || echo "router") # Stop rollback timer if [ -f "/tmp/network-mode-rollback.pid" ]; then local pid=$(cat /tmp/network-mode-rollback.pid) kill $pid 2>/dev/null rm -f /tmp/network-mode-rollback.pid rm -f /tmp/network-mode-rollback.remaining # Clear pending mode uci delete network-modes.config.pending_mode 2>/dev/null uci delete network-modes.config.pending_since 2>/dev/null uci set network-modes.config.rollback_timer="0" uci commit network-modes json_add_boolean "success" 1 json_add_string "message" "Mode $current_mode confirmé, rollback annulé" json_add_string "mode" "$current_mode" else json_add_boolean "success" 0 json_add_string "error" "Aucun rollback actif" fi json_dump } # Rollback to previous mode rollback() { json_init # Stop any active rollback timer if [ -f "/tmp/network-mode-rollback.pid" ]; then local pid=$(cat /tmp/network-mode-rollback.pid) kill $pid 2>/dev/null rm -f /tmp/network-mode-rollback.pid rm -f /tmp/network-mode-rollback.remaining fi # Get backup file local latest_backup=$(ls -t "$BACKUP_DIR"/backup_*.tar.gz 2>/dev/null | head -1) if [ -z "$latest_backup" ]; then json_add_boolean "success" 0 json_add_string "error" "Aucune sauvegarde disponible" json_dump return fi # Restore backup cd / tar -xzf "$latest_backup" 2>/dev/null # Reload network services /etc/init.d/network reload 2>&1 /etc/init.d/firewall reload 2>&1 /etc/init.d/dnsmasq reload 2>&1 # Update UCI local previous_mode=$(uci -q get network-modes.config.current_mode || echo "router") uci delete network-modes.config.pending_mode 2>/dev/null uci set network-modes.config.last_change="$(date '+%Y-%m-%d %H:%M:%S') (rollback)" uci commit network-modes json_add_boolean "success" 1 json_add_string "message" "Configuration restaurée depuis la sauvegarde" json_add_string "mode" "$previous_mode" json_add_string "backup_file" "$latest_backup" json_dump } # Main dispatcher case "$1" in list) echo '{"status":{},"modes":{},"get_current_mode":{},"get_available_modes":{},"set_mode":{"mode":"str"},"preview_changes":{},"apply_mode":{},"confirm_mode":{},"rollback":{},"sniffer_config":{},"ap_config":{},"relay_config":{},"router_config":{},"update_settings":{"mode":"str"},"add_vhost":{"domain":"str","backend":"str","port":"int","ssl":"bool"},"generate_config":{"mode":"str"}}' ;; call) case "$2" in status) get_status ;; modes) get_modes ;; get_current_mode) get_current_mode ;; get_available_modes) get_available_modes ;; set_mode) set_mode ;; preview_changes) preview_changes ;; apply_mode) apply_mode ;; confirm_mode) confirm_mode ;; rollback) rollback ;; sniffer_config) get_sniffer_config ;; ap_config) get_ap_config ;; relay_config) get_relay_config ;; router_config) get_router_config ;; update_settings) update_settings ;; add_vhost) add_vhost ;; generate_config) generate_config ;; *) echo '{"error": "Unknown method"}' ;; esac ;; esac