开发OpenWrt路由器上LuCI的模块

【题外话】html

学校里最近改造了校园网,要求必须用iNode验证,万幸的是路由器能刷OpenWrt,而且OpenWrt上有好多iNode认证的开源项目,好比njit8021xclient(如下简称njit-client)就很是好用。虽然程序写的好用,可是配置起来仍是稍微麻烦一些的,你们一般的方法是在/etc/init.d下写启动脚本,把用户名、密码什么的都直接填进去,但毕竟配置起来不方便,同时往后修改起来也不便。好在用Lua为LuCI写配置模块很简单,索性就本身作了一个,如今把开发的流程写一下,方便初学的同窗去作。为njit-client作好的Web配置界面也已经开源,地址:https://github.com/mayswind/luci-app-njitclient,或者直接下载编译好(不限平台)的文件:http://pan.baidu.com/s/1CbPallinux

 

【文章索引】git

  1. LuCI配置界面开发的框架
  2. 用Lua和UCI接口开发LuCI配置模块
  3. 在Bash文件中调用UCI接口
  4. 编译开发的程序

 

【1、LuCI配置界面开发的框架】github

LuCI是OpenWrt上的Web管理界面,LuCI采用了MVC三层架构,同时其使用Lua脚本开发,因此开发LuCI的配置界面不须要编辑任何的Html代码,除非想本身单独去建立网页(View层),不然咱们基本上只须要修改Model层就能够了。官方也有一个如何去建立模块的说明文档,虽然写的比较晦涩:http://luci.subsignal.org/trac/wiki/Documentation/ModulesHowToapi

要为LuCI增长一个新模块,首先须要建立两个文件,一个位于Controller(/usr/lib/lua/luci/controller/)下,定义模块的入口;另外一个位于Model(/usr/lib/lua/luci/model/cbi/)下,为配置模块实际的代码。数组

首先咱们定义模块的入口,在/usr/lib/lua/luci/controller/下建立一个lua文件,相似以下:浏览器

module("luci.controller.控制器名", package.seeall)

function index()
        entry(路径, 调用目标, _("显示名称"), 显示顺序)
        end

第一行说明了程序和模块的名称,好比在controller/目录建立一个mymodule.lua,那么就能够写成“luci.controller.mymodule”,若是你的程序比较多,可能分为好几个模块,那么能够在controller下再常见一个子目录,好比controller/myapp/,那么就能够写成“luci.controller.myapp.mymodule”。网络

接下来的entry表示添加一个新的模块入口,官方给出了entry的定义,其中后两项都是能够为空的:架构

entry(path, target, title=nil, order=nil)

第一项是访问的路径,不过路径是按字符串数组给定的,好比路径按以下方式写“{"click", "here", "now"}”,那么就能够在浏览器里访问“http://192.168.1.1/cgi-bin/luci/click/here/now”来访问这个脚本。而一般咱们但愿为管理员菜单添加脚本,那么咱们须要按以下方式编写“{"admin", "一级菜单名", "菜单项名"}”,系统会自动在对应的菜单中生成菜单项。好比想在“网络”菜单下建立一个菜单项,那么一级菜单名能够写为“network”。app

第二项为调用目标,调用目标分为三种,分别是执行指定方法(Action)、访问指定页面(Views)以及调用CBI Module。

  • 第一种能够直接调用指定的函数,好比点击菜单项就直接重启路由器等等,好比写为“call("function_name")”,而后在lua文件下编写名为function_name的函数就能够调用了。
  • 第二种能够访问指定的页面,好比写为“template("myapp/mymodule")”就能够调用/usr/lib/lua/luci/view/myapp/mymodule.htm文件了。
  • 而若是要编写配置页面,那么使用第三种方法无非是最方便的,好比写为“cbi("myapp/mymodule")”就能够调用/usr/lib/lua/luci/model/cbi/myapp/mymodule.lua文件了。

而title和order无非是针对管理员菜单来的,能够参考其余的lua文件来决定编写的内容。

这里咱们建立/usr/lib/lua/luci/controller/njitclient.lua文件,定义咱们的入口,代码以下:

module("luci.controller.njitclient", package.seeall)

function index()
        entry({"admin", "network", "njitclient"}, cbi("njitclient"), _("NJIT Client"), 100)
        end

 

【2、用Lua和UCI接口开发LuCI配置模块

咱们要作的实际上就是但愿能将用户名、密码等信息存储在路由器文件中,同时路由器开机时能根据设定的配置自动运行njit-client,同时咱们还但愿能动态的禁用和启用njit-client等等。因此最方便的方式就是使用CBI Module,上一节咱们也添加了这个调用,那么接下来咱们就要根据上边写的路径来建立/usr/lib/lua/luci/model/cbi/njitclient.lua文件。

