uhttpd作为一个简单的web服务器,其代码量并不多,而且组织结构比较清楚。和其它网络服务器差不多,其main函数进行一些初始化(首先parse config-file,然后parse argv),然后进入一个循环,不断地监听,每当有一个客户请求到达时,则对它进行处理。
1、uhttpd uci配置参数说明
/etc/init.d/uhttpd脚本会使用procd的方式启动uhttpd进程,该工具后面可以带很多参数,如下:
root@zihome:~# uhttpd -h
uhttpd: option requires an argument -- h
Usage: uhttpd -p [addr:]port -h docroot
-f Do not fork to background
-c file Configuration file, default is '/etc/httpd.conf'
-p [addr:]port Bind to specified address and port, multiple allowed
-s [addr:]port Like -p but provide HTTPS on this port
-C file ASN.1 server certificate file
-K file ASN.1 server private key file
-h directory Specify the document root, default is '.'
-E string Use given virtual URL as 404 error handler
-I string Use given filename as index for directories, multiple allowed
-S Do not follow symbolic links outside of the docroot
-D Do not allow directory listings, send 403 instead
-R Enable RFC1918 filter
-n count Maximum allowed number of concurrent script requests
-N count Maximum allowed number of concurrent connections
-l string URL prefix for Lua handler, default is '/lua'
-L file Lua handler script, omit to disable Lua
-u string URL prefix for UBUS via JSON-RPC handler
-U file Override ubus socket path
-a Do not authenticate JSON-RPC requests against UBUS session api
-X Enable CORS HTTP headers on JSON-RPC api
-x string URL prefix for CGI handler, default is '/cgi-bin'
-i .ext=path Use interpreter at path for files with the given extension
-t seconds CGI, Lua and UBUS script timeout in seconds, default is 60
-T seconds Network timeout in seconds, default is 30
-k seconds HTTP keepalive timeout
-d string URL decode given string
-r string Specify basic auth realm
-m string MD5 crypt given string
openwrt上面还是通过uci来配置uhttpd,配置文件如下:
config uhttpd 'main'
list listen_http '0.0.0.0:80'
list listen_http '[::]:80'
list listen_https '0.0.0.0:443'
list listen_https '[::]:443'
option home '/www'
option rfc1918_filter '1'
option max_requests '3'
option max_connections '10'
option cert '/etc/uhttpd.crt'
option key '/etc/uhttpd.key'
option cgi_prefix '/cgi-bin'
option script_timeout '120'
option network_timeout '60'
option http_keepalive '60'
option tcp_keepalive '5'
option no_ubusauth '0'
option ubus_prefix '/ubus'
uHTTPd 配置项含义:
名 称 | 类 型 | 含 义 |
---|---|---|
listen_http | 字符串 | 定义服务器的 IP 和端口。指所监听的非加密的地址和端口。如果仅给出端口号,将同时服务于IPv4和IPv6请求。使用0.0.0.0:80仅绑定在 IPv4 接口,使用[::]:80 仅绑定 IPv6 |
home | 目录路径 | 定义服务器的文档根目录 |
max_requests | 整型数字 | 最大的并行请求数,如果大于这个值,后续的请求将进入排队队列中 |
cert | 文件路径 | 用于 HTTPS 连接的 ASN.1/DER 证书。在提供 HTTS 连接时必须提供 |
key | 文件路径 | 用于 HTTPS 连接的 ASN.1/DER 私钥。在提供 HTTPS 连接时必须提供 |
cgi_prefix | 字符串 | 定义 CGI 脚本的相对于根目录的前缀。如果没有该选项,CGI功能将不支持 |
script_timeout | 整型数字 | Lua 或CGI请求的最大等待时间秒值。如果没有输出产生,则超时后执行就结束了 |
network_timeout | 整型数字 | 网络活动的最大等待时间,如果指定的秒数内没有网络活动发生,则程序终止,连接关闭 |
tcp_keepalive | 整型数字 | tcp 心跳检测时间间隔,发现对端已不存在时则关闭连接。设置为 0 则关闭 tcp 心跳检测 |
realm | 字符串 | 基本认证的域值,默认为主机名,是当客户端进行基本认证的提示内容 |
config | 文件路径 | 用于基本认证的配置文件 |
no_dirlists | 是否显示文件列表 | 正常情况可以直接通过浏览器查看文件,不安全可以使用该字段屏蔽浏览器查看 |
max_requests | 最大请求数 | 同时处理的请求的最大数量。当这个数量被超过时,额外的请求将被放入队列中等待 |
max_connections | 最大连接数 | 同时处理的最大TCP连接数量。当这个数量被超过时,额外的TCP连接尝试将被放入队列中等待 |
ubus_prefix | ubus前缀 | 使用JSON-RPC访问,如http://192.168.18.1/ubus. |
ubus_noauth | session认证 | 关闭后可以不用认证,直接访问http接口 |
/etc/init.d/uhttpd脚本在启动的时候会去获取/etc/config/uhttpd配置里面的信息然后进行启动,我们现在用到的参数如下:
root@zihome:/# ps | grep uhttp
1395 root 1556 S /usr/sbin/uhttpd -f -h /www -r openwrt -x /cgi-bin -t 120 -T 60 -k 60 -A 5 -n 3 -N 10 -R -p 0.0.0.0:80 -p [::]:80
31572 root 1520 S grep uhttp
https://openwrt.org/docs/guide-user/services/webserver/uhttpd
2、uhttpd的登录认证超时机制
登录做为web登录最基础的功能,其背后是由rpcd提供的session模式实现的。
session模式实现了创建、更新、退出、添加acl权限等功能。
具体使用可以查看rpcd的介绍:
'session' @3602a25d
"create":{"timeout":"Integer"}
"list":{"ubus_rpc_session":"String"}
"grant":{"ubus_rpc_session":"String","scope":"String","objects":"Array"}
"revoke":{"ubus_rpc_session":"String","scope":"String","objects":"Array"}
"access":{"ubus_rpc_session":"String","scope":"String","object":"String","function":"String"}
"set":{"ubus_rpc_session":"String","values":"Table"}
"get":{"ubus_rpc_session":"String","keys":"Array"}
"unset":{"ubus_rpc_session":"String","keys":"Array"}
"destroy":{"ubus_rpc_session":"String"}
"login":{"username":"String","password":"String","timeout":"Integer"
3、ubus over http功能
在openwrt默认的web应用中,很主要的一共功能点,就是展示和设置信息。因为ubus -v list里面覆盖了大部分我们需要的信息,所以如果可以通过一种简单的rpc方案,通过http直接访问ubus的内容那就方便了。
这就是ubus over http功能,web发送一个http请求,这个请求的结构根据ubus命令封装之后,直接从ubus接口里面获取内容返回给web页面。
因为ubus接口里面包含了太多的信息,我们不想把所有信息都暴露给web,所以有了rpcd里面的acls权限管理。权限管理里面说明了只能执行那些命令。
使用该功能需要在uci里面把配置打开
option ubus_prefix /ubus
之后可以用postman发送post请求
登录:
{
"jsonrpc":"2.0",
"id":1,
"method":"call",
"params":[
"00000000000000000000000000000000",
"session",
"login",
{
"username":"root",
"password":"admin"
}
]
}
此时会返回该账号的session,还有权限之类的
{
"jsonrpc": "2.0",
"id": 1,
"result": [
0,
{
"ubus_rpc_session": "e5333f3fe2ed4601be3b0a8da0a6998e",
"timeout": 300,
"expires": 300,
"acls": {
"access-group": {
"luci-access": [
"read",
"write"
],
"luci-app-firewall": [
"read",
"write"
],
...
"uci-access": [
"read",
"write"
],
"unauthenticated": [
"read"
]
},
"cgi-io": {
"backup": [
"read"
],
"download": [
"read"
],
"exec": [
"read"
],
"upload": [
"write"
]
},
"file": {
"/": [
"list"
],
"/*": [
"list"
],
"/bin/dmesg -r": [
"exec"
],
...
"/usr/sbin/logread -e ^": [
"exec"
]
},
"ubus": {
"file": [
"list",
"read",
"stat",
"write",
"remove",
"exec"
],
"hostapd.*": [
"del_client"
],
"iwinfo": [
"assoclist",
"freqlist",
"txpowerlist",
"countrylist",
"scan"
],
"luci": [
"getFeatures",
"getConntrackList",
"getInitList",
"getLocaltime",
"getProcessList",
"getRealtimeStats",
"getTimezones",
"getLEDs",
"getUSBDevices",
"getSwconfigFeatures",
"getSwconfigPortState",
"getBlockDevices",
"getMountPoints",
"setInitAction",
"setLocaltime",
"setPassword",
"setBlockDetect",
"getConntrackHelpers"
],
"luci-rpc": [
"getBoardJSON",
"getDHCPLeases",
"getDSLStatus",
"getDUIDHints",
"getHostHints",
"getNetworkDevices",
"getWirelessDevices"
],
"network": [
"get_proto_handlers"
],
"network.interface": [
"dump"
],
"network.rrdns": [
"lookup"
],
"session": [
"access",
"login"
],
"system": [
"board",
"info",
"validate_firmware_image"
],
"uci": [
"changes",
"get",
"add",
"apply",
"confirm",
"delete",
"order",
"set",
"rename"
]
},
"uci": {
"*": [
"read",
"write"
],
...
"uhttpd": [
"read",
"write"
]
}
},
"data": {
"username": "root"
}
}
]
}
之后我们就可以使用这个session进行发送ubus请求,比如系统信息
{
"jsonrpc":"2.0",
"id":1,
"method":"call",
"params":[
"2cd182b0120310db8869b43d4340a307",
"system",
"board",
{
}
]
}
返回内容:
{
"jsonrpc": "2.0",
"id": 1,
"result": [
0,
{
"kernel": "4.14.275",
"hostname": "OpenWrt",
"system": "Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz",
"model": "VMware, Inc. VMware Virtual Platform",
"board_name": "vmware-inc-vmware-virtual-platform",
"release": {
"distribution": "OpenWrt",
"version": "19.07-SNAPSHOT",
"revision": "r11430-ecbbb37",
"target": "x86/64",
"description": "OpenWrt 19.07-SNAPSHOT r11430-ecbbb37"
}
}
]
}
可以看到返回的内容跟直接输入ubus call一致
root@OpenWrt:~# ubus call system board
{
"kernel": "4.14.275",
"hostname": "OpenWrt",
"system": "Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz",
"model": "VMware, Inc. VMware Virtual Platform",
"board_name": "vmware-inc-vmware-virtual-platform",
"release": {
"distribution": "OpenWrt",
"version": "19.07-SNAPSHOT",
"revision": "r11430-ecbbb37",
"target": "x86/64",
"description": "OpenWrt 19.07-SNAPSHOT r11430-ecbbb37"
}
}
当然如果不属于上面权限的ubus消息是无法发送的,比如
{
"jsonrpc":"2.0",
"id":1,
"method":"call",
"params":[
"2cd182b0120310db8869b43d4340a307",
"network.interface.lan",
"status",
{
}
]
}
返回没有权限
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32002,
"message": "Access denied"
}
}
这些权限的配置都位于/usr/share/rpcd/acl.d/
目录下面配置,我们可以自己按照规则增删。
上面json请求的结构体描述如下:
{ "jsonrpc": "2.0",
"id": <unique-id-to-identify-request>,
"method": "call",
"params": [
<ubus_rpc_session>, <ubus_object>, <ubus_method>,
{ <ubus_arguments> }
]
}
{ "jsonrpc": "2.0", "id": 1, "method": "call", "params": [ "c1ed6c7b025d0caca723a816fa61b668", "file", "read", { "path": "/etc/board.json" } ] }
how to use ubus over http in openwrt 12.09
:https://www.cnblogs.com/nicephil/p/6768381.html#e4bdbfe794a8e696b9e6b395_2
openwrt-rpcd服务ACL配置错误风险分析:https://www.cnblogs.com/hac425/p/9416854.html
https://openwrt.org/docs/techref/ubus#access_to_ubus_over_http
4、cgi框架
要运行cgi程序,首先意味着需fork出一个子进程,并通过execl函数替换进程空间为cgi程序;其次,数据传递,子进程替换了进程空间后,怎么获得原信息,有怎么把回馈数据传输给父进程(即uhttpd),父进程又怎么接收这些数据。
https://www.cnblogs.com/zmkeil/archive/2013/05/14/3078766.html