From e247efa254599f0a2cf9178b2ef16b5ac6cc8fb8 Mon Sep 17 00:00:00 2001 From: Peter Stadler Date: Tue, 4 Feb 2020 13:10:00 +0100 Subject: [PATCH] nginx-util: add tests, clean up and fix issues Add tests for nginx-ssl-util and nginx-ssl-util-nopcre using (fake)chroot. Clean the code up making nginx-ssl-util a header file. Both changes are for better (future) code quality only. There are minor functional improvements: * fix compiler error of gcc7 by using std=c++17 * fix error if there is no lan/loopback interface * notice instead of error message if there is no default server * add ipv6-prefix-assignment.*.local-address.address for LAN * add CONFLICTS in Makefile for choosing the right version * add cast to release of unique_ptr to avoid warning * add version message to help message Signed-off-by: Peter Stadler --- net/nginx-util/Makefile | 18 +- net/nginx-util/src/CMakeLists.txt | 43 ++- ...{nginx-ssl-util.cpp => nginx-ssl-util.hpp} | 14 +- net/nginx-util/src/nginx-util.cpp | 97 ++++--- net/nginx-util/src/test-nginx-util-root.sh | 251 ++++++++++++++++++ net/nginx-util/src/test-nginx-util.sh | 38 +++ net/nginx-util/src/test-px5g.sh | 9 +- net/nginx-util/src/ubus-cxx.hpp | 2 +- 8 files changed, 408 insertions(+), 64 deletions(-) rename net/nginx-util/src/{nginx-ssl-util.cpp => nginx-ssl-util.hpp} (98%) create mode 100644 net/nginx-util/src/test-nginx-util-root.sh create mode 100755 net/nginx-util/src/test-nginx-util.sh diff --git a/net/nginx-util/Makefile b/net/nginx-util/Makefile index 2224336bc..46c98a1d6 100644 --- a/net/nginx-util/Makefile +++ b/net/nginx-util/Makefile @@ -1,13 +1,17 @@ include $(TOPDIR)/rules.mk PKG_NAME:=nginx-util -PKG_VERSION:=1.2 +PKG_VERSION:=1.3 PKG_RELEASE:=1 +PKG_MAINTAINER:=Peter Stadler include $(INCLUDE_DIR)/package.mk include $(INCLUDE_DIR)/cmake.mk -define Package/nginx-util +CMAKE_OPTIONS+= -DUBUS=y +CMAKE_OPTIONS+= -DVERSION=$(PKG_VERSION) + +define Package/nginx-util/default SECTION:=net CATEGORY:=Network SUBMENU:=Web Servers/Proxies @@ -15,23 +19,29 @@ define Package/nginx-util DEPENDS:=+libstdcpp +libubus +libubox +libpthread endef +define Package/nginx-util + $(Package/nginx-util/default) + CONFLICTS:=nginx-ssl-util +endef + define Package/nginx-ssl-util/default - $(Package/nginx-util) + $(Package/nginx-util/default) TITLE+= and manager of its SSL certificates DEPENDS+= +libopenssl CONFLICTS:=nginx-util - PROVIDES:=nginx-ssl-util endef define Package/nginx-ssl-util $(Package/nginx-ssl-util/default) TITLE+= (using PCRE) DEPENDS+= +libpcre + CONFLICTS+= nginx-ssl-util-nopcre endef define Package/nginx-ssl-util-nopcre $(Package/nginx-ssl-util/default) TITLE+= (using ) + CONFLICTS+= nginx-ssl-util endef define Package/nginx-util/description diff --git a/net/nginx-util/src/CMakeLists.txt b/net/nginx-util/src/CMakeLists.txt index df7440d38..af1d67ea1 100644 --- a/net/nginx-util/src/CMakeLists.txt +++ b/net/nginx-util/src/CMakeLists.txt @@ -1,38 +1,59 @@ cmake_minimum_required(VERSION 2.6) PROJECT(nginx-util CXX) +SET(CMAKE_CXX_STANDARD 17) INCLUDE(CheckFunctionExists) +IF(UBUS) FIND_PATH(ubus_include_dir libubus.h) FIND_LIBRARY(ubox NAMES ubox) FIND_LIBRARY(ubus NAMES ubus) INCLUDE_DIRECTORIES(${ubus_include_dir}) +ENDIF() -ADD_DEFINITIONS(-Os -Wall -Werror -Wextra --std=c++2a -g3) +ADD_DEFINITIONS(-Os -Wall -Werror -Wextra -g3) ADD_DEFINITIONS(-Wno-unused-parameter -Wmissing-declarations) SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") -ADD_EXECUTABLE(px5g px5g.cpp) -TARGET_LINK_LIBRARIES(px5g ssl crypto) + +IF(UBUS) + +ADD_COMPILE_DEFINITIONS(VERSION=${VERSION}) ADD_EXECUTABLE(nginx-util nginx-util.cpp) +TARGET_COMPILE_DEFINITIONS(nginx-util PUBLIC -DNO_SSL) TARGET_LINK_LIBRARIES(nginx-util ${ubox} ${ubus} pthread) +INSTALL(TARGETS nginx-util RUNTIME DESTINATION bin) -ADD_EXECUTABLE(nginx-ssl-util nginx-ssl-util.cpp) +ADD_EXECUTABLE(nginx-ssl-util nginx-util.cpp) TARGET_LINK_LIBRARIES(nginx-ssl-util ${ubox} ${ubus} pthread ssl crypto pcre) +INSTALL(TARGETS nginx-ssl-util RUNTIME DESTINATION bin) -ADD_EXECUTABLE(nginx-ssl-util-nopcre nginx-ssl-util.cpp) +ADD_EXECUTABLE(nginx-ssl-util-nopcre nginx-util.cpp) TARGET_COMPILE_DEFINITIONS(nginx-ssl-util-nopcre PUBLIC -DNO_PCRE) TARGET_LINK_LIBRARIES(nginx-ssl-util-nopcre ${ubox} ${ubus} pthread ssl crypto) +INSTALL(TARGETS nginx-ssl-util-nopcre RUNTIME DESTINATION bin) + +ELSE() + +CONFIGURE_FILE(test-px5g.sh test-px5g.sh COPYONLY) +CONFIGURE_FILE(test-nginx-util.sh test-nginx-util.sh COPYONLY) +CONFIGURE_FILE(test-nginx-util-root.sh test-nginx-util-root.sh COPYONLY) -ADD_EXECUTABLE(nginx-ssl-util-noubus nginx-ssl-util.cpp) +ADD_EXECUTABLE(px5g px5g.cpp) +TARGET_LINK_LIBRARIES(px5g ssl crypto) +INSTALL(TARGETS px5g RUNTIME DESTINATION bin) + +ADD_EXECUTABLE(nginx-ssl-util-noubus nginx-util.cpp) TARGET_COMPILE_DEFINITIONS(nginx-ssl-util-noubus PUBLIC -DNO_UBUS) TARGET_LINK_LIBRARIES(nginx-ssl-util-noubus pthread ssl crypto pcre) +INSTALL(TARGETS nginx-ssl-util-noubus RUNTIME DESTINATION bin) -INSTALL(TARGETS px5g RUNTIME DESTINATION bin) -INSTALL(TARGETS nginx-util RUNTIME DESTINATION bin) -INSTALL(TARGETS nginx-ssl-util RUNTIME DESTINATION bin) -INSTALL(TARGETS nginx-ssl-util-nopcre RUNTIME DESTINATION bin) -# INSTALL(TARGETS nginx-ssl-util-noubus RUNTIME DESTINATION bin) +ADD_EXECUTABLE(nginx-ssl-util-nopcre-noubus nginx-util.cpp) +TARGET_COMPILE_DEFINITIONS(nginx-ssl-util-nopcre-noubus PUBLIC -DNO_PCRE -DNO_UBUS) +TARGET_LINK_LIBRARIES(nginx-ssl-util-nopcre-noubus pthread ssl crypto) +INSTALL(TARGETS nginx-ssl-util-nopcre-noubus RUNTIME DESTINATION bin) + +ENDIF() diff --git a/net/nginx-util/src/nginx-ssl-util.cpp b/net/nginx-util/src/nginx-ssl-util.hpp similarity index 98% rename from net/nginx-util/src/nginx-ssl-util.cpp rename to net/nginx-util/src/nginx-ssl-util.hpp index 7b268cbd4..0fa7009cc 100644 --- a/net/nginx-util/src/nginx-ssl-util.cpp +++ b/net/nginx-util/src/nginx-ssl-util.hpp @@ -1,3 +1,6 @@ +#ifndef __NGINX_SSL_UTIL_HPP +#define __NGINX_SSL_UTIL_HPP + #include #ifdef NO_PCRE @@ -491,12 +494,7 @@ void use_cron_to_recreate_certificate(const std::string & name) void add_ssl_if_needed(const std::string & name) { - try { add_ssl_directives_to(name, name==LAN_NAME); } - catch (...) { - std::cerr<<"add_ssl_if_needed error: "; - std::cerr<<"cannot add SSL directives to "<(blobmsg_data(ip)), ""); - } + for (auto ip : loopback_status.filter("ipv4-address", "", "address")) { + add_listen("", static_cast(blobmsg_data(ip)), ""); + } - for (auto ip : loopback_status.filter("ipv6-address", "", "address")) { - add_listen("[", static_cast(blobmsg_data(ip)), "]"); - } + for (auto ip : loopback_status.filter("ipv6-address", "", "address")) { + add_listen("[", static_cast(blobmsg_data(ip)), "]"); + } + } catch (const std::runtime_error &) { /* do nothing about it */ } - auto lan_status = ubus::call("network.interface.lan", "status"); + try { + auto lan_status = ubus::call("network.interface.lan", "status"); - for (auto ip : lan_status.filter("ipv4-address", "", "address")) { - add_listen("", static_cast(blobmsg_data(ip)), ""); - } + for (auto ip : lan_status.filter("ipv4-address", "", "address")) { + add_listen("", static_cast(blobmsg_data(ip)), ""); + } - for (auto ip : lan_status.filter("ipv6-address", "", "address")) { - add_listen("[", static_cast(blobmsg_data(ip)), "]"); - } + for (auto ip : lan_status.filter("ipv6-address", "", "address")) { + add_listen("[", static_cast(blobmsg_data(ip)), "]"); + } + + for (auto ip : lan_status.filter("ipv6-prefix-assignment", "", + "local-address", "address")) + { + add_listen("[", static_cast(blobmsg_data(ip)), "]"); + } + } catch (const std::runtime_error &) { /* do nothing about it */ } +#else + add_listen("", "127.0.0.1", ""); #endif write_file(LAN_LISTEN, listen); write_file(LAN_LISTEN_DEFAULT, listen_default); -#ifdef NGINX_OPENSSL +#ifndef NO_SSL write_file(LAN_SSL_LISTEN, ssl_listen); write_file(LAN_SSL_LISTEN_DEFAULT, ssl_listen_default); #endif @@ -66,23 +78,23 @@ void init_lan() { std::exception_ptr ex; -#ifdef NGINX_OPENSSL - auto thrd = std::thread([&ex]{ - try { add_ssl_if_needed(std::string{LAN_NAME}); } +#ifndef NO_SSL + auto thrd = std::thread([]{ //&ex + try { add_ssl_if_needed(std::string{LAN_NAME}); } catch (...) { - std::cerr<<"init_lan error: cannot add SSL for "< int auto cmds = std::array{ std::array{"init_lan", ""}, std::array{"get_env", ""}, -#ifdef NGINX_OPENSSL +#ifndef NO_SSL std::array{ADD_SSL_FCT, " server_name" }, std::array{"del_ssl", " server_name" }, #endif @@ -126,7 +138,7 @@ auto main(int argc, char * argv[]) -> int else if (argc==2 && args[1]==cmds[1][0]) { get_env(); } -#ifdef NGINX_OPENSSL +#ifndef NO_SSL else if (argc==3 && args[1]==cmds[2][0]) { add_ssl_if_needed(std::string{args[2]});} @@ -138,13 +150,30 @@ auto main(int argc, char * argv[]) -> int #endif else { + std::cerr<<"Tool for creating Nginx configuration files ("; +#ifdef VERSION + std::cerr<<"version "< int return 1; } - -#endif diff --git a/net/nginx-util/src/test-nginx-util-root.sh b/net/nginx-util/src/test-nginx-util-root.sh new file mode 100644 index 000000000..a6d78757c --- /dev/null +++ b/net/nginx-util/src/test-nginx-util-root.sh @@ -0,0 +1,251 @@ +#!/bin/bash + +PRINT_PASSED=2 + +NGINX_UTIL="/usr/bin/nginx-util" + +__esc_newlines() { + echo "${1}" | sed -E 's/$/\\n/' | tr -d '\n' | sed -E 's/\\n$/\n/' +} + +__esc_sed_rhs() { + __esc_newlines "${1}" | sed -E 's/[&/\]/\\&/g' +} + +_sed_rhs() { + __esc_sed_rhs "$(echo "${1}" | sed -E "s/[$]/$(__esc_sed_rhs "${2}")/g")" +} + +__esc_regex() { + __esc_newlines "${1}" | sed -E 's/[^^_a-zA-Z0-9-]/[&]/g; s/\^/\\^/g' +} + +_regex() { + __esc_regex "${1}" | sed -E -e 's/^(\[\s])*/^\\s*/' \ + -e 's/(\[\s])+\[[*]]/(\\s.*)?/g' \ + -e 's/(\[\s])+/\\s+/g' \ + -e 's/(\[\s])*\[[;]]/\\s*;/g' \ + -e "s/\[['\"]]/['\"]?/g" \ + -e "s/\[[$]]/$(__esc_sed_rhs "$(__esc_regex "${2}")")/g" +} + +_echo_sed() { + echo "" | sed -E "c${1}" +} + +setpoint_add_ssl() { + local indent="\n$1" + local name="$2" + local default="" + [ "${name}" == "${LAN_NAME}" ] && default=".default" + local prefix="${CONF_DIR}${name}" + + local CONF="$(grep -vE "$(_regex "${NGX_INCLUDE}" \ + "${LAN_LISTEN}${default}")" "${prefix}.sans" 2>/dev/null)" + local ADDS="" + echo "${CONF}" \ + | grep -qE "$(_regex "${NGX_INCLUDE}" "${LAN_SSL_LISTEN}${default}")" \ + || ADDS="${ADDS}${indent}$(_sed_rhs "${NGX_INCLUDE}" \ + "${LAN_SSL_LISTEN}${default}")" + echo "${CONF}" | grep -qE "$(_regex "${NGX_SSL_CRT}" "${prefix}")" \ + || ADDS="${ADDS}${indent}$(_sed_rhs "${NGX_SSL_CRT}" "${prefix}")" + echo "${CONF}" | grep -qE "$(_regex "${NGX_SSL_KEY}" "${prefix}")" \ + || ADDS="${ADDS}${indent}$(_sed_rhs "${NGX_SSL_KEY}" "${prefix}")" + echo "${CONF}" | grep -qE "^\s*ssl_session_cache\s" \ + || ADDS="${ADDS}${indent}$(_sed_rhs "${NGX_SSL_SESSION_CACHE}" "${name}")" + echo "${CONF}" | grep -qE "^\s*ssl_session_timeout\s" \ + || ADDS="${ADDS}${indent}$(_sed_rhs "${NGX_SSL_SESSION_TIMEOUT}" "")" + + if [ -n "${ADDS}" ] + then + ADDS="$(echo "${ADDS}" | sed -E 's/^\\n//')" + echo "${CONF}" | grep -qE "$(_regex "${NGX_SERVER_NAME}" "${name}")" \ + && echo "${CONF}" \ + | sed -E "/$(_regex "${NGX_SERVER_NAME}" "${name}")/a\\${ADDS}" \ + > "${prefix}.with" \ + && _echo_sed "Added directives to ${prefix}.with:\n${ADDS}" \ + && return 0 \ + || _echo_sed "Cannot add directives to ${prefix}.sans, missing:\ + \n$(_sed_rhs "${NGX_SERVER_NAME}" "${name}")\n${ADDS}" + return 1 + fi + return 0 +} + +# ---------------------------------------------------------------------------- + + +function test() { + eval "$1 2>/dev/null >/dev/null " + if [ $? -eq $2 ] + then + [ "${PRINT_PASSED}" -gt 0 ] \ + && printf "%-72s%-1s\n" "$1" "2>/dev/null >/dev/null (-> $2?) passed." + else + printf "%-72s%-1s\n" "$1" "2>/dev/null >/dev/null (-> $2?) failed!!!" + [ "${PRINT_PASSED}" -gt 1 ] && exit 1 + fi +} + + +[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting ${NGINX_UTIL} get_env ...\n" + +eval $("${NGINX_UTIL}" get_env) +test '[ -n "${NGINX_CONF}" ]' 0 +test '[ -n "${CONF_DIR}" ]' 0 +test '[ -n "${LAN_NAME}" ]' 0 +test '[ -n "${LAN_LISTEN}" ]' 0 +test '[ -n "${LAN_SSL_LISTEN}" ]' 0 +test '[ -n "${SSL_SESSION_CACHE_ARG}" ]' 0 +test '[ -n "${SSL_SESSION_TIMEOUT_ARG}" ]' 0 +test '[ -n "${ADD_SSL_FCT}" ]' 0 + + +[ "$PRINT_PASSED" -gt 0 ] && printf "\nPrepare files in ${CONF_DIR} ...\n" + +mkdir -p ${CONF_DIR} + +cd ${CONF_DIR} + +NGX_INCLUDE="include '\$';" +NGX_SERVER_NAME="server_name * '\$' *;" +NGX_SSL_CRT="ssl_certificate '\$.crt';" +NGX_SSL_KEY="ssl_certificate_key '\$.key';" +NGX_SSL_SESSION_CACHE="ssl_session_cache '$(echo "${SSL_SESSION_CACHE_ARG}" \ + | sed -E "s/$(__esc_regex ${LAN_NAME})/\$/")';" +NGX_SSL_SESSION_TIMEOUT="ssl_session_timeout '${SSL_SESSION_TIMEOUT_ARG}';" + +cat > ${LAN_NAME}.sans < minimal.sans < normal.sans < more_server.sans < more_names.sans < different_name.sans < comments.sans < name_comment.sans < tab.sans </dev/null) + [ "$?" -gt 0 ] && { + echo "created ${name}.conf:"; cat "${name}.conf" + echo "differs from setpoint:"; cat "${name}.with" + exit 1 + } +done + + +[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting ${NGINX_UTIL} del_ssl ...\n" + +sed -i "/server {/a\\ include '${LAN_LISTEN}';" minimal.sans + +for conf in ${CONFS}; do + name=${conf%:*} + cp ${name}.with ${name}.conf + test '${NGINX_UTIL} del_ssl '${name} ${conf#*:} + (test '[ "$(cat '${name}'.conf)" == "$(cat '${name}'.sans)" ]' 0 >/dev/null) + [ "$?" -gt 0 ] && { + echo "created ${name}.conf:"; cat "${name}.conf" + echo "differs from setpoint:"; cat "${name}.sans" + exit 1 + } +done + diff --git a/net/nginx-util/src/test-nginx-util.sh b/net/nginx-util/src/test-nginx-util.sh new file mode 100755 index 000000000..840f6f260 --- /dev/null +++ b/net/nginx-util/src/test-nginx-util.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +printf "Initializing tests ...\n" + +fakechroot="" + +[ -x /usr/bin/fakechroot ] && fakechroot="/usr/bin/fakechroot" \ +|| [ "$(id -u)" -eq 0 ] || { \ + printf "Error: Testing needs fakechroot or whoami=root for chroot." + return 1 +} + +TMPROOT=$(mktemp -d /tmp/test-nginx-util-XXXXXX) + +ln -s /bin ${TMPROOT}/bin + +mkdir -p ${TMPROOT}/usr/bin/ + +cp ./test-nginx-util-root.sh ${TMPROOT}/usr/bin/ + + +printf "\n\n******* Testing nginx-ssl-util-noubus *******\n" + +cp ./nginx-ssl-util-noubus ${TMPROOT}/usr/bin/nginx-util + +${fakechroot} /bin/chroot ${TMPROOT} /bin/sh -c /usr/bin/test-nginx-util-root.sh + +echo $? + + +printf "\n\n******* Testing nginx-ssl-util-nopcre-noubus *******\n" + +cp ./nginx-ssl-util-nopcre-noubus ${TMPROOT}/usr/bin/nginx-util + +${fakechroot} /bin/chroot ${TMPROOT} /bin/sh -c /usr/bin/test-nginx-util-root.sh + + +rm -r ${TMPROOT} diff --git a/net/nginx-util/src/test-px5g.sh b/net/nginx-util/src/test-px5g.sh index 9bae051c6..944464c2a 100755 --- a/net/nginx-util/src/test-px5g.sh +++ b/net/nginx-util/src/test-px5g.sh @@ -2,6 +2,7 @@ PRINT_PASSED=2 +printf "Initializing tests ...\n" OPENSSL_PEM="$(mktemp)" OPENSSL_DER="$(mktemp)" @@ -18,14 +19,14 @@ openssl req -x509 -nodes -days 1 -keyout /dev/null 2>/dev/null \ function test() { - MSG="$1 >/dev/null \t (-> $2?) \t" eval "$1 >/dev/null " if [ $? -eq $2 ] then - [ "$PRINT_PASSED" -gt 0 ] && printf "$MSG passed.\n" + [ "${PRINT_PASSED}" -gt 0 ] \ + && printf "%-72s%-1s\n" "$1" ">/dev/null (-> $2?) passed." else - printf "$MSG failed!!!\n" - [ "$PRINT_PASSED" -gt 1 ] && exit 1 + printf "%-72s%-1s\n" "$1" ">/dev/null (-> $2?) failed!!!" + [ "${PRINT_PASSED}" -gt 1 ] && exit 1 fi } diff --git a/net/nginx-util/src/ubus-cxx.hpp b/net/nginx-util/src/ubus-cxx.hpp index 83a1ee1df..b1a62c6ce 100644 --- a/net/nginx-util/src/ubus-cxx.hpp +++ b/net/nginx-util/src/ubus-cxx.hpp @@ -208,7 +208,7 @@ public: auto operator++() -> iterator &; - inline ~iterator() { if (cur.get()==this) { cur.release(); } } + inline ~iterator() { if (cur.get()==this) { static_cast(cur.release()); } } };