不久前我将 ubuntu 系统改造成了我的主路由器,但是它真的太臃肿了,不过我也通过折腾它学习了不少知识。因为我只需要 iptables dnsmasq 等基本功能就够了, 所以我需要一个足够轻量的路由器系统,OpenWrt 正是我想要的。OpenWrt 是适合于嵌入式设备的一个 Linux 发行版,它非常的小巧,所有功能都以 package 的形式运行, 并且提供 web 界面进行管理,小米、极路由等很多智能路由器都在用它。

那么直接使用 OpenWrt 系统会是更好的选择,因为我需要在路由器上跑一些“特殊”功能,所以我只需要将它做成 OpenWrt 的插件直接在 web 界面管理就行了。

预置条件

我默认你已经写好了自己的“插件”,它可能是一个 shell 脚本,也可能是 c golang 或者别的编程语言写好的程序,它已经实现了你需要的功能, 你目前只是需要将它打包为 OpenWrt 的一个插件。当然你可以写一个简单的重启功能脚本来做练习。我自己的程序名称叫 bargo 下面就用它来举例。

Web 管理界面开发

我们的插件一般都需要做一些动态的配置,OpenWrt 很好的支持了这一切。OpenWrt 的 web 界面也是传统的 MVC 结构,主要用 lua 脚本来编写, 我们只需要按照它的文档规则“填空”就能做出一个简单的配置页面。web 管理里面的主要代码在系统的 /usr/lib/lua/luci 目录,里面就能看到 MVC 目录。

先创建控制器文件 /usr/lib/lua/luci/controller/bargo.lua

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# module 名称
module("luci.controller.bargo", package.seeall)

function index()
    # 4 个参数介绍
    # 1.后台访问路径 admin/services/bargo 
    # 2.target 动作(call, template, cbicall 是调用自定义函数,template 调用 html 模板,cbi 调用 openwrt 的公共表单页面
    # 3.菜单名称 
    # 4.排序
    entry({"admin", "services", "bargo"}, cbi("bargo"), _("Bargo Client"), 1)
end

现在就可以在 web 后台能看到这个菜单并进入了。

1

下面我们来创建插件的配置文件 /etc/config/bargo

1
2
3
config server
option username ''
option password ''

我的插件只需要两个配置信息,用户名和密码。现在我们需要创建表单页面来管理它。上面我们在控制器里写了 cbi(“bargo”) 的调用,我现在只需要 创建一个 cbi 文件,控制器就能根据 cbi 文件自动的用我们的配置信息来生成 web 管理页面。

创建 cbi 文件 /usr/lib/lua/luci/model/cbi/bargo.lua

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
require("luci.sys")

# 页面标题和描述
m = Map("bargo", translate("Bargo Client"), translate("Configure Bargo client, Powered By Sinchie."))

# 读取配置文件
s = m:section(TypedSection, "server", "")
s.addremove = false
s.anonymous = true

# 是否启用的选择框
enable = s:option(Flag, "enable", translate("Enable"))
# 映射我们的配置到输入框
username = s:option(Value, "username", translate("Username"))
pass = s:option(Value, "password", translate("Password"))
pass.password = true

# 如果点击了保存按钮
local apply = luci.http.formvalue("cbi.apply")
if apply then
    # 这里是调用我们自己的程序脚本,后面会讲怎么来写这个脚本
    io.popen("/etc/init.d/bargo restart > /dev/null &")
end

return m

2

这样我们的 web 管理页面就写完了,是不是超级简单,就像是“填空”一样,更多详情配置请参考 官方文档

启动脚本

上面我们的 cbi 文件中写了 /etc/init.d/bargo restart 这个命令,那么我们来编写这个脚本。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/bin/sh /etc/rc.common

# 启动顺序
START=95

# start 函数
start() {
    # 载入/etc/config/bargo 中的配置信息,以供我们的程序使用
    config_load bargo
    # 可以判断 enable 是否勾选并执行我们的程序
    ......
    echo "Bargo Client has start."
}

