require "os" require "internal_api" local json = require "cjson" require "sys" require "utils" dyutils = require("dyutils") siganl = require 'posix.signal' syswait = require 'posix.sys.wait' unistd = require 'posix.unistd' posix = require 'posix' --[[ /app/config/RUIJIE_WIFI.json { "baseurl":"http://113.137.24.86:22222", "user":"admin", "password":"ruijie.com" } /etc/init.d/ruijie_wifi #!/bin/sh /etc/rc.common START=99 USE_PROCD=1 PROG="lua" start_service () { procd_open_instance procd_set_param respawn 3600 10 0 procd_set_param command "$PROG" /app/ruijie_wifi.lua procd_set_param pidfile /var/run/ruijie_wifi.pid procd_set_param limits core="unlimited" procd_close_instance } restart() { stop sleep 1 start } reload_service() { stop sleep 1 start } ]] AP_CONFIG_FILE = "/app/config/RUIJIE_WIFI.json" ap_conf = nil gw_sn = nil local_mqtt_client = nil -- 华为ap支持代码开始 local function my_print(str) posix.write(posix.STDOUT_FILENO, str) end local function read_frame(read_fd, timeout) local fds = {[read_fd] = {events = {IN = true}}} local re_buf = '' r = posix.poll(fds, timeout) if r == 0 then return re_buf elseif r == nil then return nil else end repeat for fd in pairs(fds) do if fds[fd].revents.IN then local tmp = posix.read(fd, 1) re_buf = re_buf .. tmp if tmp == '\n' then return re_buf end end if fds[fd].revents.HUP then posix.close(fd) fds[fd] = nil if not next(fds) then return end end end r = posix.poll(fds, 1000) until (r == 0) return re_buf end local function check_login(r_fd, w_fd) re = false -- 等待登录信息输入完成 for t = 1, 30 do frame = read_frame(r_fd, 1000) if (frame == nil) or (#frame == 0) then break else my_print(frame) end end -- 检查登录是否成功 for t = 1, 10 do -- my_print('pwd\n') posix.write(w_fd, 'pwd\n') while true do frame = read_frame(r_fd, 5000) if frame ~= nil then my_print(frame) if (string.find(frame, 'flash', 1, true)) then re = true break end else break end end if (re == true) then break end end return re end --[[命令tabl结构 local cmd = { ask = "display station all", --命令 ack = "Total",--命令期望的返回 try_t = 3,--重试次数 exe_t = 500,--执行的超时时间 ack_ex = nil--备用的期望返回 } ]]-- local function exe_cmd(r_fd, w_fd, cmd) posix.write(w_fd, cmd.ask .. '\n') local re_buf = '' while true do local frame = read_frame(r_fd, cmd.exe_t) if (frame == nil) then break else if #frame > 0 then re_buf = re_buf .. frame if (string.find(frame, cmd.ack, 1, true)) or (cmd.ack_ex and (string.find(frame, cmd.ack_ex, 1, true))) then return true, re_buf end else break end end end return false, nil end --功能执行多个命令,cmds_tab是含有命令table的table local function exe_cmds(r_fd, w_fd, cmds_tab) for i, v in pairs(cmds_tab) do for t = 1, v.try_t do local re, frame = exe_cmd(r_fd, w_fd, v) if re then my_print(frame) break else return false; end end end return true; end local function terminal_init(base_url, user, passwd) local cr, pw = posix.pipe() local pr, cw = posix.pipe() local pid = posix.fork() if pid == 0 then posix.close(pr) posix.close(pw) posix.dup2(cr, posix.STDIN_FILENO) posix.dup2(cw, posix.STDOUT_FILENO) posix.dup2(cw, posix.STDERR_FILENO) posix.exec("/app/sshpass", {"-p", passwd, "ssh", user .. "@" .. base_url}) posix.exit(0) elseif pid > 0 then posix.close(cr) posix.close(cw) if (check_login(pr, pw)) then my_print('login ok\n') return pr, pw, pid else my_print('login err\n') end else end end local function terminal_uninit(pid) posix.kill(pid, posix.SIGTERM) posix.wait(pid) end local function split_str(sour, reps) local resultStrList = {} string.gsub(sour, '[^' .. reps .. ']+', function(s) table.insert(resultStrList, s) end) return resultStrList end function huawei_get_data(base_url, user, passwd, mac) local r_fd, w_fd, pid = terminal_init(base_url, user, passwd); if (r_fd == nil) or (w_fd == nil) or (pid == nil) then return nil end local cmd = { ask = "display station all", ack = "Total", try_t = 3, exe_t = 500, ack_ex = nil } local result = {} local rx_rate_5g = 0 local tx_rate_5g = 0 local rx_rate_2g = 0 local tx_rate_2g = 0 local re, frame = exe_cmd(r_fd, w_fd, cmd) if re then my_print(frame) local re_tab = split_str(frame, "\n") for i, line in pairs(re_tab) do --print("line" .. line) if string.find(line, mac, 1, true) then local re_tab = split_str(line, " "); if re_tab and #re_tab > 11 then result['ssid'] = re_tab[11] if re_tab[5] == "5G" then local rate_tab = split_str(re_tab[7], "/"); if rate_tab and #rate_tab == 2 then rx_rate_5g = rx_rate_5g + (tonumber(rate_tab[1]) or 0) tx_rate_5g = tx_rate_5g + (tonumber(rate_tab[2]) or 0) end elseif re_tab[5] == "2.4G" then local rate_tab = split_str(re_tab[7], "/"); if rate_tab and #rate_tab == 2 then rx_rate_2g = rx_rate_2g + (tonumber(rate_tab[1]) or 0) tx_rate_2g = tx_rate_2g + (tonumber(rate_tab[2]) or 0) end else -- end end elseif 1 == string.find(line, "Total:", 1, true) then local re_tab = split_str(line, " "); result['client_number'] = tonumber(re_tab[2]) or 0 result['client_number_2g'] = tonumber(re_tab[4]) or 0 result['client_number_5g'] = tonumber(re_tab[6]) or 0 else -- end end end result['rx_rate_2g'] = rx_rate_2g result['tx_rate_2g'] = tx_rate_5g result['rx_rate_5g'] = rx_rate_5g result['tx_rate_5g'] = tx_rate_5g result['mac'] = mac print(json.encode(result)) terminal_uninit(pid) return result; end local function huawei_set_data(base_url, user, passwd, mac, ssid, password) local r_fd, w_fd, pid = terminal_init(base_url, user, passwd); if (r_fd == nil) or (w_fd == nil) or (pid == nil) then return nil end ssid_pro_cmd = "ssid-profile name " .. ap_conf['ssid_pro'] ssid_name_cmd = "ssid " .. ssid sec_pro_cmd = "security-profile name " .. ap_conf['security_pro'] sec_name_cmd = "security wpa-wpa2 psk pass-phrase " .. password .. " aes" cmds_tab = { { ask = "system-view", ack = "Enter system view", try_t = 3, exe_t = 500, ack_ex = nil }, {ask = "wlan", ack = "wlan-view", try_t = 3, exe_t = 500, ack_ex = nil}, { ask = ssid_pro_cmd, ack = "wlan-ssid", try_t = 3, exe_t = 500, ack_ex = nil }, { ask = ssid_name_cmd, ack = "Continue?[Y/N]", try_t = 3, exe_t = 500, ack_ex = "wlan-ssid" }, { ask = "y", ack = "[", try_t = 3, exe_t = 10000, ack_ex = "Unrecognized" }, {ask = "quit", ack = "wlan-view", try_t = 3, exe_t = 500, ack_ex = nil}, -- { ask = sec_pro_cmd, ack = "wlan-sec-prof", try_t = 3, exe_t = 500, ack_ex = nil }, { ask = sec_name_cmd, ack = "Continue?[Y/N]", try_t = 3, exe_t = 500, ack_ex = "wlan-sec-prof" }, { ask = "y", ack = "[", try_t = 3, exe_t = 10000, ack_ex = "Unrecognized" }, {ask = "quit", ack = "wlan-view", try_t = 3, exe_t = 500, ack_ex = nil}, {ask = "quit", ack = "]", try_t = 3, exe_t = 500, ack_ex = nil} } local ok = exe_cmds(r_fd, w_fd, cmds_tab) local result = {} result["error_msg"] = ok; result['mac'] = mac print(json.encode(result)) terminal_uninit(pid) return result; end ---华为ap支持代码结束 function exec_host_cmd(cmd) local result = io.popen(cmd):read("*a") return result end function get_data(base_url, user, passwd, mac) local mac_arr = dyutils.split(mac, ":") local mac_str = string.format("%s%s.%s%s.%s%s", mac_arr[1], mac_arr[2], mac_arr[3], mac_arr[4], mac_arr[5], mac_arr[6]) mac_str = string.lower(mac_str) exec_host_cmd("rm /tmp/cookie.txt") local login = string.format( "curl -s -X POST -d 'username=%s&password=%s' -c /tmp/cookie.txt %s/login.php", user, passwd, base_url) exec_host_cmd(login) local get = string.format( "curl -s -X POST -o /tmp/output.txt -d 'command=show+web-api+apmg+ap-config+permit&mode_url=exec&charset=gbk&mode_url=exec&charset=gbk' -b /tmp/cookie.txt %s/newcli.php", base_url) exec_host_cmd(get) path = "/tmp/output.txt" str = io.readFile(path) local ap_info = {} if str ~= nil then ap_info = json.decode(str) if ap_info == nil then print("json format error from file:" .. path) end else print("Got nil from file:" .. path) end path = "/tmp/output.txt" local get = string.format( "curl -s -X POST -o %s -d 'command=show+ac-config+debug+client&mode_url=exec&charset=gbk' -b /tmp/cookie.txt %s/newcli.php", path, base_url) exec_host_cmd(get) local ap_list = ap_info['data']['list'] local ap_name = nil for key, value in pairs(ap_list) do if string.lower(mac_str) == string.lower(value['mac']) then ap_name = value['apname'] end end if ap_name == nil then return nil end -- 读取文件 -- 以只读方式打开文件 local file_input = io.open(path, "r") io.input(file_input) -- 逐行读取文件 sta_table = {} local str = file_input:read("*l") while (str ~= nil) do if string.find(str, ap_name) ~= nil then sta_mac, ip, ap = string.match(str, "(%w+)%s(%w+)%s%w+%s(%w+)") local index = 1 local sta = {} for word in string.gmatch(str, "[%w,:,.,/]+") do -- print(index, word) if index == 1 then sta['sta_mac'] = word elseif index == 2 then sta['sta_ip'] = word elseif index == 4 then sta['apname'] = word elseif index == 5 then sta['radio'] = tonumber(word) elseif index == 14 then sta['rx_rate'] = tonumber(word) elseif index == 15 then sta['tx_rate'] = tonumber(word) end index = index + 1 end table.insert(sta_table, sta) end str = file_input:read("*l") end io.close(file_input) local get = string.format( "curl -s -X POST -o %s -d 'command=show+wlan+secinfo+1&mode_url=exec&charset=gbk' -b /tmp/cookie.txt %s/newcli.php", path, base_url) exec_host_cmd(get) local result = {} for key, value in pairs(ap_list) do if string.lower(mac_str) == string.lower(value['mac']) then result['mac'] = mac sta_info = nil local sta_2g_cnt = 0 local sta_5g_cnt = 0 local rate_2g_tx = 0 local rate_5g_tx = 0 local rate_2g_rx = 0 local rate_5g_rx = 0 for k, sta in pairs(sta_table) do if sta['apname'] == value['apname'] then if sta['radio'] == 1 then sta_2g_cnt = sta_2g_cnt + 1 rate_2g_tx = rate_2g_tx + sta['tx_rate'] rate_2g_rx = rate_2g_rx + sta['rx_rate'] elseif sta['radio'] == 2 then sta_5g_cnt = sta_5g_cnt + 1 rate_5g_tx = rate_5g_tx + sta['tx_rate'] rate_5g_rx = rate_5g_rx + sta['rx_rate'] end end end result['client_number'] = value['stanum'] result['client_number_2g'] = sta_2g_cnt result['client_number_5g'] = sta_5g_cnt result['rx_rate_2g'] = rate_2g_rx result['tx_rate_2g'] = rate_2g_tx result['rx_rate_5g'] = rate_5g_rx result['tx_rate_5g'] = rate_5g_tx end end local ssid = exec_host_cmd( "cat /tmp/output.txt | grep -i ^\"WLAN SSID\" | awk -F : '{print $2}' | awk '{gsub(/^\\s+|\\s+$/, \"\");print}'") local password = exec_host_cmd( "cat /tmp/output.txt | grep -i ^\"password\" | awk -F : '{print $2}' | awk '{gsub(/^\\s+|\\s+$/, \"\");print}'") ssid = string.gsub(ssid, "\n", "") password = string.gsub(password, "\n", "") result['ssid'] = ssid result['password'] = password print(cjson.encode(result)) return result end function set_data(base_url, user, passwd, mac, ssid, password) exec_host_cmd("rm /tmp/cookie.txt") local login = string.format( "curl -s -X POST -d 'username=%s&password=%s' -c /tmp/cookie.txt %s/login.php", user, passwd, base_url) exec_host_cmd(login) local get = "curl -s -X POST -o /tmp/output.txt -d 'command=wlan-config+1%0D%0Assid+" .. ssid .. "%0D%0Atunnel++local%0D%0Aenable-broad-ssid+%0D%0Asta-limit+10%0D%0Ano+band-select+enable%0D%0Assid-code+utf-8%0D%0Aexit%0D%0Awlansec+1%0D%0Asecurity+sta-psk+disable+%0D%0Asecurity+wpa+akm+psk+set-key+ascii+" .. password .. "%0D%0Asecurity+rsn+akm+psk+set-key+ascii+" .. password .. "%0D%0Aexit&mode_url=config&charset=gbk' -b /tmp/cookie.txt " .. base_url .."/newcli.php" exec_host_cmd(get) local get = string.format( "curl -s -X POST -o /tmp/output.txt -d 'mode_url=exec&command=write&charset=gbk' -b /tmp/cookie.txt %s/newcli.php", base_url) exec_host_cmd(get) path = "/tmp/output.txt" -- 读取文件 -- 以只读方式打开文件 local file_input = io.open(path, "r") io.input(file_input) -- 逐行读取文件 local result = {} local status = nil local str = file_input:read("*l") while (str ~= nil) do if string.find(str, "OK") ~= nil then status = 0 end str = file_input:read("*l") end io.close(file_input) if status == nil then status = 9999 end result['error_code'] = status if (status == 0) then result['error_msg'] = "successful" elseif (status == 100) then result['error_msg'] = "json format error" elseif (status == 101) then result['error_msg'] = "param save error" elseif (status == 201) then result['error_msg'] = "pppoe uesr or paasword error" elseif (status == 202) then result['error_msg'] = "ping server error" elseif (status == 9999) then result['error_msg'] = "unknow error" elseif (status == -1) then result['error_msg'] = "general error" end print(cjson.encode(result)) return result end function load_ap_conf() local str = io.readFile(AP_CONFIG_FILE) if str ~= nil then ap_conf = json.decode(str) if ap_conf ~= nil then return true end end return false end function get_mac(mac) if ap_conf ~= nil then if ap_conf['ap_type'] == "huawei" then return huawei_get_data(ap_conf['baseurl'], ap_conf["user"], ap_conf["password"], mac) else return get_data(ap_conf['baseurl'], ap_conf['user'], ap_conf['password'], mac) end end return nil end function set_mac(mac, ssid, password) if ap_conf ~= nil then if ap_conf['ap_type'] == "huawei" then return huawei_set_data(ap_conf['baseurl'], ap_conf['user'], ap_conf['password'], mac, ssid, password) else return set_data(ap_conf['baseurl'], ap_conf['user'], ap_conf['password'], mac, ssid, password) end end return nil end local function handler() local pid, status, code = syswait.wait(-1, syswait.WNOHANG) log.error('system exit', pid, status, code) -- 打印不出来 os.exit(0) end local function get_ruijie_wifi(mi, mac) local result = get_mac(mac) if result ~= nil then result['mi'] = mi result['timestamp'] = os.time(os.date('!*t', os.time())) local topic = string.format("G/%s/gateway/device/%s/service/Get_RuiJieWiFiStatus", gw_sn, gw_sn) local json_str = cjson.encode(result) internal_api.mqtt_send(local_mqtt_client, topic, json_str) else print("get_mac return nil") end end local function set_ruijie_wifi(mi, mac, ssid, password) local result = set_mac(mac, ssid, password) if result ~= nil then result['mi'] = mi result['timestamp'] = os.time(os.date('!*t', os.time())) local topic = string.format("G/%s/gateway/device/%s/service/Set_RuiJieWiFi", gw_sn, gw_sn) local json_str = cjson.encode(result) internal_api.mqtt_send(local_mqtt_client, topic, json_str) else print("set_mac return nil") end end local function on_mqtt_msg(topic, payload) local obj = cjson.decode(payload) if topic == subscribe[1] then -- Get Ruijie WiFi get_ruijie_wifi(obj['mi'], obj['mac']) end if topic == subscribe[2] then -- Set Ruijie WiFi set_ruijie_wifi(obj['mi'], obj['mac'], obj['ssid'], obj['password']) end end function main_loop() while true do sys.wait(2000) end end function main() if load_ap_conf() then print(json.encode(ap_conf)); gw_sn = exec_host_cmd( "cat /app/config/fac.ini | grep -i ^sn | awk -F = '{print $2}' | awk '{gsub(/^\\s+|\\s+$/, \"\");print}' | tr '\\n' '\\0'") subscribe = {} sub_str = string.format("M/%s/gateway/device/%s/service/Get_RuiJieWiFiStatus", gw_sn, gw_sn) table.insert(subscribe, sub_str) sub_str = string.format("M/%s/gateway/device/%s/service/Set_RuiJieWiFi", gw_sn, gw_sn) table.insert(subscribe, sub_str) local_mqtt_client = internal_api.mqtt_session("localhost", 1883, nil, nil, subscribe, on_mqtt_msg) else print("load_ap_conf err") end siganl.signal(siganl.SIGKILL, handler) siganl.signal(siganl.SIGHUP, handler) sys.taskInit(main_loop) -- 启动系统框架 sys.init(0, 0) sys.run() end main()