[RFC] nginx-util: use UCI for server configurationlilik-openwrt-22.03
@ -0,0 +1,475 @@ | |||||
#!/bin/sh | |||||
# This is a template copy it by: ./README.sh | xclip -selection c | |||||
# to https://openwrt.org/docs/guide-user/services/webserver/nginx#configuration | |||||
NGINX_UTIL="/usr/bin/nginx-util" | |||||
EXAMPLE_COM="example.com" | |||||
MSG=" | |||||
/* Created by the following bash script that includes the source of some files: | |||||
* https://github.com/openwrt/packages/net/nginx-util/files/README.sh | |||||
*/" | |||||
eval $("${NGINX_UTIL}" get_env) | |||||
code() { | |||||
local file | |||||
[ $# -gt 1 ] && file="$2" || file="$(basename "$1")" | |||||
printf "<file nginx %s>\n%s</file>" "$1" "$(cat "${file}")"; | |||||
} | |||||
ifConfEcho() { | |||||
sed -nE "s/^\s*$1=\s*(\S*)\s*\\\\$/\n$2 \"\1\";/p" ../../nginx/Makefile; | |||||
} | |||||
cat <<EOF | |||||
===== Configuration =====${MSG} | |||||
The official Documentation contains a | |||||
[[https://docs.nginx.com/nginx/admin-guide/|Admin Guide]]. | |||||
Here we will look at some often used configuration parts and how we handle them | |||||
at OpenWrt. | |||||
At different places there are references to the official | |||||
[[https://docs.nginx.com/nginx/technical-specs/|Technical Specs]] | |||||
for further reading. | |||||
**tl;dr:** When starting Nginx by ''/etc/init.d/nginx'', it creates its main | |||||
configuration dynamically based on a minimal template and the | |||||
[[docs:guide-user:base-system:uci|🡒UCI]] configuration. | |||||
The UCI ''/etc/config/nginx'' contains initially: | |||||
| ''config server '${LAN_NAME}''' | \ | |||||
Default server for the LAN, which includes all ''${CONF_DIR}*.locations''. | | |||||
| ''config server '_redirect2ssl''' | \ | |||||
Redirects inexistent URLs to HTTPS. | | |||||
It enables also the ''${CONF_DIR}'' directory for further configuration: | |||||
| ''${CONF_DIR}\$NAME.conf'' | \ | |||||
Is included in the main configuration. \ | |||||
It is prioritized over a UCI ''config server '\$NAME' ''. | | |||||
| ''${CONF_DIR}\$NAME.locations'' | \ | |||||
Is include in the ''${LAN_NAME}'' server and can be re-used for others, too. | | |||||
| ''$(dirname "${CONF_DIR}")/restrict_locally'' | \ | |||||
Is include in the ''${LAN_NAME}'' server and allows only accesses from LAN. | | |||||
Setup configuration (for a server ''\$NAME''): | |||||
| ''$(basename ${NGINX_UTIL}) [${ADD_SSL_FCT}|del_ssl] \$NAME'' | \ | |||||
Add/remove a self-signed certificate and corresponding directives. | | |||||
| ''uci set nginx.\$NAME.access_log='logd openwrt''' | \ | |||||
Writes accesses to Openwrt’s \ | |||||
[[docs:guide-user:base-system:log.essentials|🡒logd]]. | | |||||
| ''uci set nginx.\$NAME.error_log='logd' '' | \ | |||||
Writes errors to Openwrt’s \ | |||||
[[docs:guide-user:base-system:log.essentials|🡒logd]]. | | |||||
| ''uci [set|add_list] nginx.\$NAME.key='value' '' | \ | |||||
Becomes a ''key value;'' directive if the //key// does not start with //uci_//. | | |||||
| ''uci set nginx.\$NAME=[disable|server]'' |\ | |||||
Disable/enable inclusion in the dynamic conf.| | |||||
| ''uci set nginx.global.uci_enable=false'' | \ | |||||
Use a custom ''${NGINX_CONF}'' rather than a dynamic conf. | | |||||
==== Basic ====${MSG} | |||||
We modify the configuration by changing servers saved in the UCI configuration | |||||
at ''/etc/config/nginx'' and/or by creating different configuration files in the | |||||
''${CONF_DIR}'' directory. | |||||
These files use the file extensions ''.locations'' and ''.conf'' plus ''.crt'' | |||||
and ''.key'' for SSL certificates and keys.(( | |||||
We can disable a single configuration file in ''${CONF_DIR}'' by giving it | |||||
another extension, e.g., by adding ''.disabled''.)) | |||||
For the new configuration to take effect, we must reload it by: | |||||
<code bash>service nginx reload</code> | |||||
For OpenWrt we use a special initial configuration, which is explained in the | |||||
section [[#openwrt_s_defaults|🡓OpenWrt’s Defaults]]. | |||||
So, we can make a site available at a specific URL in the **LAN** by creating a | |||||
''.locations'' file in the directory ''${CONF_DIR}''. | |||||
Such a file consists just of some | |||||
[[https://nginx.org/en/docs/http/ngx_http_core_module.html#location| | |||||
location blocks]]. | |||||
Under the latter link, you can find also the official documentation for all | |||||
available directives of the HTTP core of Nginx. | |||||
Look for //location// in the Context list. | |||||
The following example provides a simple template, see at the end for | |||||
different [[#locations_for_apps|🡓Locations for Apps]]((look for | |||||
[[https://github.com/search?utf8=%E2%9C%93&q=repo%3Aopenwrt%2Fpackages | |||||
+extension%3Alocations&type=Code&ref=advsearch&l=&l=| | |||||
other packages using a .locations file]], too.)): | |||||
<code nginx ${CONF_DIR}example.locations> | |||||
location /ex/am/ple { | |||||
access_log off; # default: not logging accesses. | |||||
# access_log /proc/self/fd/1 openwrt; # use logd (init forwards stdout). | |||||
# error_log stderr; # default: logging to logd (init forwards stderr). | |||||
error_log /dev/null; # disable error logging after config file is read. | |||||
# (state path of a file for access_log/error_log to the file instead.) | |||||
index index.html; | |||||
} | |||||
# location /eg/static { … } | |||||
</code> | |||||
All location blocks in all ''.locations'' files must use different URLs, | |||||
since they are all included in the ''${LAN_NAME}'' server that is part of the | |||||
[[#openwrt_s_defaults|🡓OpenWrt’s Defaults]].(( | |||||
We reserve the ''location /'' for making LuCI available under the root URL, | |||||
e.g. [[https://192.168.1.1/|192.168.1.1/]]. | |||||
All other sites shouldn’t use the root ''location /'' without suffix.)) | |||||
We should use the root URL for other sites than LuCI only on **other** domain | |||||
names, e.g., we could make a site available at https://${EXAMPLE_COM}/. | |||||
In order to do that, we create [[#new_server_parts|🡓New Server Parts]] for all | |||||
domain names. | |||||
We can also activate SSL thereby, see | |||||
[[#ssl_server_parts|🡓SSL Server Parts]]. | |||||
We use such server parts also for publishing sites to the internet (WAN) | |||||
instead of making them available just locally (in the LAN). | |||||
Via ''${CONF_DIR}*.conf'' files we can add directives to the //http// part of | |||||
the configuration. | |||||
If you would change the configuration ''$(basename "${UCI_CONF}").template'' | |||||
instead, it is not updated to new package's versions anymore. | |||||
Although it is not recommended, you can also disable the whole UCI config and | |||||
create your own ''${NGINX_CONF}''; then invoke: | |||||
<code bash>uci set nginx.global.uci_enable=false</code> | |||||
==== New Server Parts ====${MSG} | |||||
For making the router reachable from the WAN at a registered domain name, | |||||
it is not enough letting the | |||||
[[docs:guide-user:firewall:firewall_configuration|🡒firewall]] accept requests | |||||
(typically on ports 80 and 443) and giving the name server the internet IP | |||||
address of the router (maybe updated automatically by a | |||||
[[docs:guide-user:services:ddns:client|🡒DDNS Client]]). | |||||
We also need to set up virtual hosting for this domain name by creating an | |||||
appropriate server section in ''/etc/config/nginx'' | |||||
(or in a ''${CONF_DIR}*.conf'' file, which cannot be changed using UCI). | |||||
All such parts are included in the main configuration of OpenWrt | |||||
([[#openwrt_s_defaults|🡓OpenWrt’s Defaults]]). | |||||
In the server part, we state the domain as | |||||
[[https://nginx.org/en/docs/http/ngx_http_core_module.html#server_name| | |||||
server_name]]. | |||||
The link points to the same document as for the location blocks in the | |||||
[[#basic|🡑Basic Configuration]]: the official documentation for all available | |||||
directives of the HTTP core of Nginx. | |||||
This time look for //server// in the Context list, too. | |||||
The server part should also contain similar location blocks as | |||||
++before.| | |||||
We can re-include a ''.locations'' file that is included in the server part for | |||||
the LAN by default. | |||||
Then the site is reachable under the same path at both domains, e.g. by | |||||
https://192.168.1.1/ex/am/ple as well as by https://${EXAMPLE_COM}/ex/am/ple. | |||||
++ | |||||
We can add directives to a server in the UCI configuration by invoking | |||||
''uci [set|add_list] nginx.${EXAMPLE_COM//./_}.key=value''. | |||||
If the //key// is not starting with //uci_//, it becomes a ''key value;'' | |||||
++directive.| | |||||
Although the UCI config does not support nesting like Nginx, we can add a whole | |||||
block as //value//. | |||||
++ | |||||
We cannot use dots in a //key// name other than in the //value//. | |||||
In the following example we replace the dot in //${EXAMPLE_COM}// by an | |||||
underscore for the UCI name of the server, but not for Nginx's //server_name//: | |||||
<code bash> | |||||
uci add nginx server && | |||||
uci rename nginx.@server[-1]=${EXAMPLE_COM//./_} && | |||||
uci add_list nginx.${EXAMPLE_COM//./_}.listen='80' && | |||||
uci add_list nginx.${EXAMPLE_COM//./_}.listen='[::]:80' && | |||||
uci set nginx.${EXAMPLE_COM//./_}.server_name='${EXAMPLE_COM}' && | |||||
uci add_list nginx.${EXAMPLE_COM//./_}.include=\ | |||||
'$(basename ${CONF_DIR})/${EXAMPLE_COM}.locations' | |||||
# uci add_list nginx.${EXAMPLE_COM//./_}.location='/ { … }' \ | |||||
# root location for this server. | |||||
</code> | |||||
We can disable respective re-enable this server again by: | |||||
<code bash> | |||||
uci set nginx.${EXAMPLE_COM//./_}=disable # respective: \ | |||||
uci set nginx.${EXAMPLE_COM//./_}=server | |||||
</code> | |||||
These changes are made in the RAM (and can be used until a reboot), we can save | |||||
them permanently by: | |||||
<code bash>uci commit nginx</code> | |||||
For creating a similar ''${CONF_DIR}${EXAMPLE_COM}.conf'', we can adopt the | |||||
following: | |||||
<code nginx ${CONF_DIR}${EXAMPLE_COM}.conf> | |||||
server { | |||||
listen 80; | |||||
listen [::]:80; | |||||
server_name ${EXAMPLE_COM}; | |||||
include '$(basename ${CONF_DIR})/${EXAMPLE_COM}.locations'; | |||||
# location / { … } # root location for this server. | |||||
} | |||||
</code> | |||||
[[#openwrt_s_defaults|🡓OpenWrt’s Defaults]] include the UCI server | |||||
''config server '_redirect2ssl' ''. | |||||
It acts as //default_server// for HTTP and redirects requests for inexistent | |||||
URLs to HTTPS. | |||||
For making another domain name accessible to all addresses, the corresponding | |||||
server part should listen on port //80// and contain the FQDN as | |||||
//server_name//, cf. the official documentation on | |||||
[[https://nginx.org/en/docs/http/request_processing.html|request_processing]]. | |||||
Furthermore, there is a UCI server named ''${LAN_NAME}''. | |||||
It is the //default_server// for HTTPS and allows connections from LAN only. | |||||
It includes the file ''$(dirname "${CONF_DIR}")/restrict_locally'' with | |||||
appropriate //allow/deny// directives, cf. the official documentation on | |||||
[[https://nginx.org/en/docs/http/ngx_http_access_module.html|limiting access]]. | |||||
==== SSL Server Parts ====${MSG} | |||||
For enabling HTTPS for a domain we need a SSL certificate as well as its key and | |||||
add them by the directives //ssl_certificate// respective | |||||
//ssl_certificate_key// to the server part of the domain | |||||
([[https://nginx.org/en/docs/http/configuring_https_servers.html#sni|TLS SNI]] | |||||
is supported by default). | |||||
The rest of the configuration is similar as for general | |||||
[[#new_server_parts|🡑New Server Parts]]. | |||||
We only have to adjust the listen directives by adding the //ssl// parameter and | |||||
changing the port from //80// to //443//. | |||||
The official documentation of the SSL module contains an | |||||
[[https://nginx.org/en/docs/http/ngx_http_ssl_module.html#example| | |||||
example]] with some optimizations. | |||||
We can extend an existing UCI server section similarly, e.g., for the above | |||||
''config server '${EXAMPLE_COM//./_}' '' we invoke: | |||||
<code bash> | |||||
# Instead of 'del_list' the listen* entries, we could use '443 ssl' beforehand. | |||||
uci del_list nginx.${EXAMPLE_COM//./_}.listen='80' && | |||||
uci del_list nginx.${EXAMPLE_COM//./_}.listen='[::]:80' && | |||||
uci add_list nginx.${EXAMPLE_COM//./_}.listen='443 ssl' && | |||||
uci add_list nginx.${EXAMPLE_COM//./_}.listen='[::]:443 ssl' && | |||||
uci set nginx.${EXAMPLE_COM//./_}.ssl_certificate=\ | |||||
'${CONF_DIR}${EXAMPLE_COM}.crt' && | |||||
uci set nginx.${EXAMPLE_COM//./_}.ssl_certificate_key=\ | |||||
'${CONF_DIR}${EXAMPLE_COM}.key' && | |||||
uci set nginx.${EXAMPLE_COM//./_}.ssl_session_cache=\ | |||||
'${SSL_SESSION_CACHE_ARG}' && | |||||
uci set nginx.${EXAMPLE_COM//./_}.ssl_session_timeout=\ | |||||
'${SSL_SESSION_TIMEOUT_ARG}' && | |||||
uci commit nginx | |||||
</code> | |||||
For making the server in ''${CONF_DIR}${EXAMPLE_COM}.conf'' available | |||||
via SSL, we can make similar changes there. | |||||
The following command creates a **self-signed** SSL certificate and changes the | |||||
corresponding configuration: | |||||
<code bash>$(basename "${NGINX_UTIL}") ${ADD_SSL_FCT} ${EXAMPLE_COM}</code> | |||||
- If a ''$(basename "${CONF_DIR}")/${EXAMPLE_COM}.conf'' file exists, it\ | |||||
adds //ssl_*// directives and changes the //listen// directives there.\ | |||||
Else it does that similarly to the example above for a ++selected UCI\ | |||||
server.| Hereby it searches the UCI config first for a server with the\ | |||||
given name and then for a server whose //server_name// contains the name.\ | |||||
For //${EXAMPLE_COM}// it is the latter as a UCI key cannot have dots.++ | |||||
- It checks if there is a certificate with key for '${EXAMPLE_COM}' that is\ | |||||
valid for at least 13 months or tries to create a self-signed one. | |||||
- When cron is activated, it installs a cron job for renewing the self-signed\ | |||||
certificate every year if needed, too. We can activate cron by: \ | |||||
<code bash>service cron enable && service cron start</code> | |||||
This can be undone by invoking: | |||||
<code bash>$(basename "${NGINX_UTIL}") del_ssl ${EXAMPLE_COM}</code> | |||||
For using an SSL certificate and key that are managed otherwise, there is: | |||||
<code bash>$(basename "${NGINX_UTIL}") add_ssl ${EXAMPLE_COM} "\$MANAGER" \ | |||||
"/absolute/path/to/crt" "/absolute/path/to/key"</code> | |||||
It only adds //ssl_*// directives and changes the //listen// directives in | |||||
the appropriate configuration, but does not create or change the certificate | |||||
or its key. This can be reverted by: | |||||
<code bash>$(basename "${NGINX_UTIL}") del_ssl ${EXAMPLE_COM} "\$MANAGER"</code> | |||||
For example [[https://github.com/ndilieto/uacme|uacme]] or | |||||
[[https://github.com/Neilpang/acme.sh|acme.sh]] can be used for creating an SSL | |||||
certificate signed by Let’s Encrypt and changing the config | |||||
++accordingly.| | |||||
They call ''$(basename "${NGINX_UTIL}") add_ssl \$FQDN acme \$CRT \$KEY'' | |||||
internally.++ | |||||
We can install them by: | |||||
<code bash> | |||||
opkg update && opkg install uacme #or: acme #and for LuCI: luci-app-acme | |||||
</code> | |||||
[[#openwrt_s_defaults|🡓OpenWrt’s Defaults]] include a UCI server for the LAN: | |||||
''config server '${LAN_NAME}' ''. | |||||
It has //ssl_*// directives prepared for a self-signed((Let’s Encrypt (and other | |||||
CAs) cannot sign certificates of a **local** server.)) | |||||
SSL certificate, which is created on the first start of Nginx. | |||||
The server listens on all addresses, is the //default_server// for HTTPS and | |||||
allows connections from LAN only (by including the file ''restrict_locally'' | |||||
with //allow/deny// directives, cf. the official documentation on | |||||
[[https://nginx.org/en/docs/http/ngx_http_access_module.html|limiting access]]). | |||||
For making another domain name accessible to all addresses, the corresponding | |||||
SSL server part should listen on port //443// and contain the FQDN as | |||||
//server_name//, cf. the official documentation on | |||||
[[https://nginx.org/en/docs/http/request_processing.html|request_processing]]. | |||||
Furthermore, there is also a UCI server named ''_redirect2ssl'', which listens | |||||
on all addresses, acts as //default_server// for HTTP and redirects requests for | |||||
inexistent URLs to HTTPS. | |||||
==== OpenWrt’s Defaults ====${MSG} | |||||
Since Nginx is compiled with these presets, we can pretend that the main | |||||
configuration will always contain the following directives | |||||
(though we can overwrite them): | |||||
<code nginx>$(ifConfEcho --pid-path pid)\ | |||||
$(ifConfEcho --lock-path lock_file)\ | |||||
$(ifConfEcho --error-log-path error_log)\ | |||||
$(false && ifConfEcho --http-log-path access_log)\ | |||||
$(ifConfEcho --http-proxy-temp-path proxy_temp_path)\ | |||||
$(ifConfEcho --http-client-body-temp-path client_body_temp_path)\ | |||||
$(ifConfEcho --http-fastcgi-temp-path fastcgi_temp_path)\ | |||||
</code> | |||||
When starting or reloading the Nginx service, the ''/etc/init.d/nginx'' script | |||||
sets also the following directives | |||||
(so we cannot change them in the used configuration file): | |||||
<code nginx> | |||||
daemon off; # procd expects services to run in the foreground | |||||
</code> | |||||
Then, the init sript creates the main configuration | |||||
''$(basename "${UCI_CONF}")'' dynamically from the template: | |||||
$(code "${UCI_CONF}.template") | |||||
So, the access log is turned off by default and we can look at the error log | |||||
by ''logread'', as init.d script forwards stderr and stdout to the | |||||
[[docs:guide-user:base-system:log.essentials|🡒runtime log]]. | |||||
We can set the //error_log// and //access_log// to files, where the log | |||||
messages are forwarded to instead (after the configuration is read). | |||||
And for redirecting the access log of a //server// or //location// to the logd, | |||||
too, we insert the following directive in the corresponding block: | |||||
<code nginx> access_log /proc/self/fd/1 openwrt;</code> | |||||
If we setup a server through UCI, we can use the options //error_log// and/or | |||||
//access_log// also with the special path | |||||
++'logd'.| | |||||
When initializing the Nginx service, this special path is replaced by //stderr// | |||||
respective ///proc/self/fd/1// (which are forwarded to the runtime log). | |||||
++ | |||||
For creating the configuration from the template shown above, Nginx’s init | |||||
script replaces the comment ''#UCI_HTTP_CONFIG'' by all UCI servers. | |||||
For each server section in the the UCI configuration, it basically copies all | |||||
options into a Nginx //server { … }// part, in detail: | |||||
* Options starting with ''uci_'' are skipped. Currently there is only\ | |||||
the ''option ${MANAGE_SSL}=…'' in ++usage.| It is set to\ | |||||
//'self-signed'// when invoking\ | |||||
''$(basename ${NGINX_UTIL}) ${ADD_SSL_FCT} \$NAME''.\ | |||||
Then the corresponding certificate is re-newed if it is about to expire.\ | |||||
All those certificates are checked on the initialization of the Nginx service\ | |||||
and if Cron is available, it is deployed for checking them annually, too.++ | |||||
* All other lists or options of the form ''key='value' '' are written\ | |||||
one-to-one as ''key value;'' directives to the configuration file.\ | |||||
Just the path //logd// has a special meaning for the logging directives\ | |||||
(described in the previous paragraph). | |||||
The init.d script of Nginx uses the //$(basename ${NGINX_UTIL})// for creating | |||||
the configuration file | |||||
++in RAM.| | |||||
The main configuration ''${UCI_CONF}'' is a symbolic link to this place | |||||
(it is a dead link if the Nginx service is not running). | |||||
++ | |||||
We could use a custom configuration created at ''${NGINX_CONF}'' instead of the | |||||
dynamic configuration, too.(( | |||||
For using a custom configuration at ''${NGINX_CONF}'', we execute | |||||
<code bash>uci set nginx.global.uci_enable='false' </code> | |||||
Then the rest of the UCI config is ignored and //init.d// will not create the | |||||
main configuration dynamically from the template anymore. | |||||
Invoking ''$(basename ${NGINX_UTIL}) [${ADD_SSL_FCT}|del_ssl] \$FQDN'' | |||||
will still try to change a server in ''$(basename "${CONF_DIR}")/\$FQDN.conf'' | |||||
(this is less reliable than for a UCI config as it uses regular expressions, not | |||||
a complete parser for the Nginx configuration).)) | |||||
This is not encouraged since you cannot setup servers using UCI anymore. | |||||
Rather, we can put custom configuration parts to ''.conf'' files in the | |||||
''${CONF_DIR}'' directory. | |||||
The main configuration pulls in all ''$(basename "${CONF_DIR}")/*.conf'' files | |||||
into the //http {…}// block behind the created UCI servers. | |||||
The initial UCI config is enabled and contains two server section: | |||||
$(code "/etc/config/nginx" "nginx.config") | |||||
While the LAN server is the //default_server// for HTTPS, the server | |||||
redirecting requests for an inexistent ''server_name'' from HTTP to HTTPS acts | |||||
as //default_server// if there is ++no other|; | |||||
it uses an invalid name for that, more in the official documentation on | |||||
[[https://nginx.org/en/docs/http/request_processing.html|request_processing]] | |||||
++. | |||||
The LAN server pulls in all ''.locations'' files from the directory | |||||
''${CONF_DIR}''. | |||||
We can install the location parts of different sites there (see | |||||
[[#basic|🡑Basic Configuration]]) and re-include them into other servers. | |||||
This is needed especially for making them available to the WAN | |||||
([[#new_server_parts|🡑New Server Parts]]). | |||||
The LAN server listens for all addresses on port //443// and restricts the | |||||
access to local addresses by including: | |||||
$(code "$(dirname "${CONF_DIR}")/restrict_locally") | |||||
When starting or reloading the Nginx service, the init.d looks which UCI servers | |||||
have set ''option ${MANAGE_SSL} 'self-signed' '', e.g. the LAN server. | |||||
For all those servers it checks if there is a certificate that is still valid | |||||
for 13 months or (re-)creates a self-signed one. | |||||
If there is any such server, it installs also a cron job that checks the | |||||
corresponding certificates once a year. | |||||
The option ''${MANAGE_SSL}'' is set to //'self-signed'// respectively removed | |||||
from a UCI server named ''${EXAMPLE_COM//./_}'' by the following | |||||
(see [[#ssl_server_parts|🡑SSL Server Parts]], too): | |||||
<code bash> | |||||
$(basename ${NGINX_UTIL}) ${ADD_SSL_FCT} ${EXAMPLE_COM//./_} \ | |||||
# respectively: \ | |||||
$(basename ${NGINX_UTIL}) del_ssl ${EXAMPLE_COM//./_} | |||||
</code> | |||||
EOF |
@ -0,0 +1,22 @@ | |||||
config main global | |||||
option uci_enable 'true' | |||||
config server '_lan' | |||||
list listen '443 ssl default_server' | |||||
list listen '[::]:443 ssl default_server' | |||||
option server_name '_lan' | |||||
list include 'restrict_locally' | |||||
list include 'conf.d/*.locations' | |||||
option uci_manage_ssl 'self-signed' | |||||
option ssl_certificate '/etc/nginx/conf.d/_lan.crt' | |||||
option ssl_certificate_key '/etc/nginx/conf.d/_lan.key' | |||||
option ssl_session_cache 'shared:SSL:32k' | |||||
option ssl_session_timeout '64m' | |||||
option access_log 'off; # logd openwrt' | |||||
config server '_redirect2ssl' | |||||
list listen '80' | |||||
list listen '[::]:80' | |||||
option server_name '_redirect2ssl' | |||||
option return '302 https://$host$request_uri' |
@ -0,0 +1,10 @@ | |||||
allow ::1; | |||||
allow fc00::/7; | |||||
allow fec0::/10; | |||||
allow fe80::/10; | |||||
allow 127.0.0.0/8; | |||||
allow 10.0.0.0/8; | |||||
allow 172.16.0.0/12; | |||||
allow 192.168.0.0/16; | |||||
allow 169.254.0.0/16; | |||||
deny all; |
@ -0,0 +1,32 @@ | |||||
# Consider using UCI or creating files in /etc/nginx/conf.d/ for configuration. | |||||
# Parsing UCI configuration is skipped if uci set nginx.global.uci_enable=false | |||||
# For details see: https://openwrt.org/docs/guide-user/services/webserver/nginx | |||||
worker_processes auto; | |||||
user root; | |||||
events {} | |||||
http { | |||||
access_log off; | |||||
log_format openwrt | |||||
'$request_method $scheme://$host$request_uri => $status' | |||||
' (${body_bytes_sent}B in ${request_time}s) <- $http_referer'; | |||||
include mime.types; | |||||
default_type application/octet-stream; | |||||
sendfile on; | |||||
client_max_body_size 128M; | |||||
large_client_header_buffers 2 1k; | |||||
gzip on; | |||||
gzip_vary on; | |||||
gzip_proxied any; | |||||
root /www; | |||||
#UCI_HTTP_CONFIG | |||||
include conf.d/*.conf; | |||||
} |
@ -0,0 +1,171 @@ | |||||
--- | |||||
Language: Cpp | |||||
AccessModifierOffset: -2 | |||||
AlignAfterOpenBracket: Align | |||||
AlignConsecutiveMacros: false | |||||
AlignConsecutiveAssignments: false | |||||
AlignConsecutiveDeclarations: false | |||||
AlignEscapedNewlines: Left | |||||
AlignOperands: true | |||||
AlignTrailingComments: true | |||||
AllowAllArgumentsOnNextLine: true | |||||
AllowAllConstructorInitializersOnNextLine: true | |||||
AllowAllParametersOfDeclarationOnNextLine: false | |||||
AllowShortBlocksOnASingleLine: Always | |||||
AllowShortCaseLabelsOnASingleLine: true | |||||
# AllowShortEnumsOnASingleLine: true | |||||
AllowShortLambdasOnASingleLine: All | |||||
AllowShortFunctionsOnASingleLine: Inline | |||||
AllowShortIfStatementsOnASingleLine: Always | |||||
AllowShortLoopsOnASingleLine: true | |||||
AlwaysBreakAfterDefinitionReturnType: None | |||||
AlwaysBreakAfterReturnType: None | |||||
AlwaysBreakBeforeMultilineStrings: true | |||||
AlwaysBreakTemplateDeclarations: Yes | |||||
BinPackArguments: true | |||||
BinPackParameters: false | |||||
# BitFieldColonSpacing: After | |||||
BreakBeforeBraces: Custom | |||||
BraceWrapping: | |||||
AfterCaseLabel: false | |||||
AfterClass: false | |||||
AfterControlStatement: MultiLine | |||||
AfterEnum: false | |||||
AfterFunction: true | |||||
AfterNamespace: false | |||||
AfterObjCDeclaration: false | |||||
AfterStruct: false | |||||
AfterUnion: false | |||||
AfterExternBlock: false | |||||
BeforeCatch: true | |||||
BeforeElse: true | |||||
# BeforeLambdaBody: true | |||||
# BeforeWhile: false | |||||
IndentBraces: false | |||||
SplitEmptyFunction: false | |||||
SplitEmptyRecord: false | |||||
SplitEmptyNamespace: false | |||||
BreakBeforeBinaryOperators: None | |||||
BreakBeforeInheritanceComma: false | |||||
BreakInheritanceList: BeforeColon | |||||
BreakBeforeTernaryOperators: true | |||||
BreakConstructorInitializersBeforeComma: false | |||||
BreakConstructorInitializers: BeforeColon | |||||
BreakAfterJavaFieldAnnotations: false | |||||
BreakStringLiterals: true | |||||
ColumnLimit: 100 | |||||
CommentPragmas: '^ IWYU pragma:' | |||||
CompactNamespaces: false | |||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true | |||||
ConstructorInitializerIndentWidth: 4 | |||||
ContinuationIndentWidth: 4 | |||||
Cpp11BracedListStyle: true | |||||
DeriveLineEnding: true | |||||
DerivePointerAlignment: false | |||||
DisableFormat: false | |||||
ExperimentalAutoDetectBinPacking: false | |||||
FixNamespaceComments: true | |||||
ForEachMacros: | |||||
- foreach | |||||
- Q_FOREACH | |||||
- BOOST_FOREACH | |||||
IncludeBlocks: Preserve | |||||
IncludeCategories: | |||||
- Regex: '^<ext/.*\.h>' | |||||
Priority: 2 | |||||
SortPriority: 0 | |||||
- Regex: '^<.*\.h>' | |||||
Priority: 1 | |||||
SortPriority: 0 | |||||
- Regex: '^<.*' | |||||
Priority: 2 | |||||
SortPriority: 0 | |||||
- Regex: '.*' | |||||
Priority: 3 | |||||
SortPriority: 0 | |||||
IncludeIsMainRegex: '([-_](test|unittest))?$' | |||||
IncludeIsMainSourceRegex: '' | |||||
IndentCaseLabels: true | |||||
IndentGotoLabels: true | |||||
IndentPPDirectives: None | |||||
IndentWidth: 4 | |||||
IndentWrappedFunctionNames: false | |||||
JavaScriptQuotes: Leave | |||||
JavaScriptWrapImports: true | |||||
KeepEmptyLinesAtTheStartOfBlocks: false | |||||
MacroBlockBegin: '' | |||||
MacroBlockEnd: '' | |||||
MaxEmptyLinesToKeep: 1 | |||||
NamespaceIndentation: None | |||||
ObjCBinPackProtocolList: Never | |||||
ObjCBlockIndentWidth: 2 | |||||
ObjCSpaceAfterProperty: false | |||||
ObjCSpaceBeforeProtocolList: true | |||||
PenaltyBreakAssignment: 2 | |||||
PenaltyBreakBeforeFirstCallParameter: 1 | |||||
PenaltyBreakComment: 300 | |||||
PenaltyBreakFirstLessLess: 120 | |||||
PenaltyBreakString: 1000 | |||||
PenaltyBreakTemplateDeclaration: 10 | |||||
PenaltyExcessCharacter: 1000000 | |||||
PenaltyReturnTypeOnItsOwnLine: 200 | |||||
PointerAlignment: Left | |||||
RawStringFormats: | |||||
- Language: Cpp | |||||
Delimiters: | |||||
- cc | |||||
- CC | |||||
- cpp | |||||
- Cpp | |||||
- CPP | |||||
- 'c++' | |||||
- 'C++' | |||||
CanonicalDelimiter: '' | |||||
BasedOnStyle: google | |||||
- Language: TextProto | |||||
Delimiters: | |||||
- pb | |||||
- PB | |||||
- proto | |||||
- PROTO | |||||
EnclosingFunctions: | |||||
- EqualsProto | |||||
- EquivToProto | |||||
- PARSE_PARTIAL_TEXT_PROTO | |||||
- PARSE_TEST_PROTO | |||||
- PARSE_TEXT_PROTO | |||||
- ParseTextOrDie | |||||
- ParseTextProtoOrDie | |||||
CanonicalDelimiter: '' | |||||
BasedOnStyle: google | |||||
ReflowComments: true | |||||
SortIncludes: true | |||||
SortUsingDeclarations: true | |||||
SpaceAfterCStyleCast: false | |||||
SpaceAfterLogicalNot: false | |||||
SpaceAfterTemplateKeyword: true | |||||
SpaceBeforeAssignmentOperators: true | |||||
SpaceBeforeCpp11BracedList: false | |||||
SpaceBeforeCtorInitializerColon: true | |||||
SpaceBeforeInheritanceColon: true | |||||
SpaceBeforeParens: ControlStatements | |||||
SpaceBeforeRangeBasedForLoopColon: true | |||||
SpaceInEmptyBlock: false | |||||
SpaceInEmptyParentheses: false | |||||
SpacesBeforeTrailingComments: 2 | |||||
SpacesInAngles: false | |||||
SpacesInConditionalStatement: false | |||||
SpacesInContainerLiterals: true | |||||
SpacesInCStyleCastParentheses: false | |||||
SpacesInParentheses: false | |||||
SpacesInSquareBrackets: false | |||||
SpaceBeforeSquareBrackets: false | |||||
Standard: Auto | |||||
StatementMacros: | |||||
- Q_UNUSED | |||||
- QT_REQUIRE_VERSION | |||||
TabWidth: 4 | |||||
UseCRLF: false | |||||
UseTab: Never | |||||
... | |||||
@ -0,0 +1,407 @@ | |||||
--- | |||||
Checks: 'clang-diagnostic-*,clang-analyzer-*,*,-fuchsia-*,-misc-definitions-in-headers,-llvm-header-guard,-*-qualified-auto,-llvm-include-order' | |||||
WarningsAsErrors: '' | |||||
HeaderFilterRegex: '.*' | |||||
AnalyzeTemporaryDtors: false | |||||
FormatStyle: file | |||||
CheckOptions: | |||||
- key: abseil-string-find-startswith.AbseilStringsMatchHeader | |||||
value: 'absl/strings/match.h' | |||||
- key: abseil-string-find-startswith.IncludeStyle | |||||
value: llvm | |||||
- key: abseil-string-find-startswith.StringLikeClasses | |||||
value: '::std::basic_string' | |||||
- key: bugprone-argument-comment.CommentBoolLiterals | |||||
value: '0' | |||||
- key: bugprone-argument-comment.CommentCharacterLiterals | |||||
value: '0' | |||||
- key: bugprone-argument-comment.CommentFloatLiterals | |||||
value: '0' | |||||
- key: bugprone-argument-comment.CommentIntegerLiterals | |||||
value: '0' | |||||
- key: bugprone-argument-comment.CommentNullPtrs | |||||
value: '0' | |||||
- key: bugprone-argument-comment.CommentStringLiterals | |||||
value: '0' | |||||
- key: bugprone-argument-comment.CommentUserDefinedLiterals | |||||
value: '0' | |||||
- key: bugprone-argument-comment.IgnoreSingleArgument | |||||
value: '0' | |||||
- key: bugprone-argument-comment.StrictMode | |||||
value: '0' | |||||
- key: bugprone-assert-side-effect.AssertMacros | |||||
value: assert | |||||
- key: bugprone-assert-side-effect.CheckFunctionCalls | |||||
value: '0' | |||||
- key: bugprone-dangling-handle.HandleClasses | |||||
value: 'std::basic_string_view;std::experimental::basic_string_view' | |||||
- key: bugprone-dynamic-static-initializers.HeaderFileExtensions | |||||
value: ',h,hh,hpp,hxx' | |||||
- key: bugprone-exception-escape.FunctionsThatShouldNotThrow | |||||
value: '' | |||||
- key: bugprone-exception-escape.IgnoredExceptions | |||||
value: '' | |||||
- key: bugprone-misplaced-widening-cast.CheckImplicitCasts | |||||
value: '0' | |||||
- key: bugprone-not-null-terminated-result.WantToUseSafeFunctions | |||||
value: '1' | |||||
- key: bugprone-signed-char-misuse.CharTypdefsToIgnore | |||||
value: '' | |||||
- key: bugprone-sizeof-expression.WarnOnSizeOfCompareToConstant | |||||
value: '1' | |||||
- key: bugprone-sizeof-expression.WarnOnSizeOfConstant | |||||
value: '1' | |||||
- key: bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression | |||||
value: '0' | |||||
- key: bugprone-sizeof-expression.WarnOnSizeOfThis | |||||
value: '1' | |||||
- key: bugprone-string-constructor.LargeLengthThreshold | |||||
value: '8388608' | |||||
- key: bugprone-string-constructor.WarnOnLargeLength | |||||
value: '1' | |||||
- key: bugprone-suspicious-enum-usage.StrictMode | |||||
value: '0' | |||||
- key: bugprone-suspicious-missing-comma.MaxConcatenatedTokens | |||||
value: '5' | |||||
- key: bugprone-suspicious-missing-comma.RatioThreshold | |||||
value: '0.200000' | |||||
- key: bugprone-suspicious-missing-comma.SizeThreshold | |||||
value: '5' | |||||
- key: bugprone-suspicious-string-compare.StringCompareLikeFunctions | |||||
value: '' | |||||
- key: bugprone-suspicious-string-compare.WarnOnImplicitComparison | |||||
value: '1' | |||||
- key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison | |||||
value: '0' | |||||
- key: bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit | |||||
value: '16' | |||||
- key: bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField | |||||
value: '1' | |||||
- key: bugprone-unused-return-value.CheckedFunctions | |||||
value: '::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty' | |||||
- key: cert-dcl16-c.IgnoreMacros | |||||
value: '1' | |||||
- key: cert-dcl16-c.NewSuffixes | |||||
value: 'L;LL;LU;LLU' | |||||
- key: cert-dcl59-cpp.HeaderFileExtensions | |||||
value: ',h,hh,hpp,hxx' | |||||
- key: cert-err09-cpp.CheckThrowTemporaries | |||||
value: '1' | |||||
- key: cert-err61-cpp.CheckThrowTemporaries | |||||
value: '1' | |||||
- key: cert-msc32-c.DisallowedSeedTypes | |||||
value: 'time_t,std::time_t' | |||||
- key: cert-msc51-cpp.DisallowedSeedTypes | |||||
value: 'time_t,std::time_t' | |||||
- key: cert-oop11-cpp.IncludeStyle | |||||
value: llvm | |||||
- key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField | |||||
value: '0' | |||||
- key: cppcoreguidelines-avoid-magic-numbers.IgnoredFloatingPointValues | |||||
value: '1.0;100.0;' | |||||
- key: cppcoreguidelines-avoid-magic-numbers.IgnoredIntegerValues | |||||
value: '1;2;3;4;' | |||||
- key: cppcoreguidelines-explicit-virtual-functions.AllowOverrideAndFinal | |||||
value: '0' | |||||
- key: cppcoreguidelines-explicit-virtual-functions.FinalSpelling | |||||
value: final | |||||
- key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors | |||||
value: '1' | |||||
- key: cppcoreguidelines-explicit-virtual-functions.OverrideSpelling | |||||
value: override | |||||
- key: cppcoreguidelines-macro-usage.AllowedRegexp | |||||
value: '^DEBUG_*' | |||||
- key: cppcoreguidelines-macro-usage.CheckCapsOnly | |||||
value: '0' | |||||
- key: cppcoreguidelines-macro-usage.IgnoreCommandLineMacros | |||||
value: '1' | |||||
- key: cppcoreguidelines-no-malloc.Allocations | |||||
value: '::malloc;::calloc' | |||||
- key: cppcoreguidelines-no-malloc.Deallocations | |||||
value: '::free' | |||||
- key: cppcoreguidelines-no-malloc.Reallocations | |||||
value: '::realloc' | |||||
- key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic | |||||
value: '1' | |||||
- key: cppcoreguidelines-owning-memory.LegacyResourceConsumers | |||||
value: '::free;::realloc;::freopen;::fclose' | |||||
- key: cppcoreguidelines-owning-memory.LegacyResourceProducers | |||||
value: '::malloc;::aligned_alloc;::realloc;::calloc;::fopen;::freopen;::tmpfile' | |||||
- key: cppcoreguidelines-pro-bounds-constant-array-index.GslHeader | |||||
value: '' | |||||
- key: cppcoreguidelines-pro-bounds-constant-array-index.IncludeStyle | |||||
value: '0' | |||||
- key: cppcoreguidelines-pro-type-member-init.IgnoreArrays | |||||
value: '0' | |||||
- key: cppcoreguidelines-pro-type-member-init.UseAssignment | |||||
value: '0' | |||||
- key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions | |||||
value: '0' | |||||
- key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor | |||||
value: '0' | |||||
- key: google-build-namespaces.HeaderFileExtensions | |||||
value: ',h,hh,hpp,hxx' | |||||
- key: google-global-names-in-headers.HeaderFileExtensions | |||||
value: ',h,hh,hpp,hxx' | |||||
- key: google-readability-braces-around-statements.ShortStatementLines | |||||
value: '1' | |||||
- key: google-readability-function-size.BranchThreshold | |||||
value: '4294967295' | |||||
- key: google-readability-function-size.LineThreshold | |||||
value: '4294967295' | |||||
- key: google-readability-function-size.NestingThreshold | |||||
value: '4294967295' | |||||
- key: google-readability-function-size.ParameterThreshold | |||||
value: '4294967295' | |||||
- key: google-readability-function-size.StatementThreshold | |||||
value: '800' | |||||
- key: google-readability-function-size.VariableThreshold | |||||
value: '4294967295' | |||||
- key: google-readability-namespace-comments.ShortNamespaceLines | |||||
value: '10' | |||||
- key: google-readability-namespace-comments.SpacesBeforeComments | |||||
value: '2' | |||||
- key: google-runtime-int.SignedTypePrefix | |||||
value: int | |||||
- key: google-runtime-int.TypeSuffix | |||||
value: '' | |||||
- key: google-runtime-int.UnsignedTypePrefix | |||||
value: uint | |||||
- key: google-runtime-references.WhiteListTypes | |||||
value: '' | |||||
- key: hicpp-braces-around-statements.ShortStatementLines | |||||
value: '0' | |||||
- key: hicpp-function-size.BranchThreshold | |||||
value: '4294967295' | |||||
- key: hicpp-function-size.LineThreshold | |||||
value: '4294967295' | |||||
- key: hicpp-function-size.NestingThreshold | |||||
value: '4294967295' | |||||
- key: hicpp-function-size.ParameterThreshold | |||||
value: '4294967295' | |||||
- key: hicpp-function-size.StatementThreshold | |||||
value: '800' | |||||
- key: hicpp-function-size.VariableThreshold | |||||
value: '4294967295' | |||||
- key: hicpp-member-init.IgnoreArrays | |||||
value: '0' | |||||
- key: hicpp-member-init.UseAssignment | |||||
value: '0' | |||||
- key: hicpp-move-const-arg.CheckTriviallyCopyableMove | |||||
value: '1' | |||||
- key: hicpp-multiway-paths-covered.WarnOnMissingElse | |||||
value: '0' | |||||
- key: hicpp-named-parameter.IgnoreFailedSplit | |||||
value: '0' | |||||
- key: hicpp-no-malloc.Allocations | |||||
value: '::malloc;::calloc' | |||||
- key: hicpp-no-malloc.Deallocations | |||||
value: '::free' | |||||
- key: hicpp-no-malloc.Reallocations | |||||
value: '::realloc' | |||||
- key: hicpp-signed-bitwise.IgnorePositiveIntegerLiterals | |||||
value: '0' | |||||
- key: hicpp-special-member-functions.AllowMissingMoveFunctions | |||||
value: '0' | |||||
- key: hicpp-special-member-functions.AllowSoleDefaultDtor | |||||
value: '0' | |||||
- key: hicpp-uppercase-literal-suffix.IgnoreMacros | |||||
value: '1' | |||||
- key: hicpp-uppercase-literal-suffix.NewSuffixes | |||||
value: '' | |||||
- key: hicpp-use-auto.MinTypeNameLength | |||||
value: '5' | |||||
- key: hicpp-use-auto.RemoveStars | |||||
value: '0' | |||||
- key: hicpp-use-emplace.ContainersWithPushBack | |||||
value: '::std::vector;::std::list;::std::deque' | |||||
- key: hicpp-use-emplace.SmartPointers | |||||
value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr' | |||||
- key: hicpp-use-emplace.TupleMakeFunctions | |||||
value: '::std::make_pair;::std::make_tuple' | |||||
- key: hicpp-use-emplace.TupleTypes | |||||
value: '::std::pair;::std::tuple' | |||||
- key: hicpp-use-equals-default.IgnoreMacros | |||||
value: '1' | |||||
- key: hicpp-use-equals-delete.IgnoreMacros | |||||
value: '1' | |||||
- key: hicpp-use-noexcept.ReplacementString | |||||
value: '' | |||||
- key: hicpp-use-noexcept.UseNoexceptFalse | |||||
value: '1' | |||||
- key: hicpp-use-nullptr.NullMacros | |||||
value: '' | |||||
- key: hicpp-use-override.AllowOverrideAndFinal | |||||
value: '0' | |||||
- key: hicpp-use-override.FinalSpelling | |||||
value: final | |||||
- key: hicpp-use-override.IgnoreDestructors | |||||
value: '0' | |||||
- key: hicpp-use-override.OverrideSpelling | |||||
value: override | |||||
- key: llvm-namespace-comment.ShortNamespaceLines | |||||
value: '1' | |||||
- key: llvm-namespace-comment.SpacesBeforeComments | |||||
value: '1' | |||||
- key: misc-throw-by-value-catch-by-reference.CheckThrowTemporaries | |||||
value: '1' | |||||
- key: misc-unused-parameters.StrictMode | |||||
value: '0' | |||||
- key: modernize-loop-convert.MaxCopySize | |||||
value: '16' | |||||
- key: modernize-loop-convert.MinConfidence | |||||
value: reasonable | |||||
- key: modernize-loop-convert.NamingStyle | |||||
value: CamelCase | |||||
- key: modernize-make-shared.IgnoreMacros | |||||
value: '1' | |||||
- key: modernize-make-shared.IncludeStyle | |||||
value: '0' | |||||
- key: modernize-make-shared.MakeSmartPtrFunction | |||||
value: 'std::make_shared' | |||||
- key: modernize-make-shared.MakeSmartPtrFunctionHeader | |||||
value: memory | |||||
- key: modernize-make-unique.IgnoreMacros | |||||
value: '1' | |||||
- key: modernize-make-unique.IncludeStyle | |||||
value: '0' | |||||
- key: modernize-make-unique.MakeSmartPtrFunction | |||||
value: 'std::make_unique' | |||||
- key: modernize-make-unique.MakeSmartPtrFunctionHeader | |||||
value: memory | |||||
- key: modernize-pass-by-value.IncludeStyle | |||||
value: llvm | |||||
- key: modernize-pass-by-value.ValuesOnly | |||||
value: '0' | |||||
- key: modernize-raw-string-literal.ReplaceShorterLiterals | |||||
value: '0' | |||||
- key: modernize-replace-auto-ptr.IncludeStyle | |||||
value: llvm | |||||
- key: modernize-replace-random-shuffle.IncludeStyle | |||||
value: llvm | |||||
- key: modernize-use-auto.MinTypeNameLength | |||||
value: '5' | |||||
- key: modernize-use-auto.RemoveStars | |||||
value: '0' | |||||
- key: modernize-use-default-member-init.IgnoreMacros | |||||
value: '1' | |||||
- key: modernize-use-default-member-init.UseAssignment | |||||
value: '0' | |||||
- key: modernize-use-emplace.ContainersWithPushBack | |||||
value: '::std::vector;::std::list;::std::deque' | |||||
- key: modernize-use-emplace.SmartPointers | |||||
value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr' | |||||
- key: modernize-use-emplace.TupleMakeFunctions | |||||
value: '::std::make_pair;::std::make_tuple' | |||||
- key: modernize-use-emplace.TupleTypes | |||||
value: '::std::pair;::std::tuple' | |||||
- key: modernize-use-equals-default.IgnoreMacros | |||||
value: '1' | |||||
- key: modernize-use-equals-delete.IgnoreMacros | |||||
value: '1' | |||||
- key: modernize-use-nodiscard.ReplacementString | |||||
value: '[[nodiscard]]' | |||||
- key: modernize-use-noexcept.ReplacementString | |||||
value: '' | |||||
- key: modernize-use-noexcept.UseNoexceptFalse | |||||
value: '1' | |||||
- key: modernize-use-nullptr.NullMacros | |||||
value: 'NULL' | |||||
- key: modernize-use-override.AllowOverrideAndFinal | |||||
value: '0' | |||||
- key: modernize-use-override.FinalSpelling | |||||
value: final | |||||
- key: modernize-use-override.IgnoreDestructors | |||||
value: '0' | |||||
- key: modernize-use-override.OverrideSpelling | |||||
value: override | |||||
- key: modernize-use-transparent-functors.SafeMode | |||||
value: '0' | |||||
- key: modernize-use-using.IgnoreMacros | |||||
value: '1' | |||||
- key: objc-forbidden-subclassing.ForbiddenSuperClassNames | |||||
value: 'ABNewPersonViewController;ABPeoplePickerNavigationController;ABPersonViewController;ABUnknownPersonViewController;NSHashTable;NSMapTable;NSPointerArray;NSPointerFunctions;NSTimer;UIActionSheet;UIAlertView;UIImagePickerController;UITextInputMode;UIWebView' | |||||
- key: openmp-exception-escape.IgnoredExceptions | |||||
value: '' | |||||
- key: performance-faster-string-find.StringLikeClasses | |||||
value: 'std::basic_string' | |||||
- key: performance-for-range-copy.AllowedTypes | |||||
value: '' | |||||
- key: performance-for-range-copy.WarnOnAllAutoCopies | |||||
value: '0' | |||||
- key: performance-inefficient-string-concatenation.StrictMode | |||||
value: '0' | |||||
- key: performance-inefficient-vector-operation.EnableProto | |||||
value: '0' | |||||
- key: performance-inefficient-vector-operation.VectorLikeClasses | |||||
value: '::std::vector' | |||||
- key: performance-move-const-arg.CheckTriviallyCopyableMove | |||||
value: '1' | |||||
- key: performance-move-constructor-init.IncludeStyle | |||||
value: llvm | |||||
- key: performance-no-automatic-move.AllowedTypes | |||||
value: '' | |||||
- key: performance-type-promotion-in-math-fn.IncludeStyle | |||||
value: llvm | |||||
- key: performance-unnecessary-copy-initialization.AllowedTypes | |||||
value: '' | |||||
- key: performance-unnecessary-value-param.AllowedTypes | |||||
value: '' | |||||
- key: performance-unnecessary-value-param.IncludeStyle | |||||
value: llvm | |||||
- key: portability-simd-intrinsics.Std | |||||
value: '' | |||||
- key: portability-simd-intrinsics.Suggest | |||||
value: '0' | |||||
- key: readability-braces-around-statements.ShortStatementLines | |||||
value: '0' | |||||
- key: readability-else-after-return.WarnOnUnfixable | |||||
value: '1' | |||||
- key: readability-function-size.BranchThreshold | |||||
value: '4294967295' | |||||
- key: readability-function-size.LineThreshold | |||||
value: '4294967295' | |||||
- key: readability-function-size.NestingThreshold | |||||
value: '4294967295' | |||||
- key: readability-function-size.ParameterThreshold | |||||
value: '4294967295' | |||||
- key: readability-function-size.StatementThreshold | |||||
value: '800' | |||||
- key: readability-function-size.VariableThreshold | |||||
value: '4294967295' | |||||
- key: readability-identifier-naming.IgnoreFailedSplit | |||||
value: '0' | |||||
- key: readability-implicit-bool-conversion.AllowIntegerConditions | |||||
value: '0' | |||||
- key: readability-implicit-bool-conversion.AllowPointerConditions | |||||
value: '0' | |||||
- key: readability-inconsistent-declaration-parameter-name.IgnoreMacros | |||||
value: '1' | |||||
- key: readability-inconsistent-declaration-parameter-name.Strict | |||||
value: '0' | |||||
- key: readability-magic-numbers.IgnoredFloatingPointValues | |||||
value: '1.0;100.0;' | |||||
- key: readability-magic-numbers.IgnoredIntegerValues | |||||
value: '1;2;3;4;' | |||||
- key: readability-redundant-member-init.IgnoreBaseInCopyConstructors | |||||
value: '0' | |||||
- key: readability-redundant-smartptr-get.IgnoreMacros | |||||
value: '1' | |||||
- key: readability-redundant-string-init.StringNames | |||||
value: '::std::basic_string' | |||||
- key: readability-simplify-boolean-expr.ChainedConditionalAssignment | |||||
value: '0' | |||||
- key: readability-simplify-boolean-expr.ChainedConditionalReturn | |||||
value: '0' | |||||
- key: readability-simplify-subscript-expr.Types | |||||
value: '::std::basic_string;::std::basic_string_view;::std::vector;::std::array' | |||||
- key: readability-static-accessed-through-instance.NameSpecifierNestingThreshold | |||||
value: '3' | |||||
- key: readability-uppercase-literal-suffix.IgnoreMacros | |||||
value: '1' | |||||
- key: readability-uppercase-literal-suffix.NewSuffixes | |||||
value: '' | |||||
- key: zircon-temporary-objects.Names | |||||
value: '' | |||||
... | |||||
@ -0,0 +1,23 @@ | |||||
/* Copyright 2020 Peter Stadler | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in the | |||||
* documentation and/or other materials provided with the distribution. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
*/ |
@ -1,194 +1,378 @@ | |||||
#include <iostream> | #include <iostream> | ||||
#include <numeric> | |||||
#include "nginx-util.hpp" | |||||
#ifndef NO_SSL | |||||
#include "nginx-ssl-util.hpp" | #include "nginx-ssl-util.hpp" | ||||
#endif | |||||
#include "nginx-util.hpp" | |||||
static auto constexpr file_comment_auto_created = | |||||
std::string_view{"# This file is re-created when Nginx starts.\n"}; | |||||
void create_lan_listen() | |||||
// TODO(pst) replace it with blobmsg_get_string if upstream takes const: | |||||
#ifndef NO_UBUS | |||||
static inline auto _pst_get_string(const blob_attr* attr) -> char* | |||||
{ | { | ||||
std::string listen = "# This file is re-created if Nginx starts or" | |||||
" a LAN address changes.\n"; | |||||
std::string listen_default = listen; | |||||
std::string ssl_listen = listen; | |||||
std::string ssl_listen_default = listen; | |||||
auto add_listen = [&listen, &listen_default | |||||
#ifndef NO_SSL | |||||
,&ssl_listen, &ssl_listen_default | |||||
#endif | |||||
] | |||||
(const std::string &pre, const std::string &ip, const std::string &suf) | |||||
-> void | |||||
{ | |||||
if (ip.empty()) { return; } | |||||
const std::string val = pre + ip + suf; | |||||
listen += "\tlisten " + val + ":80;\n"; | |||||
listen_default += "\tlisten " + val + ":80 default_server;\n"; | |||||
#ifndef NO_SSL | |||||
ssl_listen += "\tlisten " + val + ":443 ssl;\n"; | |||||
ssl_listen_default += "\tlisten " + val + ":443 ssl default_server;\n"; | |||||
return static_cast<char*>(blobmsg_data(attr)); | |||||
} | |||||
#endif | #endif | ||||
}; | |||||
void create_lan_listen() // create empty files for compatibility: | |||||
{ | |||||
// TODO(pst): replace by dummies after transitioning nginx config to UCI: | |||||
std::vector<std::string> ips; | |||||
#ifndef NO_UBUS | #ifndef NO_UBUS | ||||
try { | try { | ||||
auto loopback_status=ubus::call("network.interface.loopback", "status"); | |||||
auto loopback_status = ubus::call("network.interface.loopback", "status"); | |||||
for (auto ip : loopback_status.filter("ipv4-address", "", "address")) { | |||||
add_listen("", static_cast<const char *>(blobmsg_data(ip)), ""); | |||||
for (const auto* ip : loopback_status.filter("ipv4-address", "", "address")) { | |||||
ips.emplace_back(_pst_get_string(ip)); | |||||
} | } | ||||
for (auto ip : loopback_status.filter("ipv6-address", "", "address")) { | |||||
add_listen("[", static_cast<const char *>(blobmsg_data(ip)), "]"); | |||||
for (const auto* ip : loopback_status.filter("ipv6-address", "", "address")) { | |||||
ips.emplace_back(std::string{"["} + _pst_get_string(ip) + "]"); | |||||
} | } | ||||
} catch (const std::runtime_error &) { /* do nothing about it */ } | |||||
} | |||||
catch (const std::runtime_error&) { /* do nothing about it */ | |||||
} | |||||
try { | try { | ||||
auto lan_status = ubus::call("network.interface.lan", "status"); | auto lan_status = ubus::call("network.interface.lan", "status"); | ||||
for (auto ip : lan_status.filter("ipv4-address", "", "address")) { | |||||
add_listen("", static_cast<const char *>(blobmsg_data(ip)), ""); | |||||
for (const auto* ip : lan_status.filter("ipv4-address", "", "address")) { | |||||
ips.emplace_back(_pst_get_string(ip)); | |||||
} | } | ||||
for (auto ip : lan_status.filter("ipv6-address", "", "address")) { | |||||
add_listen("[", static_cast<const char *>(blobmsg_data(ip)), "]"); | |||||
for (const auto* ip : lan_status.filter("ipv6-address", "", "address")) { | |||||
ips.emplace_back(std::string{"["} + _pst_get_string(ip) + "]"); | |||||
} | } | ||||
for (auto ip : lan_status.filter("ipv6-prefix-assignment", "", | |||||
"local-address", "address")) | |||||
{ | |||||
add_listen("[", static_cast<const char *>(blobmsg_data(ip)), "]"); | |||||
for (const auto* ip : | |||||
lan_status.filter("ipv6-prefix-assignment", "", "local-address", "address")) { | |||||
ips.emplace_back(std::string{"["} + _pst_get_string(ip) + "]"); | |||||
} | } | ||||
} catch (const std::runtime_error &) { /* do nothing about it */ } | |||||
} | |||||
catch (const std::runtime_error&) { /* do nothing about it */ | |||||
} | |||||
#else | #else | ||||
add_listen("", "127.0.0.1", ""); | |||||
ips.emplace_back("127.0.0.1"); | |||||
#endif | #endif | ||||
std::string listen = std::string{file_comment_auto_created}; | |||||
std::string listen_default = std::string{file_comment_auto_created}; | |||||
for (const auto& ip : ips) { | |||||
listen += "\tlisten " + ip + ":80;\n"; | |||||
listen_default += "\tlisten " + ip + ":80 default_server;\n"; | |||||
} | |||||
write_file(LAN_LISTEN, listen); | write_file(LAN_LISTEN, listen); | ||||
write_file(LAN_LISTEN_DEFAULT, listen_default); | write_file(LAN_LISTEN_DEFAULT, listen_default); | ||||
#ifndef NO_SSL | |||||
std::string ssl_listen = std::string{file_comment_auto_created}; | |||||
std::string ssl_listen_default = std::string{file_comment_auto_created}; | |||||
for (const auto& ip : ips) { | |||||
ssl_listen += "\tlisten " + ip + ":443 ssl;\n"; | |||||
ssl_listen_default += "\tlisten " + ip + ":443 ssl default_server;\n"; | |||||
} | |||||
write_file(LAN_SSL_LISTEN, ssl_listen); | write_file(LAN_SSL_LISTEN, ssl_listen); | ||||
write_file(LAN_SSL_LISTEN_DEFAULT, ssl_listen_default); | write_file(LAN_SSL_LISTEN_DEFAULT, ssl_listen_default); | ||||
#endif | |||||
} | } | ||||
inline auto change_if_starts_with(const std::string_view& subject, | |||||
const std::string_view& prefix, | |||||
const std::string_view& substitute, | |||||
const std::string_view& seperator = " \t\n;") -> std::string | |||||
{ | |||||
auto view = subject; | |||||
view = view.substr(view.find_first_not_of(seperator)); | |||||
if (view.rfind(prefix, 0) == 0) { | |||||
if (view.size() == prefix.size()) { | |||||
return std::string{substitute}; | |||||
} | |||||
view = view.substr(prefix.size()); | |||||
if (seperator.find(view[0]) != std::string::npos) { | |||||
auto ret = std::string{substitute}; | |||||
ret += view; | |||||
return ret; | |||||
} | |||||
} | |||||
return std::string{subject}; | |||||
} | |||||
inline auto create_server_conf(const uci::section& sec, const std::string& indent = "") | |||||
-> std::string | |||||
{ | |||||
auto secname = sec.name(); | |||||
auto legacypath = std::string{CONF_DIR} + secname + ".conf"; | |||||
if (access(legacypath.c_str(), R_OK) == 0) { | |||||
auto message = std::string{"skipped UCI server 'nginx."} + secname; | |||||
message += "' as it could conflict with: " + legacypath + "\n"; | |||||
// TODO(pst) std::cerr<<"create_server_conf notice: "<<message; | |||||
return indent + "# " + message; | |||||
} // else: | |||||
auto conf = indent + "server { #see uci show 'nginx." + secname + "'\n"; | |||||
for (auto opt : sec) { | |||||
for (auto itm : opt) { | |||||
if (opt.name().rfind("uci_", 0) == 0) { | |||||
continue; | |||||
} | |||||
// else: standard opt.name() | |||||
auto val = itm.name(); | |||||
if (opt.name() == "error_log") { | |||||
val = change_if_starts_with(val, "logd", "/proc/self/fd/1"); | |||||
} | |||||
else if (opt.name() == "access_log") { | |||||
val = change_if_starts_with(val, "logd", "stderr"); | |||||
} | |||||
conf += indent + "\t" + opt.name() + " " + itm.name() + ";\n"; | |||||
} | |||||
} | |||||
conf += indent + "}\n"; | |||||
return conf; | |||||
} | |||||
void init_uci(const uci::package& pkg) | |||||
{ | |||||
auto conf = std::string{file_comment_auto_created}; | |||||
static const auto uci_http_config = std::string_view{"#UCI_HTTP_CONFIG\n"}; | |||||
const auto tmpl = read_file(std::string{UCI_CONF} + ".template"); | |||||
auto pos = tmpl.find(uci_http_config); | |||||
if (pos == std::string::npos) { | |||||
conf += tmpl; | |||||
} | |||||
else { | |||||
const auto index = tmpl.find_last_not_of(" \t", pos - 1); | |||||
const auto before = tmpl.begin() + index + 1; | |||||
const auto middle = tmpl.begin() + pos; | |||||
const auto after = middle + uci_http_config.length(); | |||||
conf.append(tmpl.begin(), before); | |||||
const auto indent = std::string{before, middle}; | |||||
for (auto sec : pkg) { | |||||
if (sec.type() == std::string_view{"server"}) { | |||||
conf += create_server_conf(sec, indent) + "\n"; | |||||
} | |||||
} | |||||
conf.append(after, tmpl.end()); | |||||
} | |||||
write_file(VAR_UCI_CONF, conf); | |||||
} | |||||
auto is_enabled(const uci::package& pkg) -> bool | |||||
{ | |||||
for (auto sec : pkg) { | |||||
if (sec.type() != std::string_view{"main"}) { | |||||
continue; | |||||
} | |||||
if (sec.name() != std::string_view{"global"}) { | |||||
continue; | |||||
} | |||||
for (auto opt : sec) { | |||||
if (opt.name() != "uci_enable") { | |||||
continue; | |||||
} | |||||
for (auto itm : opt) { | |||||
if (itm) { | |||||
return true; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
/* | |||||
* ___________main_thread________________|______________thread_1________________ | |||||
* create_lan_listen() or do nothing | config = uci::package("nginx") | |||||
* if config_enabled (set in thread_1): | config_enabled = is_enabled(config) | |||||
* then init_uci(config) | check_ssl(config, config_enabled) | |||||
*/ | |||||
void init_lan() | void init_lan() | ||||
{ | { | ||||
std::exception_ptr ex; | std::exception_ptr ex; | ||||
#ifndef NO_SSL | |||||
auto thrd = std::thread([]{ //&ex | |||||
try { add_ssl_if_needed(std::string{LAN_NAME}); } | |||||
std::unique_ptr<uci::package> config; | |||||
bool config_enabled = false; | |||||
std::mutex configuring; | |||||
configuring.lock(); | |||||
auto thrd = std::thread([&config, &config_enabled, &configuring, &ex] { | |||||
try { | |||||
config = std::make_unique<uci::package>("nginx"); | |||||
config_enabled = is_enabled(*config); | |||||
configuring.unlock(); | |||||
check_ssl(*config, config_enabled); | |||||
} | |||||
catch (...) { | catch (...) { | ||||
std::cerr<<"init_lan notice: no server named "<<LAN_NAME<<std::endl; | |||||
// not: ex = std::current_exception(); | |||||
std::cerr << "init_lan error: checking UCI file /etc/config/nginx\n"; | |||||
ex = std::current_exception(); | |||||
} | } | ||||
}); | }); | ||||
#endif | |||||
try { create_lan_listen(); } | |||||
try { | |||||
create_lan_listen(); | |||||
} | |||||
catch (...) { | catch (...) { | ||||
std::cerr<<"init_lan error: cannot create LAN listen files"<<std::endl; | |||||
std::cerr << "init_lan error: cannot create listen files of local IPs.\n"; | |||||
ex = std::current_exception(); | ex = std::current_exception(); | ||||
} | } | ||||
#ifndef NO_SSL | |||||
thrd.join(); | |||||
#endif | |||||
configuring.lock(); | |||||
if (config_enabled) { | |||||
try { | |||||
init_uci(*config); | |||||
} | |||||
catch (...) { | |||||
std::cerr << "init_lan error: cannot create " << VAR_UCI_CONF << " from "; | |||||
std::cerr << UCI_CONF << ".template using UCI file /etc/config/nginx\n"; | |||||
ex = std::current_exception(); | |||||
} | |||||
} | |||||
if (ex) { std::rethrow_exception(ex); } | |||||
thrd.join(); | |||||
if (ex) { | |||||
std::rethrow_exception(ex); | |||||
} | |||||
} | } | ||||
void get_env() | void get_env() | ||||
{ | { | ||||
std::cout<<"NGINX_CONF="<<"'"<<NGINX_CONF<<"'"<<std::endl; | |||||
std::cout<<"CONF_DIR="<<"'"<<CONF_DIR<<"'"<<std::endl; | |||||
std::cout<<"LAN_NAME="<<"'"<<LAN_NAME<<"'"<<std::endl; | |||||
std::cout<<"LAN_LISTEN="<<"'"<<LAN_LISTEN<<"'"<<std::endl; | |||||
#ifndef NO_SSL | |||||
std::cout<<"LAN_SSL_LISTEN="<<"'"<<LAN_SSL_LISTEN<<"'"<<std::endl; | |||||
std::cout<<"SSL_SESSION_CACHE_ARG="<<"'"<<SSL_SESSION_CACHE_ARG(LAN_NAME)<< | |||||
"'"<<std::endl; | |||||
std::cout<<"SSL_SESSION_TIMEOUT_ARG="<<"'"<<SSL_SESSION_TIMEOUT_ARG<<"'\n"; | |||||
std::cout<<"ADD_SSL_FCT="<<"'"<<ADD_SSL_FCT<<"'"<<std::endl; | |||||
#endif | |||||
std::cout << "UCI_CONF=" | |||||
<< "'" << UCI_CONF << "'" << std::endl; | |||||
std::cout << "NGINX_CONF=" | |||||
<< "'" << NGINX_CONF << "'" << std::endl; | |||||
std::cout << "CONF_DIR=" | |||||
<< "'" << CONF_DIR << "'" << std::endl; | |||||
std::cout << "LAN_NAME=" | |||||
<< "'" << LAN_NAME << "'" << std::endl; | |||||
std::cout << "LAN_LISTEN=" | |||||
<< "'" << LAN_LISTEN << "'" << std::endl; | |||||
std::cout << "LAN_SSL_LISTEN=" | |||||
<< "'" << LAN_SSL_LISTEN << "'" << std::endl; | |||||
std::cout << "SSL_SESSION_CACHE_ARG=" | |||||
<< "'" << SSL_SESSION_CACHE_ARG(LAN_NAME) << "'" << std::endl; | |||||
std::cout << "SSL_SESSION_TIMEOUT_ARG=" | |||||
<< "'" << SSL_SESSION_TIMEOUT_ARG << "'\n"; | |||||
std::cout << "ADD_SSL_FCT=" | |||||
<< "'" << ADD_SSL_FCT << "'" << std::endl; | |||||
std::cout << "MANAGE_SSL=" | |||||
<< "'" << MANAGE_SSL << "'" << std::endl; | |||||
} | } | ||||
auto main(int argc, char * argv[]) -> int | |||||
auto main(int argc, char* argv[]) -> int | |||||
{ | { | ||||
// TODO(pst): use std::span when available: | // TODO(pst): use std::span when available: | ||||
auto args = std::basic_string_view<char *>{argv, static_cast<size_t>(argc)}; | |||||
auto args = std::basic_string_view<char*>{argv, static_cast<size_t>(argc)}; | |||||
auto cmds = std::array{ | auto cmds = std::array{ | ||||
std::array<std::string_view, 2>{"init_lan", ""}, | std::array<std::string_view, 2>{"init_lan", ""}, | ||||
std::array<std::string_view, 2>{"get_env", ""}, | std::array<std::string_view, 2>{"get_env", ""}, | ||||
#ifndef NO_SSL | |||||
std::array<std::string_view, 2>{ADD_SSL_FCT, " server_name" }, | |||||
std::array<std::string_view, 2>{"del_ssl", " server_name" }, | |||||
#endif | |||||
std::array<std::string_view, 2>{ | |||||
ADD_SSL_FCT, "server_name [manager /path/to/ssl_certificate /path/to/ssl_key]"}, | |||||
std::array<std::string_view, 2>{"del_ssl", "server_name [manager]"}, | |||||
std::array<std::string_view, 2>{"check_ssl", ""}, | |||||
}; | }; | ||||
try { | try { | ||||
if (argc == 2 && args[1] == cmds[0][0]) { | |||||
init_lan(); | |||||
} | |||||
if (argc==2 && args[1]==cmds[0][0]) { init_lan(); } | |||||
else if (argc == 2 && args[1] == cmds[1][0]) { | |||||
get_env(); | |||||
} | |||||
else if (argc==2 && args[1]==cmds[1][0]) { get_env(); } | |||||
else if (argc == 3 && args[1] == cmds[2][0]) { | |||||
add_ssl_if_needed(std::string{args[2]}); | |||||
} | |||||
#ifndef NO_SSL | |||||
else if (argc==3 && args[1]==cmds[2][0]) | |||||
{ add_ssl_if_needed(std::string{args[2]});} | |||||
// NOLINTNEXTLINE(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers): 6 | |||||
else if (argc == 6 && args[1] == cmds[2][0]) { | |||||
// NOLINTNEXTLINE(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers): 5 | |||||
add_ssl_if_needed(std::string{args[2]}, args[3], args[4], args[5]); | |||||
} | |||||
else if (argc==3 && args[1]==cmds[3][0]) | |||||
{ del_ssl(std::string{args[2]}); } | |||||
else if (argc == 3 && args[1] == cmds[3][0]) { | |||||
del_ssl(std::string{args[2]}); | |||||
} | |||||
else if (argc==2 && args[1]==cmds[3][0]) | |||||
{ del_ssl(std::string{LAN_NAME}); } | |||||
#endif | |||||
else if (argc == 4 && args[1] == cmds[3][0]) { | |||||
del_ssl(std::string{args[2]}, args[3]); | |||||
} | |||||
else if (argc == 2 && args[1] == cmds[3][0]) // TODO(pst) deprecate | |||||
{ | |||||
try { | |||||
auto name = std::string{LAN_NAME}; | |||||
if (del_ssl_legacy(name)) { | |||||
auto crtpath = std::string{CONF_DIR} + name + ".crt"; | |||||
remove(crtpath.c_str()); | |||||
auto keypath = std::string{CONF_DIR} + name + ".key"; | |||||
remove(keypath.c_str()); | |||||
} | |||||
} | |||||
catch (...) { /* do nothing. */ | |||||
} | |||||
} | |||||
else if (argc == 2 && args[1] == cmds[4][0]) { | |||||
check_ssl(uci::package{"nginx"}); | |||||
} | |||||
else { | else { | ||||
std::cerr<<"Tool for creating Nginx configuration files ("; | |||||
std::cerr << "Tool for creating Nginx configuration files ("; | |||||
#ifdef VERSION | #ifdef VERSION | ||||
std::cerr<<"version "<<VERSION<<" "; | |||||
std::cerr << "version " << VERSION << " "; | |||||
#endif | #endif | ||||
std::cerr<<"with "; | |||||
std::cerr << "with libuci, "; | |||||
#ifndef NO_UBUS | #ifndef NO_UBUS | ||||
std::cerr<<"ubus, "; | |||||
#endif | |||||
#ifndef NO_SSL | |||||
std::cerr<<"libopenssl, "; | |||||
#ifdef NO_PCRE | |||||
std::cerr<<"std::regex, "; | |||||
#else | |||||
std::cerr<<"PCRE, "; | |||||
std::cerr << "libubus, "; | |||||
#endif | #endif | ||||
std::cerr << "libopenssl, "; | |||||
#ifndef NO_PCRE | |||||
std::cerr << "PCRE, "; | |||||
#endif | #endif | ||||
std::cerr<<"pthread and libstdcpp)."<<std::endl; | |||||
std::cerr << "pthread and libstdcpp)." << std::endl; | |||||
auto usage = std::string{"usage: "} + *argv + " ["; | |||||
for (auto cmd : cmds) { | |||||
usage += std::string{cmd[0]}; | |||||
usage += std::string{cmd[1]} + "|"; | |||||
} | |||||
usage[usage.size()-1] = ']'; | |||||
std::cerr<<usage<<std::endl; | |||||
auto usage = | |||||
std::accumulate(cmds.begin(), cmds.end(), std::string{"usage: "} + *argv + " [", | |||||
[](const auto& use, const auto& cmd) { | |||||
return use + std::string{cmd[0]} + (cmd[1].empty() ? "" : " ") + | |||||
std::string{cmd[1]} + "|"; | |||||
}); | |||||
usage[usage.size() - 1] = ']'; | |||||
std::cerr << usage << std::endl; | |||||
throw std::runtime_error("main error: argument not recognized"); | throw std::runtime_error("main error: argument not recognized"); | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
catch (const std::exception & e) { std::cerr<<e.what()<<std::endl; } | |||||
catch (const std::exception& e) { | |||||
std::cerr << " * " << *argv << " " << e.what() << "\n"; | |||||
} | |||||
catch (...) { perror("main error"); } | |||||
catch (...) { | |||||
std::cerr << " * * " << *argv; | |||||
perror(" main error"); | |||||
} | |||||
return 1; | return 1; | ||||
} | } |
@ -0,0 +1,22 @@ | |||||
#include <iostream> | |||||
#include <mutex> | |||||
#include <string> | |||||
#include <string_view> | |||||
#include <vector> | |||||
#include "uci-cxx.hpp" | |||||
auto main() -> int | |||||
{ | |||||
uci::element p = uci::package{"nginx"}; | |||||
std::cout << "package " << p.name() << "\n\n"; | |||||
for (auto s : p) { | |||||
std::cout << "config " << s.type() << " '" << s.name() << "'\n"; | |||||
for (auto o : s) { | |||||
for (auto i : o) { | |||||
std::cout << "\t" << o.type() << " " << o.name() << " '" << i.name() << "'\n"; | |||||
} | |||||
} | |||||
std::cout << "\n"; | |||||
} | |||||
} |
@ -0,0 +1,474 @@ | |||||
#ifndef _UCI_CXX_HPP | |||||
#define _UCI_CXX_HPP | |||||
#include <uci.h> | |||||
#include <memory> | |||||
#include <mutex> | |||||
#include <stdexcept> | |||||
#include <string> | |||||
#include <string_view> | |||||
namespace uci { | |||||
template <class T> | |||||
class iterator { // like uci_foreach_element_safe. | |||||
private: | |||||
const uci_ptr& _ptr; | |||||
uci_element* _it = nullptr; | |||||
uci_element* _next = nullptr; | |||||
// wrapper for clang-tidy | |||||
inline auto _list_to_element(const uci_list* cur) -> uci_element* | |||||
{ | |||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-type-cstyle-cast) | |||||
return list_to_element(cur); // macro casting container=pointer-offset. | |||||
} | |||||
public: | |||||
inline explicit iterator(const uci_ptr& ptr, const uci_list* cur) | |||||
: _ptr{ptr}, _it{_list_to_element(cur)} | |||||
{ | |||||
_next = _list_to_element(_it->list.next); | |||||
} | |||||
inline iterator(iterator&&) noexcept = default; | |||||
inline iterator(const iterator&) = delete; | |||||
inline auto operator=(const iterator&) -> iterator& = delete; | |||||
inline auto operator=(iterator &&) -> iterator& = delete; | |||||
auto operator*() -> T | |||||
{ | |||||
return T{_ptr, _it}; | |||||
} | |||||
inline auto operator!=(const iterator& rhs) -> bool | |||||
{ | |||||
return (&_it->list != &rhs._it->list); | |||||
} | |||||
inline auto operator++() -> iterator& | |||||
{ | |||||
_it = _next; | |||||
_next = _list_to_element(_next->list.next); | |||||
return *this; | |||||
} | |||||
inline ~iterator() = default; | |||||
}; | |||||
class locked_context { | |||||
private: | |||||
static std::mutex inuse; | |||||
public: | |||||
inline locked_context() | |||||
{ | |||||
inuse.lock(); | |||||
} | |||||
inline locked_context(locked_context&&) noexcept = default; | |||||
inline locked_context(const locked_context&) = delete; | |||||
inline auto operator=(const locked_context&) -> locked_context& = delete; | |||||
inline auto operator=(locked_context &&) -> locked_context& = delete; | |||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static) | |||||
inline auto get() -> uci_context* // is member to enforce inuse | |||||
{ | |||||
static auto free_ctx = [](uci_context* ctx) { uci_free_context(ctx); }; | |||||
static std::unique_ptr<uci_context, decltype(free_ctx)> lazy_ctx{uci_alloc_context(), | |||||
free_ctx}; | |||||
if (!lazy_ctx) { // it could be available on a later call: | |||||
lazy_ctx.reset(uci_alloc_context()); | |||||
if (!lazy_ctx) { | |||||
throw std::runtime_error("uci error: cannot allocate context"); | |||||
} | |||||
} | |||||
return lazy_ctx.get(); | |||||
} | |||||
inline ~locked_context() | |||||
{ | |||||
inuse.unlock(); | |||||
} | |||||
}; | |||||
template <class T> | |||||
class element { | |||||
private: | |||||
uci_list* _begin = nullptr; | |||||
uci_list* _end = nullptr; | |||||
uci_ptr _ptr{}; | |||||
protected: | |||||
[[nodiscard]] inline auto ptr() -> uci_ptr& | |||||
{ | |||||
return _ptr; | |||||
} | |||||
[[nodiscard]] inline auto ptr() const -> const uci_ptr& | |||||
{ | |||||
return _ptr; | |||||
} | |||||
void init_begin_end(uci_list* begin, uci_list* end) | |||||
{ | |||||
_begin = begin; | |||||
_end = end; | |||||
} | |||||
inline explicit element(const uci_ptr& pre, uci_element* last) : _ptr{pre} | |||||
{ | |||||
_ptr.last = last; | |||||
} | |||||
inline explicit element() = default; | |||||
public: | |||||
inline element(element&&) noexcept = default; | |||||
inline element(const element&) = delete; | |||||
inline auto operator=(const element&) -> element& = delete; | |||||
inline auto operator=(element &&) -> element& = delete; | |||||
auto operator[](std::string_view key) const -> T; | |||||
[[nodiscard]] inline auto name() const -> std::string | |||||
{ | |||||
return _ptr.last->name; | |||||
} | |||||
void rename(const char* value) const; | |||||
void commit() const; | |||||
[[nodiscard]] inline auto begin() const -> iterator<T> | |||||
{ | |||||
return iterator<T>{_ptr, _begin}; | |||||
} | |||||
[[nodiscard]] inline auto end() const -> iterator<T> | |||||
{ | |||||
return iterator<T>{_ptr, _end}; | |||||
} | |||||
inline ~element() = default; | |||||
}; | |||||
class section; | |||||
class option; | |||||
class item; | |||||
class package : public element<section> { | |||||
public: | |||||
inline package(const uci_ptr& pre, uci_element* last) : element{pre, last} | |||||
{ | |||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-type-cstyle-cast) | |||||
ptr().p = uci_to_package(ptr().last); // macro casting pointer-offset. | |||||
ptr().package = ptr().last->name; | |||||
auto* end = &ptr().p->sections; | |||||
auto* begin = end->next; | |||||
init_begin_end(begin, end); | |||||
} | |||||
explicit package(const char* name); | |||||
auto set(const char* key, const char* type) const -> section; | |||||
}; | |||||
class section : public element<option> { | |||||
public: | |||||
inline section(const uci_ptr& pre, uci_element* last) : element{pre, last} | |||||
{ | |||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-type-cstyle-cast) | |||||
ptr().s = uci_to_section(ptr().last); // macro casting pointer-offset. | |||||
ptr().section = ptr().last->name; | |||||
auto* end = &ptr().s->options; | |||||
auto* begin = end->next; | |||||
init_begin_end(begin, end); | |||||
} | |||||
auto set(const char* key, const char* value) const -> option; | |||||
void del(); | |||||
[[nodiscard]] inline auto anonymous() const -> bool | |||||
{ | |||||
return ptr().s->anonymous; | |||||
} | |||||
[[nodiscard]] inline auto type() const -> std::string | |||||
{ | |||||
return ptr().s->type; | |||||
} | |||||
}; | |||||
class option : public element<item> { | |||||
public: | |||||
inline option(const uci_ptr& pre, uci_element* last) : element{pre, last} | |||||
{ | |||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-type-cstyle-cast) | |||||
ptr().o = uci_to_option(ptr().last); // macro casting pointer-offset. | |||||
ptr().option = ptr().last->name; | |||||
if (ptr().o->type == UCI_TYPE_LIST) { // use union ptr().o->v as list: | |||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) | |||||
auto* end = &ptr().o->v.list; | |||||
auto* begin = end->next; | |||||
init_begin_end(begin, end); | |||||
} | |||||
else { | |||||
auto* begin = &ptr().last->list; | |||||
auto* end = begin->next; | |||||
init_begin_end(begin, end); | |||||
} | |||||
} | |||||
void del(); | |||||
[[nodiscard]] inline auto type() const -> std::string | |||||
{ | |||||
return (ptr().o->type == UCI_TYPE_LIST ? "list" : "option"); | |||||
} | |||||
}; | |||||
class item : public element<item> { | |||||
public: | |||||
inline item(const uci_ptr& pre, uci_element* last) : element{pre, last} | |||||
{ | |||||
ptr().value = ptr().last->name; | |||||
} | |||||
[[nodiscard]] inline auto type() const -> std::string | |||||
{ | |||||
return (ptr().o->type == UCI_TYPE_LIST ? "list" : "option"); | |||||
} | |||||
[[nodiscard]] inline auto name() const -> std::string | |||||
{ | |||||
return (ptr().last->type == UCI_TYPE_ITEM | |||||
? ptr().last->name | |||||
: | |||||
// else: use union ptr().o->v as string: | |||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) | |||||
ptr().o->v.string); | |||||
} | |||||
inline explicit operator bool() const | |||||
{ | |||||
const auto x = std::string_view{name()}; | |||||
if (x == "0" || x == "off" || x == "false" || x == "no" || x == "disabled") { | |||||
return false; | |||||
} | |||||
if (x == "1" || x == "on" || x == "true" || x == "yes" || x == "enabled") { | |||||
return true; | |||||
} | |||||
auto errmsg = std::string{"uci_error: item is not bool "} + name(); | |||||
throw std::runtime_error(errmsg); | |||||
} | |||||
void rename(const char* value) const; | |||||
}; | |||||
// ------------------------- implementation: ---------------------------------- | |||||
std::mutex locked_context::inuse{}; | |||||
inline auto uci_error(uci_context* ctx, const char* prefix = nullptr) -> std::runtime_error | |||||
{ | |||||
char* errmsg = nullptr; | |||||
uci_get_errorstr(ctx, &errmsg, prefix); | |||||
std::unique_ptr<char, decltype(&std::free)> auto_free{errmsg, std::free}; | |||||
return std::runtime_error{errmsg}; | |||||
} | |||||
template <class T> | |||||
auto element<T>::operator[](std::string_view key) const -> T | |||||
{ | |||||
for (auto elmt : *this) { | |||||
if (elmt.name() == key) { | |||||
return elmt; | |||||
} | |||||
} | |||||
auto errmsg = std::string{"uci error: cannot find "}.append(key); | |||||
throw uci_error(locked_context{}.get(), errmsg.c_str()); | |||||
} | |||||
template <class T> | |||||
void element<T>::rename(const char* value) const | |||||
{ | |||||
if (value == name()) { | |||||
return; | |||||
} | |||||
auto ctx = locked_context{}; | |||||
auto tmp_ptr = uci_ptr{_ptr}; | |||||
tmp_ptr.value = value; | |||||
if (uci_rename(ctx.get(), &tmp_ptr) != 0) { | |||||
auto errmsg = std::string{"uci error: cannot rename "}.append(name()); | |||||
throw uci_error(ctx.get(), errmsg.c_str()); | |||||
} | |||||
} | |||||
template <class T> | |||||
void element<T>::commit() const | |||||
{ | |||||
auto ctx = locked_context{}; | |||||
// TODO(pst) use when possible: | |||||
// if (uci_commit(ctx.get(), &_ptr.p, true) != 0) { | |||||
// auto errmsg = std::string{"uci error: cannot commit "} + _ptr.package; | |||||
// throw uci_error(ctx.get(), errmsg.c_str()); | |||||
// } | |||||
auto err = uci_save(ctx.get(), _ptr.p); | |||||
if (err == 0) { | |||||
uci_package* tmp_pkg = nullptr; | |||||
uci_context* tmp_ctx = uci_alloc_context(); | |||||
err = (tmp_ctx == nullptr ? 1 : 0); | |||||
if (err == 0) { | |||||
err = uci_load(tmp_ctx, _ptr.package, &tmp_pkg); | |||||
} | |||||
if (err == 0) { | |||||
err = uci_commit(tmp_ctx, &tmp_pkg, false); | |||||
} | |||||
if (err == 0) { | |||||
err = uci_unload(tmp_ctx, tmp_pkg); | |||||
} | |||||
if (tmp_ctx != nullptr) { | |||||
uci_free_context(tmp_ctx); | |||||
} | |||||
} | |||||
if (err != 0) { | |||||
auto errmsg = std::string{"uci error: cannot commit "} + _ptr.package; | |||||
throw uci_error(ctx.get(), errmsg.c_str()); | |||||
} | |||||
} | |||||
package::package(const char* name) | |||||
{ | |||||
auto ctx = locked_context{}; | |||||
auto* pkg = uci_lookup_package(ctx.get(), name); | |||||
if (pkg == nullptr) { | |||||
if (uci_load(ctx.get(), name, &pkg) != 0) { | |||||
auto errmsg = std::string{"uci error: cannot load package "} + name; | |||||
throw uci_error(ctx.get(), errmsg.c_str()); | |||||
} | |||||
} | |||||
ptr().package = name; | |||||
ptr().p = pkg; | |||||
ptr().last = &pkg->e; | |||||
auto* end = &ptr().p->sections; | |||||
auto* begin = end->next; | |||||
init_begin_end(begin, end); | |||||
} | |||||
auto package::set(const char* key, const char* type) const -> section | |||||
{ | |||||
auto ctx = locked_context{}; | |||||
auto tmp_ptr = uci_ptr{ptr()}; | |||||
tmp_ptr.section = key; | |||||
tmp_ptr.value = type; | |||||
if (uci_set(ctx.get(), &tmp_ptr) != 0) { | |||||
auto errmsg = std::string{"uci error: cannot set section "} + type + "'" + key + | |||||
"' in package " + name(); | |||||
throw uci_error(ctx.get(), errmsg.c_str()); | |||||
} | |||||
return section{ptr(), tmp_ptr.last}; | |||||
} | |||||
auto section::set(const char* key, const char* value) const -> option | |||||
{ | |||||
auto ctx = locked_context{}; | |||||
auto tmp_ptr = uci_ptr{ptr()}; | |||||
tmp_ptr.option = key; | |||||
tmp_ptr.value = value; | |||||
if (uci_set(ctx.get(), &tmp_ptr) != 0) { | |||||
auto errmsg = std::string{"uci error: cannot set option "} + key + "'" + value + | |||||
"' in package " + name(); | |||||
throw uci_error(ctx.get(), errmsg.c_str()); | |||||
} | |||||
return option{ptr(), tmp_ptr.last}; | |||||
} | |||||
void section::del() | |||||
{ | |||||
auto ctx = locked_context{}; | |||||
if (uci_delete(ctx.get(), &ptr()) != 0) { | |||||
auto errmsg = std::string{"uci error: cannot delete section "} + name(); | |||||
throw uci_error(ctx.get(), errmsg.c_str()); | |||||
} | |||||
} | |||||
void option::del() | |||||
{ | |||||
auto ctx = locked_context{}; | |||||
if (uci_delete(ctx.get(), &ptr()) != 0) { | |||||
auto errmsg = std::string{"uci error: cannot delete option "} + name(); | |||||
throw uci_error(ctx.get(), errmsg.c_str()); | |||||
} | |||||
} | |||||
void item::rename(const char* value) const | |||||
{ | |||||
if (value == name()) { | |||||
return; | |||||
} | |||||
auto ctx = locked_context{}; | |||||
auto tmp_ptr = uci_ptr{ptr()}; | |||||
if (tmp_ptr.last->type != UCI_TYPE_ITEM) { | |||||
tmp_ptr.value = value; | |||||
if (uci_set(ctx.get(), &tmp_ptr) != 0) { | |||||
auto errmsg = std::string{"uci error: cannot rename item "} + name(); | |||||
throw uci_error(ctx.get(), errmsg.c_str()); | |||||
} | |||||
return; | |||||
} // else: | |||||
tmp_ptr.value = tmp_ptr.last->name; | |||||
if (uci_del_list(ctx.get(), &tmp_ptr) != 0) { | |||||
auto errmsg = std::string{"uci error: cannot rename (del) "} + name(); | |||||
throw uci_error(ctx.get(), errmsg.c_str()); | |||||
} | |||||
tmp_ptr.value = value; | |||||
if (uci_add_list(ctx.get(), &tmp_ptr) != 0) { | |||||
auto errmsg = std::string{"uci error: cannot rename (add) "} + value; | |||||
throw uci_error(ctx.get(), errmsg.c_str()); | |||||
} | |||||
} | |||||
} // namespace uci | |||||
#endif |