stop() {
    # 清理程序产生的内容
    echo "Bargo Client has stoped."
}

现在我们就能使用 /etc/init.d/bargo start|stop|restart 命令行来控制我们的程序了,当然使用 web 页面也是可以的。 更多详细参数请参考使用文档配置文档

打包 package

现在我们需要将我们的管理页面,配置文件,主程序打包为 package,然后就使用就可以 opkg install mypackage 安装了,这样也方便分享,我的编译目录如下。

├── Makefile
└── files
    ├── etc
    │   ├── config
    │   │   └── bargo
    │   └── init.d
    │       └── bargo.sh
    └── usr
        ├── lib
        │   └── lua
        │       └── luci
        │           ├── controller
        │           │   └── bargo.lua
        │           └── model
        │               └── cbi
        │                   └── bargo.lua
        ├── sbin
        │   ├── bargo

主编译配置文件名字为 Makefile,这个文件是最关键的文件,是编译 package 的入口文件。这个文件中定义了插件名称,版本,分类,依赖,怎么编译,安装路径等等信息。 我自己的 package 名字叫 Bargo,下面是它的 Makefile demo。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
include $(TOPDIR)/rules.mk

PKG_NAME:=bargo
PKG_VERSION:=1.0.0
PKG_RELEASE:=1

PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)

include $(INCLUDE_DIR)/package.mk

# 定义基础信息
define Package/bargo
    SECTION:=utils
    CATEGORY:=Utilities
    TITLE:=Bargo configuration utility
    DEPENDS:=+ipset +dnsmasq-full +curl
    URL:=https://sinchie.com/
    MAINTAINER:=sinchie
endef

# 描述信息
define Package/bargo/description
    This package contains LuCI configuration pages for bargo.
endef

# 安装方法
define Package/bargo/install
    # 这部分是代码是初始化安装目录
    $(INSTALL_DIR) $(1)/etc/config
    $(INSTALL_DIR) $(1)/etc/init.d
    $(INSTALL_DIR) $(1)/usr/lib/lua/luci/model/cbi
    $(INSTALL_DIR) $(1)/usr/lib/lua/luci/controller
    $(INSTALL_DIR) $(1)/usr/sbin

    # 这里是将需要的文件 copy 的系统中
    $(INSTALL_CONF) ./files/etc/config/bargo $(1)/etc/config/bargo
    $(INSTALL_BIN) ./files/etc/init.d/bargo.sh $(1)/etc/init.d/bargo
    $(INSTALL_DATA) ./files/usr/lib/lua/luci/model/cbi/bargo.lua $(1)/usr/lib/lua/luci/model/cbi/bargo.lua
    $(INSTALL_DATA) ./files/usr/lib/lua/luci/controller/bargo.lua $(1)/usr/lib/lua/luci/controller/bargo.lua
    $(INSTALL_BIN) ./files/usr/sbin/bargo $(1)/usr/sbin/bargo
endef

$(eval $(call BuildPackage,bargo))

关于 Makefile 更全面的语法可以参考 官方文档

编译环境

如何搭建 OpenWrt 编译环境我就不做过多的赘述了,官方文档里写有详细信息,比如需要什么版本的 ubuntu 系统,需要安装那些依赖。 我自己是在自己的小服务器开了一个虚拟机来做编译环境,官方文档

环境搭建完毕下载 sdk 就可以开始编译了,官方文档

执行编译

将我们的 package 目录复制到 sdk 的 package 目录中,然后执行 make V=s package/bargo/compile 就好了。 等待编译结束,我们就可以在 sdk 的 bin 目录下找到我们编译好的 bargo_1.0.0-1_x86_64.ipk。

结束

现在我们就可以拿着编译好的 ipk 文件,分享给亲朋好友了。

只需要在 OpenWrt 系统中执行 opkg install /your/path/youripk 就能使用你的插件了。