Просмотр исходного кода

Unify: Add all hostapd interfaces + SSID monitoring

- Monitor ALL hostapd interfaces (not just wlan0-1)
- Track SSID enable/disable events
- Use ubus for DHCP leases with file fallback
- Unified state file
Gogs 2 месяцев назад
Родитель
Сommit
2221db0ee7
1 измененных файлов с 237 добавлено и 0 удалено
  1. 237 0
      package/src/client2server-minimal.lua

+ 237 - 0
package/src/client2server-minimal.lua

@@ -0,0 +1,237 @@
+-- client2server-minimal.lua - Unified DHCP + WiFi + SSID monitoring via ubus
+local cfg = {
+    server_url = "http://163.245.193.47:3843",
+    router_id = "Guayabal",
+    check_interval = 10,
+    state_file = "/tmp/client2server_state",
+}
+
+-------------------------------------------------
+-- Utilities
+-------------------------------------------------
+local function log_info(msg)
+    os.execute('logger -t client2server -p user.info "' .. msg .. '"')
+end
+
+local function http_post(event_type, data)
+    local json = '{"router_id":"' .. cfg.router_id .. '","event":"' .. event_type .. '","data":' .. data .. '}'
+    local f = io.popen("curl -s -X POST '" .. cfg.server_url .. "/api/events' -H 'Content-Type: application/json' -d '" .. json .. "'", "r")
+    local result = f:read("*a")
+    f:close()
+    return result
+end
+
+local function send_event(event_type, data)
+    log_info("Event: " .. event_type)
+    local resp = http_post(event_type, data)
+    if resp and resp:match("OK") then
+        log_info("OK")
+    else
+        log_info("Fail: " .. (resp or "nil"):sub(1, 50))
+    end
+end
+
+-------------------------------------------------
+-- State Management
+-------------------------------------------------
+local function load_state()
+    local f = io.open(cfg.state_file, "r")
+    if f then
+        local content = f:read("*a")
+        f:close()
+        local clients = {}
+        local ssid_enabled = {}
+        local dhcp = {}
+        for line in content:gmatch("[^\n]+") do
+            local t, v = line:match("^([^:]+):(.+)$")
+            if t == "client" then clients[v] = true
+            elseif t == "ssid" then ssid_enabled[v] = true
+            elseif t == "dhcp" then
+                local mac, ip = v:match("^(.+)->(.+)$")
+                if mac and ip then dhcp[mac] = {ip=ip, mac=mac} end
+            end
+        end
+        return { clients = clients, ssid_enabled = ssid_enabled, dhcp = dhcp }
+    end
+    return { clients = {}, ssid_enabled = {}, dhcp = {} }
+end
+
+local function save_state(state)
+    local f = io.open(cfg.state_file, "w")
+    if f then
+        for mac in pairs(state.clients) do
+            f:write("client:" .. mac .. "\n")
+        end
+        for iface in pairs(state.ssid_enabled) do
+            f:write("ssid:" .. iface .. "\n")
+        end
+        for mac, info in pairs(state.dhcp) do
+            f:write("dhcp:" .. mac .. "->" .. info.ip .. "\n")
+        end
+        f:close()
+    end
+end
+
+-------------------------------------------------
+-- WiFi: Get ALL hostapd interfaces
+-------------------------------------------------
+local function get_hostapd_interfaces()
+    local f = io.popen("ubus list | grep hostapd")
+    local interfaces = {}
+    if f then
+        for line in f:lines() do
+            table.insert(interfaces, line)
+        end
+        f:close()
+    end
+    return interfaces
+end
+
+-- Get clients from ALL interfaces
+local function get_wifi_clients()
+    local clients = {}
+    local interfaces = get_hostapd_interfaces()
+    for _, iface in ipairs(interfaces) do
+        local f = io.popen("ubus call " .. iface .. " get_clients 2>/dev/null")
+        if f then
+            local result = f:read("*a")
+            f:close()
+            for mac in result:gmatch('"([a-fA-F0-9:]+)"') do
+                clients[mac] = true
+            end
+        end
+    end
+    return clients
+end
+
+-- Get SSID status for ALL interfaces
+local function get_ssid_status()
+    local status = {}
+    local interfaces = get_hostapd_interfaces()
+    for _, iface in ipairs(interfaces) do
+        local f = io.popen("ubus call " .. iface .. " get_status 2>/dev/null")
+        if f then
+            local result = f:read("*a")
+            f:close()
+            local enabled = result:match('"enabled":%s*(%a+)')
+            if enabled == "true" then
+                status[iface] = true
+            end
+        end
+    end
+    return status
+end
+
+-------------------------------------------------
+-- DHCP: Get leases via ubus
+-------------------------------------------------
+local function get_dhcp_leases()
+    local leases = {}
+    
+    -- Try ubus first
+    local f = io.popen("ubus call dhcp ipv4leases 2>/dev/null")
+    if f then
+        local result = f:read("*a")
+        f:close()
+        if result:match('"leases"') then
+            for ip, mac in result:gmatch('"ip":"([%d%.]+)"[^}]*"mac":"([a-fA-F0-9:]+)"') do
+                leases[mac] = {ip=ip, mac=mac}
+            end
+            return leases
+        end
+    end
+    
+    -- Fallback: read lease file
+    f = io.popen("cat /tmp/dhcp.leases 2>/dev/null")
+    if f then
+        for line in f:lines() do
+            local e, mac, ip, h, c = line:match("^(%S+) (%S+) (%S+) (%S+) (%S+)")
+            if mac then leases[mac] = {ip=ip, mac=mac, hostname=h} end
+        end
+        f:close()
+    end
+    return leases
+end
+
+-------------------------------------------------
+-- Main Loop
+-------------------------------------------------
+function main()
+    log_info("Starting client2server-minimal...")
+    log_info("Router: " .. cfg.router_id)
+    
+    local state = load_state()
+    
+    -- Initial event
+    local leases = get_dhcp_leases()
+    local count = 0
+    for _ in pairs(leases) do count = count + 1 end
+    log_info("DHCP leases: " .. count)
+    send_event("router_online", '{"lease_count":' .. count .. '}')
+    
+    while true do
+        os.execute("sleep " .. cfg.check_interval)
+        
+        -------------------------------------------------
+        -- WiFi Clients
+        -------------------------------------------------
+        local current_clients = get_wifi_clients()
+        
+        for mac in pairs(current_clients) do
+            if not state.clients[mac] then
+                log_info("WiFi CONNECTED: " .. mac)
+                send_event("wifi_connected", '{"mac":"' .. mac .. '"}')
+            end
+        end
+        for mac in pairs(state.clients) do
+            if not current_clients[mac] then
+                log_info("WiFi DISCONNECTED: " .. mac)
+                send_event("wifi_disconnected", '{"mac":"' .. mac .. '"}')
+            end
+        end
+        state.clients = current_clients
+        
+        -------------------------------------------------
+        -- SSID Status
+        -------------------------------------------------
+        local current_ssid = get_ssid_status()
+        
+        for iface in pairs(current_ssid) do
+            if not state.ssid_enabled[iface] then
+                log_info("SSID ENABLED: " .. iface)
+                send_event("ssid_enabled", '{"interface":"' .. iface .. '"}')
+            end
+        end
+        for iface in pairs(state.ssid_enabled) do
+            if not current_ssid[iface] then
+                log_info("SSID DISABLED: " .. iface)
+                send_event("ssid_disabled", '{"interface":"' .. iface .. '"}')
+            end
+        end
+        state.ssid_enabled = current_ssid
+        
+        -------------------------------------------------
+        -- DHCP Leases
+        -------------------------------------------------
+        local current_dhcp = get_dhcp_leases()
+        
+        for mac, info in pairs(current_dhcp) do
+            if not state.dhcp[mac] then
+                log_info("DHCP NEW: " .. mac .. " -> " .. info.ip)
+                send_event("dhcp_new", '{"mac":"' .. mac .. '","ip":"' .. info.ip .. '"}')
+            end
+        end
+        for mac, info in pairs(state.dhcp) do
+            if not current_dhcp[mac] then
+                log_info("DHCP RELEASE: " .. mac .. " -> " .. info.ip)
+                send_event("dhcp_release", '{"mac":"' .. mac .. '","ip":"' .. info.ip .. '"}')
+            end
+        end
+        state.dhcp = current_dhcp
+        
+        -- Save state
+        save_state(state)
+    end
+end
+
+main()