OpenWRT UCI介绍及相关处理库


文章目录

1. 前言

基本上OpenWrt上相关的配置都可以使用UCI进行配置,这对我们进行自动化配置路由器相当有帮助,我们可以很方便的将配置过程写入脚本或者写入程序,所以这里大致总结以下uci常用命令以及一些相关的库。

2. 概念

UCI系统(https://openwrt.org/zh/docs/guide-user/base-system/uci):

“uci”是“Unified Configuration Interface”(统一配置界面)的缩写,意在OpenWrt整个系统的配置集中化。

系统配置应容易,更直接且在此有文档描述,从而使你的生活更轻松!

(它是White Russian系列OpenWrt基于nvram的配置的后继改进。)

许多程序在系统某处拥有自己的配置文件,

比如​​/etc/network/interfaces​​​, ​​/etc/exports​​​, ​​/etc/dnsmasq.conf​​​或者 ​​/etc/samba/samba.conf​​,

有时它们还使用稍有不同的语法。

在OpenWrt中你无需为此烦恼,我们只需更改UCI配置文件!

不需要为了某个更改起效而重启系统!参阅下文中的​​命令行实用工具​​以了解如何做到这点。

还有不要忘了官方程序包(official binaries)里包含了很多后台程序,但默认情况下并未启用!

比如cron后台程序默认并未激活,因而只编辑crontab并无作用。

你需要用​​/etc/init.d/crond start​​​起动它或用​​/etc/init.d/crond enable​​​激活它。 大部分后台程序都可以​​disable​​​(禁用),​​stop​​​(停止)和​​restart​​​(重起)。 还有一些​​非UCI配置​​你可以参阅。

3. UCI配置文件

OpenWrt的所有配置文件皆位于/etc/config/目录下。每个文件大致与它所配置的那部分系统相关。可用文本编辑器、“uci” 命令行实用程序或各种编程API(比如 Shell, Lua and C)来编辑/修改这些配置文件。

文件位置

描述

基本配置

​/etc/config/dhcp​

dnsmasq和DHCP的配置

​/etc/config/dropbear​

SSH服务端选项

​/etc/config/firewall​

中央防火墙配置

​/etc/config/network​

交换,接口和路由配置

​/etc/config/system​

杂项与系统配置

​/etc/config/timeserver​

rdate的时间服务器列表

​/etc/config/wireless​

无线设置和无线网络的定义

IPv6

​/etc/config/ahcpd​

Ad-Hoc配置协议(AHCP) 服务端配置以及转发器配置

​/etc/config/aiccu​

AICCU 客户端配置

​/etc/config/dhcp6c​

WIDE-DHCPv6 客户端配置

​/etc/config/dhcp6s​

WIDE-DHCPv6 服务端配置

​/etc/config/gw6c​

GW6c 客户端配置

​/etc/config/radvd​

路由通告 (radvd) 配置

其他

​/etc/config/etherwake​

以太网唤醒: etherwake

​/etc/config/fstab​

挂载点及swap

​/etc/config/hd-idle​

另一个可选的硬盘空闲休眠进程(需要路由器支持usb硬盘)

​/etc/config/httpd​

网页服务器配置选项(Busybox 自带httpd, 已被舍弃)

​/etc/config/luci​

基础 LuCI 配置

​/etc/config/luci_statistics​

包统计配置

​/etc/config/mini_snmpd​

mini_snmpd 配置

​/etc/config/mountd​

OpenWrt 自动挂载进程(类似autofs)

​/etc/config/multiwan​

简单多WAN出口配置

​/etc/config/ntpclient​

ntp客户端配置,用以获取正确时间

​/etc/config/pure-ftpd​

Pure-FTPd 服务端配置

​/etc/config/qos​

QoS配置(流量限制与整形)

​/etc/config/samba​

samba配置(Microsoft文件共享)

​/etc/config/snmpd​

SNMPd(snmp服务进程) 配置

​/etc/config/sshtunnel​

​sshtunnel​​配置

​/etc/config/stund​

STUN 服务端配置

​/etc/config/transmission​

BitTorrent配置

​/etc/config/uhttpd​

Web服务器配置(uHTTPd)

​/etc/config/upnpd​

miniupnpd UPnP服务器配置

​/etc/config/ushare​

uShare UPnP 服务器配置

​/etc/config/vblade​

vblade 用户空间AOE(ATA over Ethernet)配置

​/etc/config/vnstat​

vnstat 下载器配置

​/etc/config/wifitoogle​

使用按钮来开关WiFi的脚本

​/etc/config/wol​

Wake-on-Lan: wol

​/etc/config/znc​

ZNC 配置

4. 文件语法

在UCI的配置文件通常包含一个或多个配置语句,包含一个或多个用来定义实际值的选项语句的所谓的节。

下面是一个简单的配置示例文件:

package 'example'

config 'example' 'test'
option 'string' 'some value'
option 'boolean' '1'
list 'collection' 'first item'
list 'collection' 'second item'
  • config ‘example’ ‘test’ 语句标志着一个节(section)的开始。这里的配置类型(secType)是​​example​​,配置名(option)是​​test​​。配置中也允许出现匿名节,即自定义了配置类型,而没有配置名的节。配置类型对应配置处理程序来说是十分重要的,因为配置程序需要根据这些信息来处理这些配置项。
  • ​option 'string' 'some value'​​​和 ​​option 'boolean' '1'​​定义了一些简单值。文本选项和布尔选项在语法上并没有差异。布尔选项中可以用’0’ , ‘no’, ‘off’, 或者’false’来表示false值,或者也可以用’1’, ‘yes’,'on’或者’true’来表示真值。
  • 以list关键字开头的多个行,可用于定义包含多个值的选项。所有共享一个名称的list语句,会组装形成一个值列表,列表中每个值出现的顺序,和它在配置文件中的顺序相同。如上例中,列表的名称是’collection’,它包含了两个值,即’first item’和’second item’。
  • 'option’和’list’语句的缩进可以增加配置文件的可读性,但是在语法不是必须的。

通常不需要为标识符和值加引号,只有当值包括空格或者制表符的时候,才必须加引号。同时,在使用引号的时候,可以用双引号代替单引号。

下面列举的例子都是符合uci语法的正确配置:

  • ​option example value​
  • ​option 'example' value​
  • ​option example “value”​
  • ​option “example” 'value'​
  • ​option 'example' “value”​

反之,以下配置则存在语法错误

  • ​option 'example“ “value'​​(引号不匹配)
  • ​option example some value with space​​(值中包含空格,需要为值加引号)

还有一点是必须知道的,即UCI标识符和配置文件名称所包含的字符必须是由​​a-z​​​, ​​0-9​​​和​​_​​组成。 选项值则可以包含任意字符,只要这个值是加了引号的。

5. 命令行实用工具

使用awk、grep等命令来解析Openwrt的配置文件是低效和不明智的做法,建议用户通过uci工具对openwrt进行配置。

下面将给出一些例子,来展示uci这个强大的工具。

5.1 用法

root@OpenWrt:~# uci
Usage: uci [<options>] <command> [<arguments>]

Commands:
batch
export [<config>]
import [<config>]
changes [<config>]
commit [<config>]
add <config> <section-type>
add_list <config>.<section>.<option>=<string>
del_list <config>.<section>.<option>=<string>
show [<config>[.<section>[.<option>]]]
get <config>.<section>[.<option>]
set <config>.<section>[.<option>]=<value>
delete <config>[.<section>[[.<option>][=<id>]]]
rename <config>.<section>[.<option>]=<name>
revert <config>[.<section>[.<option>]]
reorder <config>.<section>=<position>

Options:
-c <path> set the search path for config files (default: /etc/config)
-d <str> set the delimiter for list values in uci show
-f <file> use <file> as input instead of stdin
-m when importing, merge data into an existing package
-n name unnamed sections on export (default)
-N don't name unnamed sections
-p <path> add a search path for config change files
-P <path> add a search path for config change files and use as default
-q quiet mode (don't print error messages)
-s force strict mode (stop on parser errors, default)
-S disable strict mode
-X do not use extended syntax on 'show'

5.2 示例

导出整个配置

root@OpenWrt:~# uci export uhttpd
package uhttpd

config uhttpd 'main'
list listen_https '0.0.0.0:443'
list listen_https '[::]:443'
option redirect_https '0'
option home '/www'
option rfc1918_filter '0'
option max_requests '3'
option max_connections '100'
option cert '/etc/uhttpd.crt'
option key '/etc/uhttpd.key'
option cgi_prefix '/cgi-bin'
list lua_prefix '/cgi-bin/luci=/usr/lib/lua/luci/sgi/uhttpd.lua'
option script_timeout '60'
option network_timeout '30'
option http_keepalive '20'
option tcp_keepalive '1'
list listen_http '0.0.0.0:81'
list listen_http '[::]:81'
list listen_http '0.0.0.0:8082'

config cert 'defaults'
option days '730'
option key_type 'rsa'
option bits '2048'
option ec_curve 'P-256'
option country 'ZZ'
option state 'Somewhere'
option location 'Unknown'
option commonname 'OpenWrt'

查看所有配置项的值

root@OpenWrt:~# uci show uhttpd
uhttpd.main=uhttpd
uhttpd.main.listen_https='0.0.0.0:443' '[::]:443'
uhttpd.main.redirect_https='0'
uhttpd.main.home='/www'
uhttpd.main.rfc1918_filter='0'
uhttpd.main.max_requests='3'
uhttpd.main.max_connections='100'
uhttpd.main.cert='/etc/uhttpd.crt'
uhttpd.main.key='/etc/uhttpd.key'
uhttpd.main.cgi_prefix='/cgi-bin'
uhttpd.main.lua_prefix='/cgi-bin/luci=/usr/lib/lua/luci/sgi/uhttpd.lua'
uhttpd.main.script_timeout='60'
uhttpd.main.network_timeout='30'
uhttpd.main.http_keepalive='20'
uhttpd.main.tcp_keepalive='1'
uhttpd.main.listen_http='0.0.0.0:81' '[::]:81' '0.0.0.0:8082'
uhttpd.defaults=cert
uhttpd.defaults.days='730'
uhttpd.defaults.key_type='rsa'
uhttpd.defaults.bits='2048'
uhttpd.defaults.ec_curve='P-256'
uhttpd.defaults.country='ZZ'
uhttpd.defaults.state='Somewhere'
uhttpd.defaults.location='Unknown'
uhttpd.defaults.commonname='OpenWrt'

查看特定选项的值

root@OpenWrt:~# uci get uhttpd.@uhttpd[0].listen_http
0.0.0.0:81 [::]:81 0.0.0.0:8082

查看网络接口的状态

root@OpenWrt:~# uci -P/var/state show network.wan
network.wan=interface
network.wan.ifname='eth7'
network.wan.proto='dhcp'

root@OpenWrt:~# uci -P/var/state show network.wan_eth
network.wan_eth=interface
network.wan_eth.ifname='eth0'
network.wan_eth.proto='static'
network.wan_eth.netmask='255.255.255.0'
network.wan_eth.gateway='192.168.67.254'
network.wan_eth.dns='8.8.8.8'
network.wan_eth.ipaddr='192.168.67.87'
network.wan_eth.up='1'

添加防火墙规则

这是一个添加SSH端口转发到防火墙规则的例子,和’-1’使用的一个例子。

root@OpenWrt:~# uci add firewall rule
root@OpenWrt:~# uci set firewall.@rule[-1].src=wan
root@OpenWrt:~# uci set firewall.@rule[-1].target=ACCEPT
root@OpenWrt:~# uci set firewall.@rule[-1].proto=tcp
root@OpenWrt:~# uci set firewall.@rule[-1].dest_port=22
root@OpenWrt:~# uci commit firewall
root@OpenWrt:~# /etc/init.d/firewall restart

5.3 场景示例

更改uhttpd监听端口

比如我们要将我们的配置web配置到80端口,这就需要更改uhttpd默认监听的80端口为其它端口,这里就可以将该更改uhttpd监听80端口更改为81端口的过程写入shell脚本执行,以此方便一键化部署配置web(当然实际批量生产时打包固件即可),如下是将该过程简单写为shell函数的代码(会将原本的uhttpd配置文件备份,然后判断相关端口是否被监听,是则删除后增加,由于list没有更改功能所以实用删除后增加的方式进行修改):

# 利用uci命令修改uhttpd对80端口和8080端口的监听,便于nginx监听80端口方便访问自研配置web
function uhttpd_uci_conf() {
echo "--------------------设置uhttpd监听端口---------------"
uhttpd_back="/etc/config/uhttpd_back"
# 这里的-f参数判断$myFile是否存在
if [ ! -f "$uhttpd_back" ]; then
cp /etc/config/uhttpd $uhttpd_back
fi
echo "###old uhttpd info:"
uci show uhttpd

listen_http1='0.0.0.0:80'
listen_http2='[::]:80'
listen_http3='0.0.0.0:8080'
if ! grep "$listen_http1" /etc/config/uhttpd >/dev/null
then
#不存在,不做处理
echo "uhttpd not listen 80 port."
else
#存在,删除,然后添加81端口
uci del_list uhttpd.main.listen_http='0.0.0.0:80'
uci del_list uhttpd.main.listen_http='[::]:80'
uci del_list uhttpd.main.listen_http='0.0.0.0:8080'

uci add_list uhttpd.main.listen_http='0.0.0.0:81'
uci add_list uhttpd.main.listen_http='[::]:81'
uci add_list uhttpd.main.listen_http='0.0.0.0:8082'

uci commit
echo "###new uhttpd info:"
uci show uhttpd
fi
echo "--------------------设置uhttpd监听端口完成-----------"
}

配置端口转发

此外,可以设想一下如下场景,我们将家里某个子设备PC当成服务器,而该PC的外网IP取决于路由器配置的外网IP,这时我们可以将PC的IP设置为静态IP,然后将其某些端口映射到路由器的外网IP某些端口上,这样我们就可以访问外网IP某个端口来访问PC上的对应端口了,一些大的资源不用放在路由器上我们外网也可以访问,搭建个人云盘、个人服务器都变得可行(自媒体这么火,在隐私越来越重视的情况下,我想未来将服务器、网盘等都建立在自己家中这种事也会有一定的市场空间,而ipv6普及之后外网IP的制约条件也会消失)。

这里是一个简单的端口映射shell脚本函数(可以将这些参数以外部传参的方式或者配置文件的形式读取都可以):

function add_redirect() {
uci add firewall redirect
uci set firewall.@redirect[-1].dest_port='80'
uci set firewall.@redirect[-1].src='wan'
uci set firewall.@redirect[-1].src_dport='10080'
uci set firewall.@redirect[-1].target='DNAT'
uci set firewall.@redirect[-1].dest_ip='192.168.1.200'
uci set firewall.@redirect[-1].dest='lan'
uci commit

/etc/init.d/firewall restart
uci show firewall
}

6. 常用的库

luci:包含Lua和js以及c的接口,所以熟悉前端和openwrt的完全可以用js进行openwrt配置:https://github.com/openwrt/luci

go-uci:https://github.com/digineo/go-uci