开发LuCI的配置模块有不少种方式,比较基本的能够用SimpleForm,就跟开发普通的Web应用相似,固然最方便的仍是使用UCI(Unified Configuration Interface,统一配置接口)的方式,由于使用UCI接口可使得在LuCI中能够无需考虑配置文件如何存储和读取(这种方式也会自动建立“保存&应用”、“保存”以及“复位”三个按钮),同时在Bash文件中也能够很是方便的存储和读取。

对于使用UCI的方式,咱们首先须要建立对应的配置文件(若是配置文件不存在的话,访问配置页面将会报错),格式即为linux配置文件的格式,文件须要存储在/etc/config,好比文件路径为“/etc/config/njitclient”,内容以下:

config login
    option username ''
    option password ''
    option ifname 'eth0'
    option domain ''

而后咱们要在CBI Module的lua文件中首先须要映射与存储文件的关系,好比:

m = Map("配置文件文件名", "配置页面标题", "配置页面说明")

第一个参数即为配置文件存储的文件名,不包含路径,好比按上述建立的话,应该写为“njitclient”,而第二与第三个参数则是用在来页面上显示的,好比以下所示的图:

接下来须要建立与配置文件中对应的Section,Section分为两种,NamedSection和TypedSection,前者根据配置文件中的Section名,然后者根据配置文件中的Section类型,这里咱们使用后者,代码以下。同时咱们设定不容许增长或删除Section(“.addremove = false”),以及不显示Section的名称(“.anonymous = true”)。

s = m:section(TypedSection, "login", "")
s.addremove = false
s.anonymous = true

接下来咱们须要建立Section中不一样内容的交互(建立Option),常见的好比有Value(文本框)、ListValue(下拉框)、Flag(选择框)等等,详细的能够参考官方的文档:http://luci.subsignal.org/trac/wiki/Documentation/CBI

建立Option的过程很是简单,并且建立后系统会无需考虑读取以及写入配置文件的问题,系统都会自动处理。可是根据上述的要求,咱们在应用配置之后可能但愿启用、禁用或从新启动njit-client,因此咱们还须要在页面最后判断用户是否点击了“应用”按钮,这里与编写asp网页等都是相同的,咱们能够经过以下的代码判断是否点击了“应用”按钮:

local apply = luci.http.formvalue("cbi.apply")
if apply then
    --[[
        须要处理的代码
    ]]--
end

因为剩余的代码都很是简单,因此因此这部分的所有代码见下:

 1 require("luci.sys")
 2 
 3 m = Map("njitclient", translate("NJIT Client"), translate("Configure NJIT 802.11x client."))
 4 
 5 s = m:section(TypedSection, "login", "")
 6 s.addremove = false
 7 s.anonymous = true
 8 
 9 enable = s:option(Flag, "enable", translate("Enable"))
10 name = s:option(Value, "username", translate("Username"))
11 pass = s:option(Value, "password", translate("Password"))
12 pass.password = true
13 domain = s:option(Value, "domain", translate("Domain"))
14 
15 ifname = s:option(ListValue, "ifname", translate("Interfaces"))
16 for k, v in ipairs(luci.sys.net.devices()) do
17     if v ~= "lo" then
18         ifname:value(v)
19     end
20 end
21 
22 local apply = luci.http.formvalue("cbi.apply")
23 if apply then
24     io.popen("/etc/init.d/njitclient restart")
25 end
26 
27 return m

其中Luci所有类库的函数定义和使用说明能够参考以下地址:http://luci.subsignal.org/api/luci/index.html

 

【3、在Bash文件中调用UCI接口】

上边咱们已经完成了LuCI配置界面的开发,在配置界面中咱们已经能读取并保存配置文件了。接下来咱们要编写/etc/init.d/njitclient脚本,使程序最终能运行起来。关于UCI接口在脚本文件中的官方说明能够参考:http://wiki.openwrt.org/doc/devel/config-scripting

要使用UCI调用脚本,首先第一步须要读取配置文件,命令为“config_load 配置文件名”,好比咱们能够这样读入刚才的配置文件:

config_load njitclient

接下来要遍历配置文件中的Section,可使用“config_foreach 遍历函数名 Section类型”,例如咱们能够这样:

config_foreach run_njit login

