34-Openwrt uhttpd与rpcd

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

相关推荐
To_再飞行1 天前
K8s 调度管理
linux·云原生·kubernetes
2302_799525741 天前
【Hadoop】Hadoop集群安装中出现的问题
linux·hadoop
刘一说1 天前
Linux调试命令速查:Java/微服务必备
java·linux·微服务
枫の准大一1 天前
【Linux游记】基础指令篇
linux
ypf52081 天前
OrbStack 配置国内镜像加速
linux
Hello.Reader1 天前
一文通关 Proto3完整语法与工程实践
java·linux·数据库·proto3
Hello.Reader1 天前
一文吃透 Protobuf “Editions” 模式从概念、语法到迁移与实战
linux·服务器·网络·protobuf·editions
陌上花开缓缓归以1 天前
linux ubi文件系统
linux
口嗨农民工1 天前
exiftool 分析jpeg图片使用
linux
大明者省1 天前
pycharm解释器使用anaconda建立的虚拟环境里面的python,无需系统里面安装python。
linux·python·pycharm