uhttpd作為一個(gè)簡(jiǎn)單的web服務(wù)器,其代碼量并不多,而且組織結(jié)構(gòu)比較清楚。和其它網(wǎng)絡(luò)服務(wù)器差不多,其main函數(shù)進(jìn)行一些初始化(首先parse config-file,然后parse argv),然后進(jìn)入一個(gè)循環(huán),不斷地監(jiān)聽,每當(dāng)有一個(gè)客戶請(qǐng)求到達(dá)時(shí),則對(duì)它進(jìn)行處理。
1、uhttpd uci配置參數(shù)說明
/etc/init.d/uhttpd腳本會(huì)使用procd的方式啟動(dòng)uhttpd進(jìn)程,該工具后面可以帶很多參數(shù),如下:
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 配置項(xiàng)含義:
名 稱 | 類 型 | 含 義 |
---|---|---|
listen_http | 字符串 | 定義服務(wù)器的 IP 和端口。指所監(jiān)聽的非加密的地址和端口。如果僅給出端口號(hào),將同時(shí)服務(wù)于IPv4和IPv6請(qǐng)求。使用0.0.0.0:80僅綁定在 IPv4 接口,使用[::]:80 僅綁定 IPv6 |
home | 目錄路徑 | 定義服務(wù)器的文檔根目錄 |
max_requests | 整型數(shù)字 | 最大的并行請(qǐng)求數(shù),如果大于這個(gè)值,后續(xù)的請(qǐng)求將進(jìn)入排隊(duì)隊(duì)列中 |
cert | 文件路徑 | 用于 HTTPS 連接的 ASN.1/DER 證書。在提供 HTTS 連接時(shí)必須提供 |
key | 文件路徑 | 用于 HTTPS 連接的 ASN.1/DER 私鑰。在提供 HTTPS 連接時(shí)必須提供 |
cgi_prefix | 字符串 | 定義 CGI 腳本的相對(duì)于根目錄的前綴。如果沒有該選項(xiàng),CGI功能將不支持 |
script_timeout | 整型數(shù)字 | Lua 或CGI請(qǐng)求的最大等待時(shí)間秒值。如果沒有輸出產(chǎn)生,則超時(shí)后執(zhí)行就結(jié)束了 |
network_timeout | 整型數(shù)字 | 網(wǎng)絡(luò)活動(dòng)的最大等待時(shí)間,如果指定的秒數(shù)內(nèi)沒有網(wǎng)絡(luò)活動(dòng)發(fā)生,則程序終止,連接關(guān)閉 |
tcp_keepalive | 整型數(shù)字 | tcp 心跳檢測(cè)時(shí)間間隔,發(fā)現(xiàn)對(duì)端已不存在時(shí)則關(guān)閉連接。設(shè)置為 0 則關(guān)閉 tcp 心跳檢測(cè) |
realm | 字符串 | 基本認(rèn)證的域值,默認(rèn)為主機(jī)名,是當(dāng)客戶端進(jìn)行基本認(rèn)證的提示內(nèi)容 |
config | 文件路徑 | 用于基本認(rèn)證的配置文件 |
no_dirlists | 是否顯示文件列表 | 正常情況可以直接通過瀏覽器查看文件,不安全可以使用該字段屏蔽瀏覽器查看 |
max_requests | 最大請(qǐng)求數(shù) | 同時(shí)處理的請(qǐng)求的最大數(shù)量。當(dāng)這個(gè)數(shù)量被超過時(shí),額外的請(qǐng)求將被放入隊(duì)列中等待 |
max_connections | 最大連接數(shù) | 同時(shí)處理的最大TCP連接數(shù)量。當(dāng)這個(gè)數(shù)量被超過時(shí),額外的TCP連接嘗試將被放入隊(duì)列中等待 |
ubus_prefix | ubus前綴 | 使用JSON-RPC訪問,如http://192.168.18.1/ubus. |
ubus_noauth | session認(rèn)證 | 關(guān)閉后可以不用認(rèn)證,直接訪問http接口 |
/etc/init.d/uhttpd腳本在啟動(dòng)的時(shí)候會(huì)去獲取/etc/config/uhttpd配置里面的信息然后進(jìn)行啟動(dòng),我們現(xiàn)在用到的參數(shù)如下:
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的登錄認(rèn)證超時(shí)機(jī)制
登錄做為web登錄最基礎(chǔ)的功能,其背后是由rpcd提供的session模式實(shí)現(xiàn)的。
session模式實(shí)現(xiàn)了創(chuàng)建、更新、退出、添加acl權(quán)限等功能。
具體使用可以查看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默認(rèn)的web應(yīng)用中,很主要的一共功能點(diǎn),就是展示和設(shè)置信息。因?yàn)閡bus -v list里面覆蓋了大部分我們需要的信息,所以如果可以通過一種簡(jiǎn)單的rpc方案,通過http直接訪問ubus的內(nèi)容那就方便了。
這就是ubus over http功能,web發(fā)送一個(gè)http請(qǐng)求,這個(gè)請(qǐng)求的結(jié)構(gòu)根據(jù)ubus命令封裝之后,直接從ubus接口里面獲取內(nèi)容返回給web頁面。
因?yàn)閡bus接口里面包含了太多的信息,我們不想把所有信息都暴露給web,所以有了rpcd里面的acls權(quán)限管理。權(quán)限管理里面說明了只能執(zhí)行那些命令。
使用該功能需要在uci里面把配置打開
option ubus_prefix /ubus
之后可以用postman發(fā)送post請(qǐng)求
登錄:
{
"jsonrpc":"2.0",
"id":1,
"method":"call",
"params":[
"00000000000000000000000000000000",
"session",
"login",
{
"username":"root",
"password":"admin"
}
]
}
此時(shí)會(huì)返回該賬號(hào)的session,還有權(quán)限之類的
{
"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"
}
}
]
}
之后我們就可以使用這個(gè)session進(jìn)行發(fā)送ubus請(qǐng)求,比如系統(tǒng)信息
{
"jsonrpc":"2.0",
"id":1,
"method":"call",
"params":[
"2cd182b0120310db8869b43d4340a307",
"system",
"board",
{
}
]
}
返回內(nèi)容:
{
"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"
}
}
]
}
可以看到返回的內(nèi)容跟直接輸入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"
}
}
當(dāng)然如果不屬于上面權(quán)限的ubus消息是無法發(fā)送的,比如
{
"jsonrpc":"2.0",
"id":1,
"method":"call",
"params":[
"2cd182b0120310db8869b43d4340a307",
"network.interface.lan",
"status",
{
}
]
}
返回沒有權(quán)限
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32002,
"message": "Access denied"
}
}
這些權(quán)限的配置都位于/usr/share/rpcd/acl.d/
目錄下面配置,我們可以自己按照規(guī)則增刪。
上面json請(qǐng)求的結(jié)構(gòu)體描述如下:
{ "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服務(wù)ACL配置錯(cuò)誤風(fēng)險(xiǎn)分析:https://www.cnblogs.com/hac425/p/9416854.html
https://openwrt.org/docs/techref/ubus#access_to_ubus_over_http
4、cgi框架
要運(yùn)行cgi程序,首先意味著需fork出一個(gè)子進(jìn)程,并通過execl函數(shù)替換進(jìn)程空間為cgi程序;其次,數(shù)據(jù)傳遞,子進(jìn)程替換了進(jìn)程空間后,怎么獲得原信息,有怎么把回饋數(shù)據(jù)傳輸給父進(jìn)程(即uhttpd),父進(jìn)程又怎么接收這些數(shù)據(jù)。
https://www.cnblogs.com/zmkeil/archive/2013/05/14/3078766.html