**tl;dr:** The functions `{add,del}_ssl` modify a server section of the UCI config if there is no `.conf` file with the same name in `/etc/nginx/conf.d/`. Then `init_lan` creates `/var/lib/nginx/uci.conf` files by copying the `/etc/nginx/uci.conf.template` and standard options from the UCI config; additionally the special path `logd` can be used in `{access,error}_log`. The init does not change the configuration beside re-creating self-signed certificates when needed. This is also the only purpose of the new `check_ssl`, which is installed as yearly cron job. **Initialization:** Invoking `nginx-util init_lan` parses the UCI configuration for package `nginx`. It creates a server part in `/var/lib/nginx/uci.conf` for each `section server '$name'` by copying all UCI options but the following: * `option uci_manage_ssl` is skipped. It is set to 'self-signed' by `nginx-util add_ssl $name`, removed by `nginx-util del_ssl $name` and used by `nginx-util check_ssl` (see below). * `logd` as path in `error_log` or `access_log` writes them to STDERR respective STDOUT, which are fowarded by Nginx's init to the log daemon. Specifically: `option error_log 'logd'` becomes `error_log stderr;` and `option access_log 'logd openwrt'` becomes `access_log /proc/self/fd/1 openwrt;` Other `[option|list] key 'value'` entries just become `key value;` directives. The init.d calls internally also `check_ssl` for rebuilding self-signed SSL certificates if needed (see below). And it still sets up `/var/lib/nginx/lan{,_ssl}.listen` files as it is doing in the current version (so they stay available). **Defaults:** The package installs the file `/etc/nginx/restrict_locally` containing allow/deny directives for restricting the access to LAN addresses by including it into a server part. The default server '_lan' includes this file and listens on all IPs (instead of only the local IPs as it did before; other servers do not need to listen explicitly on the local IPs anymore). The default server is contained together with a server that redirects HTTP requests for inexistent URLs to HTTPS in the UCI configuration file `/etc/config/nginx`. Furthermore, the packages installs a `/etc/nginx/uci.conf.template` containing the current setup and a marker, which will be replaced by the created UCI servers when calling `init_lan`. **Other:** If there is a file named `/etc/nginx/conf.d/$name.conf` the functions `init_lan`, `add_ssl $name` and `del_ssl $name` will use that file instead of a UCI server section (this is similar to the current version). Else it selects the UCI `section server $name`, or, when there is no such section, it searches for the first one having `option server_name '… $name …'`. For this section: * `nginx-util add_ssl $name` will add to it: `option uci_manage_ssl 'self-signed'` `option ssl_certificate '/etc/nginx/conf.d/$name.crt'` `option ssl_certificate_key '/etc/nginx/conf.d/$name.key'` `option ssl_session_cache 'shared:SSL:32k'` `option ssl_session_timeout '64m'` If these options are already present, they will stay the same; just the first option `uci_manage_ssl` will always be changed to 'self-signed'. The command also changes all `listen` list items to use port 443 and ssl instead of port 80 (without ssl). If they stated another port than 80 before, they are kept the same. Furthermore, it creates a self-signed SSL certificate if necessary, i.e., if there is no *valid* certificate and key at the locations given by the options `ssl_certificate` and `ssl_certificate_key`. * `nginx-util del_ssl $name` checks if `uci_manage_ssl` is set 'self-signed' in the corresponding UCI section. Only then it removes all of the above options regardless of the value looking just at the key name. Then, it also changes all `listen` list items to use port 80 (without ssl) instead of port 443 with ssl. If stating another port than 443, they are kept the same. Furthermore, it removes the SSL certificate and key that were indicated by `ssl_certificate{,_key}`. * `nginx-util check_ssl` looks through all server sections of the UCI config for `uci_manage_ssl 'self-signed'`. On every hit it checks if the SSL certificate-key-pair indicated by the options `ssl_certificate{,_key}` is expired. Then it re-creates a self-signed certificate. If there exists at least one `section server` with `uci_manage_ssl 'self-signed'`, it will try to install itself as cron job. If there are no such sections, it removes that cron job if possible. For installing a ssl certificate and key managed by another app, you can call: `nginx-util add_ssl $name $manager $crtpath $keypath` Hereby `$name` is as above, `$manager` is an arbitrary string, and the the ssl certificate and its key are indicated by their absolute path. If you want to remove the directives again, then you can use: `nginx-util del_ssl $name $manager` Signed-off-by: Peter Stadler <peter.stadler@student.uibk.ac.at>lilik-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 <numeric> | |||
#include "nginx-util.hpp" | |||
#ifndef NO_SSL | |||
#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 | |||
}; | |||
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 | |||
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 { | |||
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 | |||
add_listen("", "127.0.0.1", ""); | |||
ips.emplace_back("127.0.0.1"); | |||
#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_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_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() | |||
{ | |||
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 (...) { | |||
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 (...) { | |||
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(); | |||
} | |||
#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() | |||
{ | |||
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: | |||
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{ | |||
std::array<std::string_view, 2>{"init_lan", ""}, | |||
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 { | |||
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 { | |||
std::cerr<<"Tool for creating Nginx configuration files ("; | |||
std::cerr << "Tool for creating Nginx configuration files ("; | |||
#ifdef VERSION | |||
std::cerr<<"version "<<VERSION<<" "; | |||
std::cerr << "version " << VERSION << " "; | |||
#endif | |||
std::cerr<<"with "; | |||
std::cerr << "with libuci, "; | |||
#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 | |||
std::cerr << "libopenssl, "; | |||
#ifndef NO_PCRE | |||
std::cerr << "PCRE, "; | |||
#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"); | |||
} | |||
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; | |||
} |
@ -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 |