diff --git a/luci-app-zzz/Makefile b/luci-app-zzz/Makefile new file mode 100644 index 0000000..da7a36e --- /dev/null +++ b/luci-app-zzz/Makefile @@ -0,0 +1,8 @@ +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI support for NYN 802.1x Authentication Client +LUCI_DEPENDS:=+zzz +luci-base + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-zzz/luasrc/controller/zzz.lua b/luci-app-zzz/luasrc/controller/zzz.lua new file mode 100644 index 0000000..789d721 --- /dev/null +++ b/luci-app-zzz/luasrc/controller/zzz.lua @@ -0,0 +1,73 @@ +-- /usr/lib/lua/luci/controller/zzz.lua +module("luci.controller.zzz", package.seeall) + +function index() + if not nixio.fs.access("/etc/config/zzz") then + return + end + + -- Menu + entry({"admin", "network", "zzz"}, cbi("zzz"), "ZZZ", 60).dependent = false + + -- Settings + entry({"admin", "network", "zzz", "service_control"}, call("service_control")).leaf = true + + -- Status API + entry({"admin", "network", "zzz", "get_status"}, call("act_status")).leaf = true +end + +function service_control() + local sys = require "luci.sys" + local action = luci.http.formvalue("action") + local result = { success = false, message = "" } + + if action then + local cmd = "" + if action == "start" then + cmd = "/etc/rc.d/S99zzz start" + elseif action == "stop" then + cmd = "/etc/rc.d/S99zzz stop" + elseif action == "restart" then + cmd = "/etc/rc.d/S99zzz stop && sleep 2 && /etc/rc.d/S99zzz start" + end + + if cmd ~= "" then + local ret = sys.call(cmd) + if ret == 0 then + result.success = true + result.message = action .. " 成功" + else + result.success = false + result.message = action .. " 失败" + end + end + end + + luci.http.prepare_content("application/json") + luci.http.write_json(result) +end + +function act_status() + local sys = require "luci.sys" + local util = require "luci.util" + local status = {} + + -- Get status + status.running = (sys.call("pgrep -f zzz >/dev/null") == 0) + + -- Get process info + if status.running then + status.process_info = util.trim(sys.exec("ps | grep -v grep | grep zzz")) + end + + -- Get log + local log_file = "/tmp/zzz.log" + if nixio.fs.access(log_file) then + status.log = util.trim(sys.exec("tail -20 " .. log_file)) + else + status.log = util.trim(sys.exec("logread | grep zzz | tail -10")) + end + + luci.http.prepare_content("application/json") + luci.http.write_json(status) +end diff --git a/luci-app-zzz/luasrc/model/cbi/zzz.lua b/luci-app-zzz/luasrc/model/cbi/zzz.lua new file mode 100644 index 0000000..c6a3e03 --- /dev/null +++ b/luci-app-zzz/luasrc/model/cbi/zzz.lua @@ -0,0 +1,117 @@ +-- /usr/lib/lua/luci/model/cbi/zzz.lua +local m, s, o +local sys = require "luci.sys" + +-- control +local start_action = luci.http.formvalue("cbid.zzz.auth.start_service") +local stop_action = luci.http.formvalue("cbid.zzz.auth.stop_service") +local restart_action = luci.http.formvalue("cbid.zzz.auth.restart_service") + +if start_action then + sys.call("/etc/rc.d/S99zzz start") +elseif stop_action then + sys.call("/etc/rc.d/S99zzz stop") +elseif restart_action then + sys.call("/etc/rc.d/S99zzz stop; sleep 2; /etc/rc.d/S99zzz start") +end + +m = Map("zzz", "zzz 802.1x 认证客户端", + "配置使用 zzz 客户端进行网络访问的 802.1x 认证") + +-- Authentication Settings +s = m:section(TypedSection, "auth", "认证设置") +s.anonymous = true +s.addremove = false + +-- Service Status +o = s:option(DummyValue, "_status", "当前状态") +o.rawhtml = true +o.cfgvalue = function() + local sys = require "luci.sys" + local running = sys.call("pgrep zzz >/dev/null") == 0 + if running then + return "✔ 正在运行中" + else + return "✘ 未运行" + end +end + +-- control buttons +control_buttons = s:option(DummyValue, "_control", "服务控制") +control_buttons.rawhtml = true +control_buttons.cfgvalue = function() + return [[ +
+ + + +
+ ]] +end + +-- Username +o = s:option(Value, "user", "用户名", "802.1x 认证用户名") +o.password = true +o.rmempty = false + +-- Password +o = s:option(Value, "password", "密码", "802.1x 认证密码") +o.password = true +o.rmempty = false + +-- Network Device +o = s:option(ListValue, "device", "网络接口", "用于认证的网络接口") +o.rmempty = false +o:value("eth0", "eth0") +o:value("eth1", "eth1") +o:value("wan", "WAN") + +-- Add network interface +local interfaces = sys.net.devices() +for _, iface in ipairs(interfaces) do + if iface ~= "lo" then + o:value(iface, iface) + end +end + +-- Auto start +auto_start = s:option(Flag, "auto_start", "启用定时启动") +auto_start.description = "启用后将在每周一至周五的 7:00 自动启动服务" +auto_start.rmempty = false + +-- Get Status +auto_start.cfgvalue = function(self, section) + local has_cron = sys.call("crontab -l 2>/dev/null | grep 'S99zzz' >/dev/null") == 0 + return has_cron and "1" or "0" +end + +-- Crontab +auto_start.write = function(self, section, value) + if value == "1" then + -- 启用定时任务:每周一至周五 7:00 启动 + sys.call("(crontab -l 2>/dev/null | grep -v 'S99zzz' | grep -v '# zzz auto') | crontab - 2>/dev/null") + sys.call("(crontab -l 2>/dev/null; echo '0 7 * * 1,2,3,4,5 /etc/rc.d/S99zzz start # zzz auto start') | crontab -") + sys.call("/etc/init.d/cron enable && /etc/init.d/cron restart") + else + -- 禁用定时任务 + sys.call("(crontab -l 2>/dev/null | grep -v 'S99zzz' | grep -v '# zzz auto') | crontab - 2>/dev/null") + sys.call("/etc/init.d/cron restart") + end +end + +-- Crontab Status +timer_status_display = s:option(DummyValue, "_timer_status_display", "定时任务状态") +timer_status_display.rawhtml = true +timer_status_display.cfgvalue = function() + local cron_output = sys.exec("crontab -l 2>/dev/null | grep 'S99zzz' || echo '未设置'") + if cron_output:match("S99zzz") then + return "✔ 已启用 (每周一至周五 7:00 自动启动)" + else + return "✘ 未启用" + end +end + +return m diff --git a/zzz/Makefile b/zzz/Makefile new file mode 100644 index 0000000..5e63a80 --- /dev/null +++ b/zzz/Makefile @@ -0,0 +1,64 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=zzz +PKG_VERSION:=0.1.1 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Dichgrem +PKG_LICENSE:=MIT + +include $(INCLUDE_DIR)/package.mk + +define Package/zzz + SECTION:=net + CATEGORY:=Network + TITLE:=ZZZ 802.1x Authentication Client + URL:=https://github.com/diredocks/zzz + DEPENDS:= +endef + +define Package/zzz/description + A 802.1x authentication client for OpenWrt routers. + Cross-compiled C version for optimal performance and compatibility. +endef + +define Package/zzz/conffiles +/etc/config/zzz +/etc/zzz/config.ini +endef + +define Build/Prepare +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/zzz/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_DIR) $(1)/etc/zzz + + # Install precompiled binary based on architecture + $(if $(CONFIG_TARGET_x86_64),$(INSTALL_BIN) ./files/bin/zzz-x86-linux-gnu $(1)/usr/bin/zzz) + $(if $(CONFIG_TARGET_armvirt_64),$(INSTALL_BIN) ./files/bin/zzz-aarch64-linux-gnu $(1)/usr/bin/zzz) + $(if $(CONFIG_TARGET_bcm27xx_bcm2711),$(INSTALL_BIN) ./files/bin/zzz-aarch64-linux-gnu $(1)/usr/bin/zzz) + $(if $(CONFIG_TARGET_ath79_generic),$(INSTALL_BIN) ./files/bin/zzz-mipsel-linux-musleabi $(1)/usr/bin/zzz) + $(if $(CONFIG_TARGET_ramips_mt7621),$(INSTALL_BIN) ./files/bin/zzz-mipsel-linux-musleabi $(1)/usr/bin/zzz) + $(if $(CONFIG_TARGET_mediatek_mt7622),$(INSTALL_BIN) ./files/bin/zzz-aarch64-linux-gnu $(1)/usr/bin/zzz) + $(if $(CONFIG_TARGET_rockchip_armv8),$(INSTALL_BIN) ./files/bin/zzz-aarch64-linux-gnu $(1)/usr/bin/zzz) + # Fallback - try to detect architecture + $(if $(findstring aarch64,$(ARCH)),$(INSTALL_BIN) ./files/bin/zzz-aarch64-linux-gnu $(1)/usr/bin/zzz) + $(if $(findstring mips,$(ARCH)),$(INSTALL_BIN) ./files/bin/zzz-mipsel-linux-musleabi $(1)/usr/bin/zzz) + $(if $(findstring x86,$(ARCH)),$(INSTALL_BIN) ./files/bin/zzz-x86-linux-gnu $(1)/usr/bin/zzz) + + $(INSTALL_BIN) ./files/usr/bin/zzz-device-info $(1)/usr/bin/ + $(INSTALL_CONF) ./files/etc/config/zzz $(1)/etc/config/ + $(INSTALL_CONF) ./files/etc/zzz/config.ini $(1)/etc/zzz/ + $(INSTALL_BIN) ./files/etc/init.d/zzz $(1)/etc/init.d/ +endef + +$(eval $(call BuildPackage,zzz)) diff --git a/zzz/files/bin/zzz-aarch64-linux-gnu b/zzz/files/bin/zzz-aarch64-linux-gnu new file mode 100644 index 0000000..54a758a Binary files /dev/null and b/zzz/files/bin/zzz-aarch64-linux-gnu differ diff --git a/zzz/files/bin/zzz-mipsel-linux-musleabi b/zzz/files/bin/zzz-mipsel-linux-musleabi new file mode 100644 index 0000000..0485644 Binary files /dev/null and b/zzz/files/bin/zzz-mipsel-linux-musleabi differ diff --git a/zzz/files/bin/zzz-x86-linux-gnu b/zzz/files/bin/zzz-x86-linux-gnu new file mode 100644 index 0000000..55ce48e Binary files /dev/null and b/zzz/files/bin/zzz-x86-linux-gnu differ diff --git a/zzz/files/etc/config/zzz b/zzz/files/etc/config/zzz new file mode 100644 index 0000000..2e796d9 --- /dev/null +++ b/zzz/files/etc/config/zzz @@ -0,0 +1,7 @@ +config general 'general' + option enabled '0' + +config auth 'auth' + option username '' + option password '' + option device 'eth0' diff --git a/zzz/files/etc/init.d/zzz b/zzz/files/etc/init.d/zzz new file mode 100644 index 0000000..6a7fff9 --- /dev/null +++ b/zzz/files/etc/init.d/zzz @@ -0,0 +1,54 @@ +#!/bin/sh /etc/rc.common + +START=99 +USE_PROCD=1 + +CONFIG=/etc/zzz/config.ini + +start_service() { + # 检查是否启用 + local enabled=$(uci -q get zzz.general.enabled) + [ "$enabled" = "1" ] || { + echo "zzz is disabled" + return 1 + } + + generate_config + + procd_open_instance + procd_set_param command /usr/bin/zzz "$CONFIG" + procd_set_param respawn + procd_close_instance +} + +stop_service() { + procd_kill zzz +} + +generate_config() { + mkdir -p /etc/zzz + + # 获取UCI配置 + local username=$(uci -q get zzz.auth.username) + local password=$(uci -q get zzz.auth.password) + local device=$(uci -q get zzz.auth.device) + + # 检查必要参数 + [ -z "$username" ] && { + logger -t zzz "Error: username not configured" + return 1 + } + + [ -z "$password" ] && { + logger -t zzz "Error: password not configured" + return 1 + } + + # 生成INI配置文件 + cat >"$CONFIG" </dev/null 2>&1; then + zzz -mode info 2>/dev/null | grep -E "(Found|device|hardware_description)" | while read line; do + echo "$line" + done +else + echo "zzz binary not found. Showing available network interfaces:" + for dev in /sys/class/net/*; do + if [ -d "$dev" ]; then + iface=$(basename "$dev") + if [ "$iface" != "lo" ]; then + echo "Device: $iface" + if [ -f "$dev/address" ]; then + echo " MAC: $(cat "$dev/address")" + fi + if [ -f "$dev/operstate" ]; then + echo " State: $(cat "$dev/operstate")" + fi + echo "" + fi + fi + done +fi