而后咱们去编写名为“run_njit”的函数,在这个函数中,咱们可使用“config_get 变量名 Section名 Section参数名”获取变量的值,或者使用“config_get_bool 变量名 Section名 Section参数名”获取布尔型的值。因此所有的代码见下:

 1 #!/bin/sh /etc/rc.common
 2 START=50
 3 
 4 run_njit()
 5 {
 6     local enable
 7     config_get_bool enable $1 enable
 8     
 9     if [ $enable ]; then
10         local username
11         local password
12         local domain
13         local ifname
14         
15         config_get username $1 username
16         config_get password $1 password
17         config_get domain $1 domain
18         config_get ifname $1 ifname
19         
20         if [ "$domain" != "" ]; then
21             njit-client $username@$domain $password $ifname &
22         else
23             njit-client $username $password $ifname &
24         fi
25         
26         echo "NJIT Client has started."
27     fi
28 }
29 
30 start()
31 {
32     config_load njitclient
33     config_foreach run_njit login
34 }
35 
36 stop()
37 {
38     killall njit-client
39     killall udhcpc
40     
41     echo "NJIT Client has stoped."
42 }

 

【4、编译开发的程序

若是按上述内容建立好上述4个文件,那么配置页面和程序就能在OpenWrt上运行起来了。可是若是要想把本身写的程序打包,还须要建立OpenWrt的Makefile来使用OpenWrt的SDK进行编译。

关于LuCI上配置Makefile的官方说明能够见这个地址:http://luci.subsignal.org/trac/wiki/Documentation/Modules

无非就是定义包的名称(PKG_NAME)、版本和生成次数(PKG_VERSION、PKG_RELEASE)、在menuconfig中的分类说明等(define Package/luci-app-njitclient)以及安装时进行的操做(define Package/luci-app-njitclient/install)等等。其中安装的文件分为三种,分别是配置文件、可执行文件以及其余数据文件,其中配置可执行文件时,会自动加入执行权限的,因此不须要额外进行处理。Makefile所有的代码见下:

 1 include $(TOPDIR)/rules.mk
 2 
 3 PKG_NAME:=luci-app-njitclient
 4 PKG_VERSION=1.0
 5 PKG_RELEASE:=1
 6 
 7 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
 8 
 9 include $(INCLUDE_DIR)/package.mk
10 
11 define Package/luci-app-njitclient
12     SECTION:=luci
13     CATEGORY:=LuCI
14     SUBMENU:=3. Applications
15     TITLE:=NJIT 802.1X Client for LuCI
16     PKGARCH:=all
17 endef
18 
19 define Package/luci-app-njitclient/description
20     This package contains LuCI configuration pages for njit8021xclient.
21 endef
22 
23 define Build/Prepare
24 endef
25 
26 define Build/Configure
27 endef
28 
29 define Build/Compile
30 endef
31 
32 define Package/luci-app-njitclient/install
33     $(INSTALL_DIR) $(1)/etc/config
34     $(INSTALL_DIR) $(1)/etc/init.d
35     $(INSTALL_DIR) $(1)/usr/lib/lua/luci/model/cbi
36     $(INSTALL_DIR) $(1)/usr/lib/lua/luci/controller
37     
38     $(INSTALL_CONF) ./files/root/etc/config/njitclient $(1)/etc/config/njitclient
39     $(INSTALL_BIN) ./files/root/etc/init.d/njitclient $(1)/etc/init.d/njitclient
40     $(INSTALL_DATA) ./files/root/usr/lib/lua/luci/model/cbi/njitclient.lua $(1)/usr/lib/lua/luci/model/cbi/njitclient.lua
41     $(INSTALL_DATA) ./files/root/usr/lib/lua/luci/controller/njitclient.lua $(1)/usr/lib/lua/luci/controller/njitclient.lua
42 endef
43 
44 $(eval $(call BuildPackage,luci-app-njitclient))

接下来在编译目录下的package目录下建立一个文件夹,如njitclient,而后将全部的文件按目录复制到该目录下便可。以后配置好OpenWrt的交叉编译环境后就可使用OpenWrt SDK进行编译了,因为这类文章较多,故再也不赘述,能够参考相关连接3及以后的文章。

 

【相关连接】

  1. LuCI:http://luci.subsignal.org/trac/wiki
  2. LuCI界面修改实现802.1x配置界面:http://chaochaoblog.com/archives/359
  3. 【详细教程】编译openwrt + njit-client 1.3 经过iNode认证:http://www.7forz.com/1973/
  4. openwrt SDK, 利用SDK生成本身的ipk安装包:http://blog.chinaunix.net/uid-27194309-id-3432651.html
相关文章
相关标签/搜索