From 2d359a45566ea02792d3f63d7fe4ec1bdb1de2ae Mon Sep 17 00:00:00 2001 From: Peter Stadler Date: Tue, 26 May 2020 16:21:10 +0200 Subject: [PATCH] nginx-util: fix issues and cleanup * fix regex capture (to conform std) * fix issues for Clang/libcxx (warnings/includes) * fix CONFLICTS in the Makefile * use /bin/sh in host scripts and shellcheck them * add callback for setting arguments in ubus::call Signed-off-by: Peter Stadler --- net/nginx-util/Makefile | 21 ++- net/nginx-util/src/CMakeLists.txt | 19 +- net/nginx-util/src/nginx-ssl-util.hpp | 22 ++- net/nginx-util/src/nginx-util.cpp | 4 +- net/nginx-util/src/nginx-util.hpp | 37 +++- net/nginx-util/src/px5g-openssl.hpp | 76 ++++---- net/nginx-util/src/px5g.cpp | 14 +- net/nginx-util/src/regex-pcre.hpp | 44 +++-- net/nginx-util/src/test-nginx-util-root.sh | 73 ++++---- net/nginx-util/src/test-nginx-util.sh | 36 ++-- net/nginx-util/src/test-px5g.sh | 12 +- net/nginx-util/src/ubus-cxx.cpp | 148 ++++++++++++++++ net/nginx-util/src/ubus-cxx.hpp | 196 +++++++-------------- 13 files changed, 421 insertions(+), 281 deletions(-) create mode 100644 net/nginx-util/src/ubus-cxx.cpp diff --git a/net/nginx-util/Makefile b/net/nginx-util/Makefile index 5fd89878b..0d706d926 100644 --- a/net/nginx-util/Makefile +++ b/net/nginx-util/Makefile @@ -1,8 +1,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=nginx-util -PKG_VERSION:=1.3 -PKG_RELEASE:=2 +PKG_VERSION:=1.4 +PKG_RELEASE:=1 PKG_MAINTAINER:=Peter Stadler include $(INCLUDE_DIR)/package.mk @@ -11,6 +11,7 @@ include $(INCLUDE_DIR)/cmake.mk CMAKE_OPTIONS+= -DUBUS=y CMAKE_OPTIONS+= -DVERSION=$(PKG_VERSION) + define Package/nginx-util/default SECTION:=net CATEGORY:=Network @@ -19,63 +20,75 @@ define Package/nginx-util/default DEPENDS:=+libstdcpp +libubus +libubox +libpthread endef + define Package/nginx-util $(Package/nginx-util/default) CONFLICTS:=nginx-ssl-util-nopcre nginx-ssl-util endef + define Package/nginx-ssl-util/default $(Package/nginx-util/default) TITLE+= including SSL DEPENDS+= +libopenssl - CONFLICTS:=,nginx-util + CONFLICTS:=nginx-util, endef + define Package/nginx-ssl-util $(Package/nginx-ssl-util/default) TITLE+= (using PCRE) DEPENDS+= +libpcre - CONFLICTS+= ,nginx-ssl-util-nopcre + 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 Utility that builds dynamically LAN listen directives for Nginx. endef + Package/nginx-ssl-util/default/description = $(Package/nginx-util/description)\ Furthermore, it manages SSL directives for its server parts and can create \ corresponding (self-signed) certificates. + Package/nginx-ssl-util/description = \ $(Package/nginx-ssl-util/default/description) \ It uses the PCRE library for performance. + Package/nginx-ssl-util-nopcre/description = \ $(Package/nginx-ssl-util/default/description) \ It uses the standard regex library of C++. + define Package/nginx-util/install $(INSTALL_DIR) $(1)/usr/bin $(INSTALL_BIN) $(PKG_BUILD_DIR)/nginx-util $(1)/usr/bin/nginx-util endef + define Package/nginx-ssl-util/install $(INSTALL_DIR) $(1)/usr/bin $(INSTALL_BIN) $(PKG_BUILD_DIR)/nginx-ssl-util $(1)/usr/bin/nginx-util endef + define Package/nginx-ssl-util-nopcre/install $(INSTALL_DIR) $(1)/usr/bin $(INSTALL_BIN) $(PKG_BUILD_DIR)/nginx-ssl-util-nopcre \ $(1)/usr/bin/nginx-util endef + $(eval $(call BuildPackage,nginx-util)) $(eval $(call BuildPackage,nginx-ssl-util)) $(eval $(call BuildPackage,nginx-ssl-util-nopcre)) diff --git a/net/nginx-util/src/CMakeLists.txt b/net/nginx-util/src/CMakeLists.txt index af1d67ea1..3b06c8537 100644 --- a/net/nginx-util/src/CMakeLists.txt +++ b/net/nginx-util/src/CMakeLists.txt @@ -5,15 +5,8 @@ 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 -g3) -ADD_DEFINITIONS(-Wno-unused-parameter -Wmissing-declarations) +ADD_DEFINITIONS(-Wno-unused-parameter -Wmissing-declarations -Wshadow) SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") @@ -22,6 +15,14 @@ IF(UBUS) ADD_COMPILE_DEFINITIONS(VERSION=${VERSION}) +FIND_PATH(ubus_include_dir libubus.h) +FIND_LIBRARY(ubus NAMES ubus) +INCLUDE_DIRECTORIES(${ubus_include_dir}) + +FIND_PATH(ubox_include_dir libubox/blobmsg.h) +FIND_LIBRARY(ubox NAMES ubox) +INCLUDE_DIRECTORIES(${ubox_include_dir}) + ADD_EXECUTABLE(nginx-util nginx-util.cpp) TARGET_COMPILE_DEFINITIONS(nginx-util PUBLIC -DNO_SSL) TARGET_LINK_LIBRARIES(nginx-util ${ubox} ${ubus} pthread) @@ -38,6 +39,8 @@ INSTALL(TARGETS nginx-ssl-util-nopcre RUNTIME DESTINATION bin) ELSE() +ADD_COMPILE_DEFINITIONS(VERSION=0) + 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) diff --git a/net/nginx-util/src/nginx-ssl-util.hpp b/net/nginx-util/src/nginx-ssl-util.hpp index 0fa7009cc..895f9569f 100644 --- a/net/nginx-util/src/nginx-ssl-util.hpp +++ b/net/nginx-util/src/nginx-ssl-util.hpp @@ -1,8 +1,6 @@ #ifndef __NGINX_SSL_UTIL_HPP #define __NGINX_SSL_UTIL_HPP -#include - #ifdef NO_PCRE #include namespace rgx = std; @@ -147,7 +145,7 @@ constexpr auto _end = _Line{ template -constexpr auto _capture = _Line{ +static constexpr auto _capture = _Line{ [](const std::string & param, const std::string & /*begin*/) -> std::string { return '\'' + param + '\''; }, @@ -211,8 +209,8 @@ constexpr std::string_view _ssl_session_timeout = "ssl_session_timeout"; // * Use constexpr---not available for strings or char * for now---look at lib. static const auto CRON_CMD = Line::build - < _space, _escape, _space, _escape, _space, - _capture<>, _newline >(); + <_space, _escape, _space, _escape, _space, + _capture<>, _newline>(); static const auto NGX_SERVER_NAME = Line::build<_begin, _escape<_server_name>, _space, _capture<';'>, _end>(); @@ -221,15 +219,15 @@ static const auto NGX_INCLUDE_LAN_LISTEN = Line::build <_begin, _escape<_include>, _space, _escape, _end>(); static const auto NGX_INCLUDE_LAN_LISTEN_DEFAULT = Line::build - < _begin, _escape<_include>, _space, - _escape, _end >(); + <_begin, _escape<_include>, _space, + _escape, _end>(); static const auto NGX_INCLUDE_LAN_SSL_LISTEN = Line::build <_begin, _escape<_include>, _space, _escape, _end>(); static const auto NGX_INCLUDE_LAN_SSL_LISTEN_DEFAULT = Line::build - < _begin, _escape<_include>, _space, - _escape, _end >(); + <_begin, _escape<_include>, _space, + _escape, _end>(); static const auto NGX_SSL_CRT = Line::build <_begin, _escape<_ssl_certificate>, _space, _capture<';'>, _end>(); @@ -346,7 +344,7 @@ void add_ssl_directives_to(const std::string & name, const bool isdefault) auto errmsg = std::string{"add_ssl_directives_to error: "}; errmsg += "cannot add SSL directives to " + name + ".conf, missing: "; errmsg += NGX_SERVER_NAME.STR(name, "\n ") + "\n"; - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } @@ -476,7 +474,7 @@ void use_cron_to_recreate_certificate(const std::string & name) std::string errmsg{"use_cron_to_recreate_certificate error: "}; errmsg += "Cron unavailable to re-create the ssl certificate for "; errmsg += name + "\n"; - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } // else active with or without instances: #endif @@ -586,7 +584,7 @@ void del_ssl_directives_from(const std::string & name, const bool isdefault) auto errmsg = std::string{"del_ssl_directives_from error: "}; errmsg += "cannot delete SSL directives from " + name + ".conf, missing: "; errmsg += NGX_SERVER_NAME.STR(name, "\n ") + "\n"; - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } diff --git a/net/nginx-util/src/nginx-util.cpp b/net/nginx-util/src/nginx-util.cpp index 02aa7013a..b0a724da6 100644 --- a/net/nginx-util/src/nginx-util.cpp +++ b/net/nginx-util/src/nginx-util.cpp @@ -1,3 +1,5 @@ +#include + #include "nginx-util.hpp" #ifndef NO_SSL @@ -121,7 +123,7 @@ void get_env() auto main(int argc, char * argv[]) -> int { // TODO(pst): use std::span when available: - auto args = std::basic_string_view{argv, static_cast(argc)}; + auto args = std::basic_string_view{argv, static_cast(argc)}; auto cmds = std::array{ std::array{"init_lan", ""}, diff --git a/net/nginx-util/src/nginx-util.hpp b/net/nginx-util/src/nginx-util.hpp index f3f14ffad..f4999e74f 100644 --- a/net/nginx-util/src/nginx-util.hpp +++ b/net/nginx-util/src/nginx-util.hpp @@ -4,12 +4,14 @@ #include #include #include +#include #include #include -#include #include #include +#include #include +#include #ifndef NO_UBUS #include "ubus-cxx.hpp" @@ -61,15 +63,34 @@ void get_env(); void write_file(const std::string_view & name, const std::string & str, const std::ios_base::openmode flag) { - std::ofstream file(name.data(), flag); - if (!file.good()) { - throw std::ofstream::failure( - "write_file error: cannot open " + std::string{name}); + auto tmp = std::string{name}; + + if ( (flag & std::ios::ate) == 0 && (flag & std::ios::app) == 0 ) { + tmp += ".tmp-XXXXXX"; + auto fd = mkstemp(&tmp[0]); + if (fd==-1 || close(fd)!=0) + { throw std::runtime_error("write_file error: cannot access " + tmp); } } - file< pid_t std::string errmsg = "call error: cannot fork ("; errmsg += std::to_string(errno) + "): " + std::strerror(errno); - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } diff --git a/net/nginx-util/src/px5g-openssl.hpp b/net/nginx-util/src/px5g-openssl.hpp index 380eba335..1b70dc5b0 100644 --- a/net/nginx-util/src/px5g-openssl.hpp +++ b/net/nginx-util/src/px5g-openssl.hpp @@ -8,9 +8,11 @@ #include #include #include +#include #include #include + static constexpr auto rsa_min_modulus_bits = 512; using EVP_PKEY_ptr = std::unique_ptr; @@ -52,11 +54,20 @@ inline auto print_error(const char * str, const size_t /*len*/, void * errmsg) } +// wrapper for clang-tidy: +inline auto _BIO_new_fp(FILE * stream, const bool use_pem, + const bool close=false) -> BIO * +{ + return BIO_new_fp( stream, //NOLINTNEXTLINE(hicpp-signed-bitwise) macros: + (use_pem ? BIO_FP_TEXT : 0) | (close ? BIO_CLOSE : BIO_NOCLOSE) ); +} + + auto checkend(const std::string & crtpath, const time_t seconds, const bool use_pem) -> bool { BIO * bio = crtpath.empty() ? - BIO_new_fp(stdin, BIO_NOCLOSE | (use_pem ? BIO_FP_TEXT : 0)) : + _BIO_new_fp(stdin, use_pem) : BIO_new_file(crtpath.c_str(), (use_pem ? "r" : "rb")); X509 * x509 = nullptr; @@ -71,7 +82,7 @@ auto checkend(const std::string & crtpath, if (x509==nullptr) { std::string errmsg{"checkend error: unable to load certificate\n"}; ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } time_t checktime = time(nullptr) + seconds; @@ -91,7 +102,7 @@ auto gen_eckey(const int curve) -> EVP_PKEY_ptr std::string errmsg{"gen_eckey error: cannot build group for curve id "}; errmsg += std::to_string(curve) + "\n"; ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); @@ -115,18 +126,18 @@ auto gen_eckey(const int curve) -> EVP_PKEY_ptr std::string errmsg{"gen_eckey error: cannot build key with curve id "}; errmsg += std::to_string(curve) + "\n"; ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } EVP_PKEY_ptr pkey{EVP_PKEY_new(), ::EVP_PKEY_free}; - auto tmp = static_cast(static_cast(eckey)); - - if (!EVP_PKEY_assign_EC_KEY(pkey.get(), tmp)) { + // EVP_PKEY_assign_EC_KEY is a macro casting eckey to char *: + //NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) + if (!EVP_PKEY_assign_EC_KEY(pkey.get(), eckey)) { EC_KEY_free(eckey); std::string errmsg{"gen_eckey error: cannot assign EC key to EVP\n"}; ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } return pkey; @@ -139,14 +150,14 @@ auto gen_rsakey(const int keysize, const BN_ULONG exponent) -> EVP_PKEY_ptr std::string errmsg{"gen_rsakey error: RSA keysize ("}; errmsg += std::to_string(keysize) + ") out of range [512.."; errmsg += std::to_string(OPENSSL_RSA_MAX_MODULUS_BITS) + "]"; - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } auto bignum = BN_new(); if (bignum == nullptr) { std::string errmsg{"gen_rsakey error: cannot get big number struct\n"}; ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } auto rsa = RSA_new(); @@ -167,18 +178,18 @@ auto gen_rsakey(const int keysize, const BN_ULONG exponent) -> EVP_PKEY_ptr errmsg += std::to_string(keysize) + " and exponent "; errmsg += std::to_string(exponent) + "\n"; ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } EVP_PKEY_ptr pkey{EVP_PKEY_new(), ::EVP_PKEY_free}; - auto tmp = static_cast(static_cast(rsa)); - - if (!EVP_PKEY_assign_RSA(pkey.get(), tmp)) { + // EVP_PKEY_assign_RSA is a macro casting rsa to char *: + //NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) + if (!EVP_PKEY_assign_RSA(pkey.get(), rsa)) { RSA_free(rsa); std::string errmsg{"gen_rsakey error: cannot assign RSA key to EVP\n"}; ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } return pkey; @@ -190,20 +201,21 @@ void write_key(const EVP_PKEY_ptr & pkey, { BIO * bio = nullptr; - if (keypath.empty()) { - bio = BIO_new_fp( stdout, BIO_NOCLOSE | (use_pem ? BIO_FP_TEXT : 0) ); + if (keypath.empty()) { bio = _BIO_new_fp(stdout, use_pem); } - } else { // BIO_new_file(keypath.c_str(), (use_pem ? "w" : "wb") ); + else { // BIO_new_file(keypath.c_str(), (use_pem ? "w" : "wb") ); static constexpr auto mask = 0600; // auto fd = open(keypath.c_str(), O_WRONLY | O_CREAT | O_TRUNC, mask); + // creat has no cloexec, alt. triggers cppcoreguidelines-pro-type-vararg + //NOLINTNEXTLINE(android-cloexec-creat) auto fd = creat(keypath.c_str(), mask); // the same without va_args. if (fd >= 0) { auto fp = fdopen(fd, (use_pem ? "w" : "wb") ); if (fp != nullptr) { - bio = BIO_new_fp(fp, BIO_CLOSE | (use_pem ? BIO_FP_TEXT : 0)); + bio = _BIO_new_fp(fp, use_pem, true); if (bio == nullptr) { fclose(fp); } // (fp owns fd) } else { close(fd); } @@ -216,7 +228,7 @@ void write_key(const EVP_PKEY_ptr & pkey, errmsg += keypath.empty() ? "stdout" : keypath; errmsg += "\n"; ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } int len = 0; @@ -249,7 +261,7 @@ void write_key(const EVP_PKEY_ptr & pkey, errmsg += keypath.empty() ? "stdout" : keypath; errmsg += "\n"; ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } } @@ -265,7 +277,7 @@ auto subject2name(const std::string & subject) -> X509_NAME_ptr if (!name) { std::string errmsg{"subject2name error: cannot create X509 name \n"}; ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } if (subject.empty()) { return name; } @@ -287,19 +299,21 @@ auto subject2name(const std::string & subject) -> X509_NAME_ptr if (nid == NID_undef) { // skip unknown entries (silently?). } else { - auto val = static_cast( - static_cast(&subject[prev]) ); + auto val = // X509_NAME_add_entry_by_NID wants it unsigned: + //NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + reinterpret_cast(&subject[prev]); auto len = i - prev; - if ( X509_NAME_add_entry_by_NID(name.get(), nid, MBSTRING_ASC, - val, len, -1, 0) + if ( X509_NAME_add_entry_by_NID(name.get(), nid, + MBSTRING_ASC, //NOLINT(hicpp-signed-bitwise) is macro + val, len, -1, 0) == 0 ) { std::string errmsg{"subject2name error: cannot add "}; errmsg += "/" + type +"="+ subject.substr(prev, len) +"\n"; ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } } chr = '='; @@ -320,7 +334,7 @@ void selfsigned(const EVP_PKEY_ptr & pkey, const int days, if (x509 == nullptr) { std::string errmsg{"selfsigned error: cannot create X509 structure\n"}; ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } auto freeX509_and_throw = [&x509](const std::string & what) @@ -329,7 +343,7 @@ void selfsigned(const EVP_PKEY_ptr & pkey, const int days, std::string errmsg{"selfsigned error: cannot set "}; errmsg += what + " in X509 certificate\n"; ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); }; if (X509_set_version(x509, 2) == 0) { freeX509_and_throw("version"); } @@ -380,7 +394,7 @@ void selfsigned(const EVP_PKEY_ptr & pkey, const int days, } BIO * bio = crtpath.empty() ? - BIO_new_fp(stdout, BIO_NOCLOSE | (use_pem ? BIO_FP_TEXT : 0)) : + _BIO_new_fp(stdout, use_pem) : BIO_new_file(crtpath.c_str(), (use_pem ? "w" : "wb")); int len = 0; @@ -399,7 +413,7 @@ void selfsigned(const EVP_PKEY_ptr & pkey, const int days, errmsg += crtpath.empty() ? "stdout" : crtpath; errmsg += "\n"; ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } } diff --git a/net/nginx-util/src/px5g.cpp b/net/nginx-util/src/px5g.cpp index 5ad13357b..e2a073d35 100644 --- a/net/nginx-util/src/px5g.cpp +++ b/net/nginx-util/src/px5g.cpp @@ -118,7 +118,7 @@ auto checkend(const argv_view & argv) -> int } catch (...) { auto errmsg = std::string{"checkend error: invalid time "}; errmsg += argv[i]; - std::throw_with_nested(std::runtime_error(errmsg.c_str())); + std::throw_with_nested(std::runtime_error(errmsg)); } seconds = static_cast(num); @@ -126,7 +126,7 @@ auto checkend(const argv_view & argv) -> int if (num!=static_cast(seconds)) { auto errmsg = std::string{"checkend error: time too big "}; errmsg += argv[i]; - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); } } } @@ -174,7 +174,7 @@ void eckey(const argv_view & argv) if (has_main_option) { throw std::runtime_error ("eckey error: more than one main option"); - } // else: + } //else: has_main_option = true; curve = parse_curve(argv[i]); @@ -223,7 +223,7 @@ void rsakey(const argv_view & argv) if (has_main_option) { throw std::runtime_error("rsakey error: more than one keysize"); - } // else: + } //else: has_main_option = true; try { @@ -231,7 +231,7 @@ void rsakey(const argv_view & argv) } catch (...) { std::string errmsg{"rsakey error: invalid keysize "}; errmsg += argv[i]; - std::throw_with_nested(std::runtime_error(errmsg.c_str())); + std::throw_with_nested(std::runtime_error(errmsg)); } } } @@ -264,7 +264,7 @@ void selfsigned(const argv_view & argv) } catch (...) { std::string errmsg{"selfsigned error: not a number for -days "}; errmsg += argv[i].substr(4); - std::throw_with_nested(std::runtime_error(errmsg.c_str())); + std::throw_with_nested(std::runtime_error(errmsg)); } } @@ -287,7 +287,7 @@ void selfsigned(const argv_view & argv) } catch (...) { std::string errmsg{"selfsigned error: invalid keysize "}; errmsg += argv[i].substr(4); - std::throw_with_nested(std::runtime_error(errmsg.c_str())); + std::throw_with_nested(std::runtime_error(errmsg)); } } else { throw std::runtime_error("selfsigned error: invalid algorithm"); diff --git a/net/nginx-util/src/regex-pcre.hpp b/net/nginx-util/src/regex-pcre.hpp index 8408b60f4..bfd3a0534 100644 --- a/net/nginx-util/src/regex-pcre.hpp +++ b/net/nginx-util/src/regex-pcre.hpp @@ -1,5 +1,3 @@ -// implementing *some* functions using pcre for performance: - #ifndef __REGEXP_PCRE_HPP #define __REGEXP_PCRE_HPP @@ -11,6 +9,9 @@ namespace rgx { +/* partially implement the std::regex interface using PCRE for performance + * (=> pass "match" as non-const reference) + */ namespace regex_constants { @@ -130,8 +131,8 @@ class smatch { friend auto regex_search(std::string::const_iterator begin, std::string::const_iterator end, - smatch & match, - const regex & rgx); + smatch & match, //NOLINT(google-runtime-references) + const regex & rgx); // match std::regex interface. private: @@ -188,14 +189,15 @@ auto regex_replace(const std::string & subj, const std::string & insert); -inline auto regex_search(const std::string & subj, smatch & match, - const regex & rgx); +inline auto regex_search(const std::string & subj, + smatch & match, //NOLINT(google-runtime-references) + const regex & rgx); // match std::regex interface. auto regex_search(std::string::const_iterator begin, std::string::const_iterator end, - smatch & match, - const regex & rgx); + smatch & match, //NOLINT(google-runtime-references) + const regex & rgx); // match std::regex interface. @@ -260,12 +262,10 @@ auto smatch::format(const std::string & fmt) const { index = pos + 1; char chr = fmt[index++]; - int n = 0; - static const auto BASE = 10; switch(chr) { case '&': // match - ret += this->str(0); + ret += str(0); break; case '`': // prefix @@ -276,14 +276,20 @@ auto smatch::format(const std::string & fmt) const { ret.append(begin+vec[1], end); break; - default: // number => submatch - while (isdigit(chr) != 0) { - n = BASE*n + chr - '0'; - chr = fmt[index++]; - } - - ret += n>0 ? str(n) : std::string{"$"}; - + default: + if (isdigit(chr) != 0) { // one or two digits => submatch: + int num = chr - '0'; + chr = fmt[index]; + if (isdigit(chr) != 0) { // second digit: + ++index; + static const auto base = 10; + num = num*base + chr - '0'; + } + ret += str(num); + break; + } //else: + + ret += '$'; [[fallthrough]]; case '$': // escaped diff --git a/net/nginx-util/src/test-nginx-util-root.sh b/net/nginx-util/src/test-nginx-util-root.sh index a6d78757c..0ce8c9428 100644 --- a/net/nginx-util/src/test-nginx-util-root.sh +++ b/net/nginx-util/src/test-nginx-util-root.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh PRINT_PASSED=2 @@ -37,7 +37,7 @@ setpoint_add_ssl() { local indent="\n$1" local name="$2" local default="" - [ "${name}" == "${LAN_NAME}" ] && default=".default" + [ "${name}" = "${LAN_NAME}" ] && default=".default" local prefix="${CONF_DIR}${name}" local CONF="$(grep -vE "$(_regex "${NGX_INCLUDE}" \ @@ -74,10 +74,17 @@ setpoint_add_ssl() { # ---------------------------------------------------------------------------- +test_setpoint() { + [ "$(cat "$1")" = "$2" ] && return + echo "$1:"; cat "$1" + echo "differs from setpoint:"; echo "$2" + [ "${PRINT_PASSED}" -gt 1 ] && pst_exit 1 +} + -function test() { - eval "$1 2>/dev/null >/dev/null " - if [ $? -eq $2 ] +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." @@ -88,7 +95,7 @@ function test() { } -[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting ${NGINX_UTIL} get_env ...\n" +[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting %s get_env ...\n" "${NGINX_UTIL}" eval $("${NGINX_UTIL}" get_env) test '[ -n "${NGINX_CONF}" ]' 0 @@ -101,21 +108,21 @@ test '[ -n "${SSL_SESSION_TIMEOUT_ARG}" ]' 0 test '[ -n "${ADD_SSL_FCT}" ]' 0 -[ "$PRINT_PASSED" -gt 0 ] && printf "\nPrepare files in ${CONF_DIR} ...\n" +[ "$PRINT_PASSED" -gt 0 ] && printf "\nPrepare files in %s ...\n" "${CONF_DIR}" -mkdir -p ${CONF_DIR} +mkdir -p "${CONF_DIR}" -cd ${CONF_DIR} +cd "${CONF_DIR}" || exit 2 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})/\$/")';" + | sed -E "s/$(__esc_regex "${LAN_NAME}")/\$/")';" NGX_SSL_SESSION_TIMEOUT="ssl_session_timeout '${SSL_SESSION_TIMEOUT_ARG}';" -cat > ${LAN_NAME}.sans < "${LAN_NAME}.sans" </dev/null) - [ "$?" -gt 0 ] && { - echo "created ${name}.conf:"; cat "${name}.conf" - echo "differs from setpoint:"; cat "${name}.with" - exit 1 - } + name="${conf%:*}" + cp "${name}.sans" "${name}.conf" + test '"${NGINX_UTIL}" add_ssl '"${name}" "${conf#*:}" + test_setpoint "${name}.conf" "$(cat "${name}.with")" done - -[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting ${NGINX_UTIL} del_ssl ...\n" +[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting %s del_ssl ...\n" "${NGINX_UTIL}" 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 - } + name="${conf%:*}" + cp "${name}.with" "${name}.conf" + test '"${NGINX_UTIL}" del_ssl '"${name}" "${conf#*:}" + test_setpoint "${name}.conf" "$(cat "${name}.sans")" done - diff --git a/net/nginx-util/src/test-nginx-util.sh b/net/nginx-util/src/test-nginx-util.sh index 840f6f260..787906350 100755 --- a/net/nginx-util/src/test-nginx-util.sh +++ b/net/nginx-util/src/test-nginx-util.sh @@ -1,38 +1,48 @@ -#!/bin/bash +#!/bin/sh printf "Initializing tests ...\n" fakechroot="" -[ -x /usr/bin/fakechroot ] && fakechroot="/usr/bin/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) +TMPROOT="$(mktemp -d "/tmp/test-nginx-util-XXXXXX")" -ln -s /bin ${TMPROOT}/bin +ln -s /bin "${TMPROOT}/bin" -mkdir -p ${TMPROOT}/usr/bin/ +mkdir -p "${TMPROOT}/usr/bin/" -cp ./test-nginx-util-root.sh ${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 +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 $? +"${fakechroot}" /bin/chroot "${TMPROOT}" \ + /bin/sh -c "/usr/bin/test-nginx-util-root.sh" || +{ + echo "!!! Error: $?" + rm -r "${TMPROOT}" + exit 1 +} printf "\n\n******* Testing nginx-ssl-util-nopcre-noubus *******\n" -cp ./nginx-ssl-util-nopcre-noubus ${TMPROOT}/usr/bin/nginx-util +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 +"${fakechroot}" /bin/chroot "${TMPROOT}" \ + /bin/sh -c "/usr/bin/test-nginx-util-root.sh" || +{ + echo "!!! Error: $?" + rm -r "${TMPROOT}" + exit 1 +} -rm -r ${TMPROOT} +rm -r "${TMPROOT}" diff --git a/net/nginx-util/src/test-px5g.sh b/net/nginx-util/src/test-px5g.sh index 944464c2a..486b9ae98 100755 --- a/net/nginx-util/src/test-px5g.sh +++ b/net/nginx-util/src/test-px5g.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh PRINT_PASSED=2 @@ -8,7 +8,7 @@ OPENSSL_PEM="$(mktemp)" OPENSSL_DER="$(mktemp)" NONCE=$(dd if=/dev/urandom bs=1 count=4 2>/dev/null | hexdump -e '1/1 "%02x"') -SUBJECT=/C="ZZ"/ST="Somewhere"/L="None"/O="OpenWrt'$NONCE'"/CN="OpenWrt" +SUBJECT="/C=ZZ/ST=Somewhere/L=None/O=OpenWrt'$NONCE'/CN=OpenWrt" openssl req -x509 -nodes -days 1 -keyout /dev/null 2>/dev/null \ -out "$OPENSSL_PEM" -subj "$SUBJECT" \ @@ -18,9 +18,9 @@ openssl req -x509 -nodes -days 1 -keyout /dev/null 2>/dev/null \ || ( printf "error: generating DER certificate with openssl"; return 1) -function test() { +test() { eval "$1 >/dev/null " - if [ $? -eq $2 ] + if [ $? -eq "$2" ] then [ "${PRINT_PASSED}" -gt 0 ] \ && printf "%-72s%-1s\n" "$1" ">/dev/null (-> $2?) passed." @@ -130,8 +130,8 @@ test './px5g selfsigned -newkey rsa:666 | openssl x509 -checkend 0 ' 0 test './px5g selfsigned -newkey ec | openssl x509 -checkend 0 ' 0 test './px5g selfsigned -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 \ | openssl x509 -checkend 0 ' 0 -test './px5g selfsigned -subj $SUBJECT | openssl x509 -noout \ - -subject -nameopt compat | grep -q subject=$SUBJECT 2>/dev/null' 0 +test './px5g selfsigned -subj "$SUBJECT" | openssl x509 -noout \ + -subject -nameopt compat | grep -q subject="$SUBJECT" 2>/dev/null' 0 test './px5g selfsigned -out /dev/null -keyout /proc/self/fd/1 \ | openssl rsa -check 2>/dev/null ' 0 diff --git a/net/nginx-util/src/ubus-cxx.cpp b/net/nginx-util/src/ubus-cxx.cpp new file mode 100644 index 000000000..7f65813ca --- /dev/null +++ b/net/nginx-util/src/ubus-cxx.cpp @@ -0,0 +1,148 @@ +#include + +#include "ubus-cxx.hpp" + + +inline void example_for_checking_if_there_is_a_key() +{ + if (ubus::call("service", "list").filter("cron")) { + std::cout<<"Cron is active (with or without instances) "<(t); + std::cout<<"["<(t); + std::cout< int + { return blobmsg_add_string(buf, "config", "nginx"); }; + for (auto t : ubus::call("uci", "get", set_arg).filter("values")) { + //NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) + auto x = const_cast(t); + std::cout<(t); + std::cout< void + { + auto end = message.end(); + auto explore_internal = + [&end](auto & explore_ref, auto it, size_t depth=1) -> void + { + std::cout<(*it); + if (first) { first = false; } + else { std::cout<<",\n"; } + std::cout< int { + + try { + example_for_checking_if_there_is_a_key(); + + example_for_getting_values(); + + example_for_sending_message(); + + example_for_exploring(); + + example_for_recursive_exploring(); + + return 0; + } + + catch (const std::exception & e) { std::cerr< -} #include +#include #include #include #include #include #include + #ifndef NDEBUG #include #endif -// // example for checking if there is a key: -// if (ubus::call("service", "list", 1000).filter("cron")) { -// std::cout<<"Cron is active (with or without instances) "< void -// { -// auto end = message.end(); -// auto explore_internal = -// [&end](auto & explore_ref, auto it, size_t depth=1) -> void -// { -// std::cout<; using strings = std::vector; @@ -130,7 +39,7 @@ inline auto concat(strings dest, strings src, Strings ...more) template inline auto concat(strings dest, S src, Strings ...more) { - dest.push_back(std::move(src)); + dest.emplace_back(std::move(src)); return concat(std::move(dest), std::move(more)...); } @@ -186,7 +95,7 @@ public: } - inline iterator(iterator &&) = default; + inline iterator(iterator &&) noexcept = default; inline iterator(const iterator &) = delete; @@ -208,7 +117,8 @@ public: auto operator++() -> iterator &; - inline ~iterator() { if (cur.get()==this) { static_cast(cur.release()); } } + inline ~iterator() + { if (cur.get()==this) { static_cast(cur.release()); } } }; @@ -225,8 +135,8 @@ private: public: - inline explicit message(msg_ptr message, strings filter={""}) - : msg{std::move(message)}, keys{std::move(filter)} {} + inline explicit message(msg_ptr message_ptr, strings filter={""}) + : msg{std::move(message_ptr)}, keys{std::move(filter)} {} inline message(message &&) = default; @@ -268,42 +178,41 @@ public: -class ubus { +class lock_shared_resources { private: - static std::mutex buffering; + static std::mutex inuse; public: - inline ubus() = delete; + inline lock_shared_resources() { inuse.lock(); } - inline ubus(ubus &&) = delete; + inline lock_shared_resources(lock_shared_resources &&) noexcept = default; - inline ubus(const ubus &) = delete; + inline lock_shared_resources(const lock_shared_resources &) = delete; - inline auto operator=(ubus &&) -> auto && = delete; + inline auto operator=(const lock_shared_resources &) -> auto & = delete; - inline auto operator=(const ubus &) -> auto & = delete; + inline auto operator=(lock_shared_resources &&) -> auto && = delete; - static auto get_context() -> ubus_context * + + //NOLINTNEXTLINE(readability-convert-member-functions-to-static) + inline auto get_context() -> ubus_context * // is member to enforce inuse. { static auto ubus_freeing = [] (ubus_context * ctx) { ubus_free(ctx); }; static std::unique_ptr lazy_ctx{ubus_connect(nullptr), ubus_freeing}; if (!lazy_ctx) { // it could be available on a later call: - static std::mutex connecting; - connecting.lock(); - if (!lazy_ctx) { lazy_ctx.reset(ubus_connect(nullptr)); } - connecting.unlock(); + lazy_ctx.reset(ubus_connect(nullptr)); if (!lazy_ctx) { throw std::runtime_error("ubus error: cannot connect context"); @@ -314,7 +223,8 @@ public: } - static auto lock_and_get_shared_blob_buf() -> blob_buf * + //NOLINTNEXTLINE(readability-convert-member-functions-to-static) + inline auto get_blob_buf() -> blob_buf * // is member to enforce inuse. { static blob_buf buf; @@ -322,28 +232,37 @@ public: static std::unique_ptr created_to_free_on_the_end_of_life{&buf, blob_buf_freeing}; - buffering.lock(); blob_buf_init(&buf, 0); + return &buf; } - static void unlock_shared_blob_buf() { buffering.unlock(); } + inline ~lock_shared_resources() { inuse.unlock(); } +}; - inline ~ubus() = delete; -}; +template +auto call(const char * path, const char * method, F set_arguments, + int timeout=call_timeout) -> message; + + +inline auto call(const char * path, const char * method, + int timeout=call_timeout) -> message +{ return call(path, method, [](blob_buf * /*buf*/) { return 0; }, timeout); } + +inline auto call(const char * path, int timeout=call_timeout) -> message +{ return call(path, "", timeout); } -auto call(const char * path, const char * method="", int timeout=500); // ------------------------- implementation: ---------------------------------- -std::mutex ubus::buffering; +std::mutex lock_shared_resources::inuse; inline auto iterator::operator++() -> iterator & @@ -363,7 +282,10 @@ inline auto iterator::operator++() -> iterator & ++i; auto tmp = cur.release(); - cur = std::unique_ptr{new iterator(tmp)}; + + struct new_iterator : public iterator // use private constructor: + { explicit new_iterator(iterator * par) : iterator{par} {} }; + cur = std::make_unique(tmp); } else { while (true) { @@ -392,31 +314,39 @@ inline auto iterator::operator++() -> iterator & } -inline auto call(const char * path, const char * method, const int timeout) +template +inline auto call(const char * path, const char * method, F set_arguments, + int timeout) -> message { - auto ctx = ubus::get_context(); + + auto shared = lock_shared_resources{}; + + auto ctx = shared.get_context(); uint32_t id; int err = ubus_lookup_id(ctx, path, &id); if (err==0) { // call - ubus_request req{}; + ubus_request request{}; - auto buf = ubus::lock_and_get_shared_blob_buf(); - err = ubus_invoke_async(ctx, id, method, buf->head, &req); - ubus::unlock_shared_blob_buf(); + auto buf = shared.get_blob_buf(); + err = set_arguments(buf); + if (err==0) { + err = ubus_invoke_async(ctx, id, method, buf->head, &request); + } if (err==0) { - msg_ptr msg; + msg_ptr message_ptr; - /* Cannot capture anything (msg), the lambda would be another type. + /* Cannot capture message_ptr, the lambda would be another type. * Pass a location where to save the message as priv pointer when * invoking and get it back here: */ - req.priv = &msg; + request.priv = &message_ptr; - req.data_cb = [](ubus_request * req, int /*type*/, blob_attr * msg) + request.data_cb = + [](ubus_request * req, int /*type*/, blob_attr * msg) { if (req==nullptr || msg==nullptr) { return; } @@ -427,15 +357,15 @@ inline auto call(const char * path, const char * method, const int timeout) if (!*saved) { throw std::bad_alloc(); } }; - err = ubus_complete_request(ctx, &req, timeout); + err = ubus_complete_request(ctx, &request, timeout); - if (err==0) { return message{msg}; } + if (err==0) { return message{message_ptr}; } } } std::string errmsg = "ubus::call error: cannot invoke"; errmsg += " (" + std::to_string(err) + ") " + path + " " + method; - throw std::runtime_error(errmsg.c_str()); + throw std::runtime_error(errmsg); }