Merge pull request #12323 from peter-stadler/nginx-util-clang
nginx-util: fix issues and cleanup
This commit is contained in:
commit
c94ded697b
13 changed files with 421 additions and 281 deletions
|
@ -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 <peter.stadler@student.uibk.ac.at>
|
||||
|
||||
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 <regex>)
|
||||
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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef __NGINX_SSL_UTIL_HPP
|
||||
#define __NGINX_SSL_UTIL_HPP
|
||||
|
||||
#include <thread>
|
||||
|
||||
#ifdef NO_PCRE
|
||||
#include <regex>
|
||||
namespace rgx = std;
|
||||
|
@ -147,7 +145,7 @@ constexpr auto _end = _Line{
|
|||
|
||||
|
||||
template<char clim='\0'>
|
||||
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<NGINX_UTIL>, _space, _escape<ADD_SSL_FCT,'\''>, _space,
|
||||
_capture<>, _newline >();
|
||||
<_space, _escape<NGINX_UTIL>, _space, _escape<ADD_SSL_FCT,'\''>, _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<LAN_LISTEN,'\''>, _end>();
|
||||
|
||||
static const auto NGX_INCLUDE_LAN_LISTEN_DEFAULT = Line::build
|
||||
< _begin, _escape<_include>, _space,
|
||||
_escape<LAN_LISTEN_DEFAULT, '\''>, _end >();
|
||||
<_begin, _escape<_include>, _space,
|
||||
_escape<LAN_LISTEN_DEFAULT, '\''>, _end>();
|
||||
|
||||
static const auto NGX_INCLUDE_LAN_SSL_LISTEN = Line::build
|
||||
<_begin, _escape<_include>, _space, _escape<LAN_SSL_LISTEN, '\''>, _end>();
|
||||
|
||||
static const auto NGX_INCLUDE_LAN_SSL_LISTEN_DEFAULT = Line::build
|
||||
< _begin, _escape<_include>, _space,
|
||||
_escape<LAN_SSL_LISTEN_DEFAULT, '\''>, _end >();
|
||||
<_begin, _escape<_include>, _space,
|
||||
_escape<LAN_SSL_LISTEN_DEFAULT, '\''>, _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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include <iostream>
|
||||
|
||||
#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<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", ""},
|
||||
|
|
|
@ -4,12 +4,14 @@
|
|||
#include <array>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
#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<<str<<std::flush;
|
||||
try {
|
||||
std::ofstream file(tmp.data(), flag);
|
||||
if (!file.good()) {
|
||||
throw std::ofstream::failure
|
||||
("write_file error: cannot open " + std::string{tmp});
|
||||
}
|
||||
|
||||
file.close();
|
||||
file<<str<<std::flush;
|
||||
|
||||
file.close();
|
||||
} catch(...) {
|
||||
if (tmp!=name) { remove(tmp.c_str()); } //remove can fail.
|
||||
throw;
|
||||
}
|
||||
|
||||
if (rename(tmp.c_str(), name.data()) != 0) {
|
||||
throw std::runtime_error
|
||||
("write_file error: cannot move " + tmp + " to " + name.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -113,7 +134,7 @@ auto call(const char * program, S... args) -> 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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -8,9 +8,11 @@
|
|||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
static constexpr auto rsa_min_modulus_bits = 512;
|
||||
|
||||
using EVP_PKEY_ptr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
|
||||
|
@ -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<char *>(static_cast<void *>(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<char *>(static_cast<void *>(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<const unsigned char *>(
|
||||
static_cast<const void *>(&subject[prev]) );
|
||||
auto val = // X509_NAME_add_entry_by_NID wants it unsigned:
|
||||
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
reinterpret_cast<const unsigned char *>(&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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<time_t>(num);
|
||||
|
@ -126,7 +126,7 @@ auto checkend(const argv_view & argv) -> int
|
|||
if (num!=static_cast<intmax_t>(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");
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// implementing *some* <regex> 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
|
||||
|
|
|
@ -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 <<EOF
|
||||
cat > "${LAN_NAME}.sans" <<EOF
|
||||
# default_server for the LAN addresses getting the IPs by:
|
||||
# ifstatus lan | jsonfilter -e '@["ipv4-address","ipv6-address"].*.address'
|
||||
server {
|
||||
|
@ -196,56 +203,44 @@ EOF
|
|||
CONFS="${CONFS} tab:0"
|
||||
|
||||
|
||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting ${NGINX_UTIL} init_lan ...\n"
|
||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting %s init_lan ...\n" "${NGINX_UTIL}"
|
||||
|
||||
mkdir -p "$(dirname "${LAN_LISTEN}")"
|
||||
|
||||
cp ${LAN_NAME}.sans ${LAN_NAME}.conf
|
||||
cp "${LAN_NAME}.sans" "${LAN_NAME}.conf"
|
||||
|
||||
test '${NGINX_UTIL} init_lan' 0
|
||||
test '"${NGINX_UTIL}" init_lan' 0
|
||||
|
||||
|
||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nSetup files in ${CONF_DIR} ...\n"
|
||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nSetup files in %s ...\n" "${CONF_DIR}"
|
||||
|
||||
for conf in ${CONFS}
|
||||
do test 'setpoint_add_ssl " " '${conf%:*} ${conf#*:}
|
||||
do test 'setpoint_add_ssl " " '"${conf%:*}" "${conf#*:}"
|
||||
done
|
||||
|
||||
test 'setpoint_add_ssl "\t" tab' 0 # fixes wrong indentation.
|
||||
|
||||
|
||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting ${NGINX_UTIL} add_ssl ...\n"
|
||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting %s add_ssl ...\n" "${NGINX_UTIL}"
|
||||
|
||||
cp different_name.sans different_name.with
|
||||
|
||||
test '[ "${ADD_SSL_FCT}" == "add_ssl" ] ' 0
|
||||
test '[ "${ADD_SSL_FCT}" = "add_ssl" ] ' 0
|
||||
|
||||
for conf in ${CONFS}; do
|
||||
name=${conf%:*}
|
||||
cp ${name}.sans ${name}.conf
|
||||
test '${NGINX_UTIL} add_ssl '${name} ${conf#*:}
|
||||
(test '[ "$(cat '${name}'.conf)" == "$(cat '${name}'.with)" ]' 0 >/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
|
||||
|
||||
|
|
|
@ -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}"
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
148
net/nginx-util/src/ubus-cxx.cpp
Normal file
148
net/nginx-util/src/ubus-cxx.cpp
Normal file
|
@ -0,0 +1,148 @@
|
|||
#include <iostream>
|
||||
|
||||
#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) "<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void example_for_getting_values()
|
||||
{
|
||||
auto lan_status = ubus::call("network.interface.lan", "status");
|
||||
for (auto t : lan_status.filter("ipv6-address", "", "address")) {
|
||||
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||
auto x = const_cast<blob_attr *>(t);
|
||||
std::cout<<"["<<blobmsg_get_string(x)<<"] ";
|
||||
}
|
||||
for (auto t : lan_status.filter("ipv4-address", "").filter("address")) {
|
||||
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||
auto x = const_cast<blob_attr *>(t);
|
||||
std::cout<<blobmsg_get_string(x)<<" ";
|
||||
}
|
||||
std::cout<<std::endl;
|
||||
}
|
||||
|
||||
|
||||
inline void example_for_sending_message()
|
||||
{
|
||||
auto set_arg = [](blob_buf * buf) -> 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<blob_attr *>(t);
|
||||
std::cout<<blobmsg_get_string(x)<<"\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void example_for_exploring()
|
||||
{
|
||||
ubus::strings keys{"ipv4-address", "", ""};
|
||||
for (auto t : ubus::call("network.interface.lan", "status").filter(keys)) {
|
||||
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||
auto x = const_cast<blob_attr *>(t);
|
||||
std::cout<<blobmsg_name(x)<<": ";
|
||||
switch (blob_id(x)) {
|
||||
case BLOBMSG_TYPE_UNSPEC: std::cout<<"[unspecified]"; break;
|
||||
case BLOBMSG_TYPE_ARRAY: std::cout<<"[array]"; break;
|
||||
case BLOBMSG_TYPE_TABLE: std::cout<<"[table]"; break;
|
||||
case BLOBMSG_TYPE_STRING: std::cout<<blobmsg_get_string(x); break;
|
||||
case BLOBMSG_TYPE_INT64: std::cout<<blobmsg_get_u64(x); break;
|
||||
case BLOBMSG_TYPE_INT32: std::cout<<blobmsg_get_u32(x); break;
|
||||
case BLOBMSG_TYPE_INT16: std::cout<<blobmsg_get_u16(x); break;
|
||||
case BLOBMSG_TYPE_BOOL: std::cout<<blobmsg_get_bool(x); break;
|
||||
case BLOBMSG_TYPE_DOUBLE: std::cout<<blobmsg_get_double(x); break;
|
||||
default: std::cout<<"[unknown]";
|
||||
}
|
||||
std::cout<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void example_for_recursive_exploring()
|
||||
{ // output like from the original ubus call:
|
||||
const auto explore = [](auto message) -> void
|
||||
{
|
||||
auto end = message.end();
|
||||
auto explore_internal =
|
||||
[&end](auto & explore_ref, auto it, size_t depth=1) -> void
|
||||
{
|
||||
std::cout<<std::endl;
|
||||
bool first = true;
|
||||
for (; it!=end; ++it) {
|
||||
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||
auto attr = const_cast<blob_attr *>(*it);
|
||||
if (first) { first = false; }
|
||||
else { std::cout<<",\n"; }
|
||||
std::cout<<std::string(depth, '\t');
|
||||
std::string name = blobmsg_name(attr);
|
||||
if (!name.empty()) { std::cout<<"\""<<name<<"\": "; }
|
||||
switch (blob_id(attr)) {
|
||||
case BLOBMSG_TYPE_UNSPEC: std::cout<<"(unspecified)"; break;
|
||||
case BLOBMSG_TYPE_ARRAY:
|
||||
std::cout<<"[";
|
||||
explore_ref(explore_ref, ubus::iterator{attr}, depth+1);
|
||||
std::cout<<"\n"<<std::string(depth, '\t')<<"]";
|
||||
break;
|
||||
case BLOBMSG_TYPE_TABLE:
|
||||
std::cout<<"{";
|
||||
explore_ref(explore_ref, ubus::iterator{attr}, depth+1);
|
||||
std::cout<<"\n"<<std::string(depth, '\t')<<"}";
|
||||
break;
|
||||
case BLOBMSG_TYPE_STRING:
|
||||
std::cout<<"\""<<blobmsg_get_string(attr)<<"\"";
|
||||
break;
|
||||
case BLOBMSG_TYPE_INT64:
|
||||
std::cout<<blobmsg_get_u64(attr);
|
||||
break;
|
||||
case BLOBMSG_TYPE_INT32:
|
||||
std::cout<<blobmsg_get_u32(attr);
|
||||
break;
|
||||
case BLOBMSG_TYPE_INT16:
|
||||
std::cout<<blobmsg_get_u16(attr);
|
||||
break;
|
||||
case BLOBMSG_TYPE_BOOL:
|
||||
std::cout<<(blobmsg_get_bool(attr) ? "true" : "false");
|
||||
break;
|
||||
case BLOBMSG_TYPE_DOUBLE:
|
||||
std::cout<<blobmsg_get_double(attr);
|
||||
break;
|
||||
default: std::cout<<"(unknown)"; break;
|
||||
}
|
||||
}
|
||||
};
|
||||
std::cout<<"{";
|
||||
explore_internal(explore_internal, message.begin());
|
||||
std::cout<<"\n}"<<std::endl;
|
||||
};
|
||||
explore(ubus::call("network.interface.lan", "status"));
|
||||
}
|
||||
|
||||
|
||||
auto main() -> 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<<e.what()<<std::endl; }
|
||||
|
||||
catch (...) { perror("main error"); }
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -1,114 +1,23 @@
|
|||
#ifndef _UBUS_CXX_HPP
|
||||
#define _UBUS_CXX_HPP
|
||||
|
||||
extern "C" { //TODO(pst): remove when in upstream
|
||||
#include <libubus.h>
|
||||
}
|
||||
#include <cassert>
|
||||
#include <libubus.h>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include <iostream>
|
||||
#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) "<<std::endl;
|
||||
// }
|
||||
|
||||
// // example for getting values:
|
||||
// auto lan_status = ubus::call("network.interface.lan", "status");
|
||||
// for (auto x : lan_status.filter("ipv6-address", "", "address")) {
|
||||
// std::cout<<"["<<blobmsg_get_string(x)<<"] ";
|
||||
// }
|
||||
// for (auto x : lan_status.filter("ipv4-address", "").filter("address")) {
|
||||
// std::cout<<blobmsg_get_string(x)<<" ";
|
||||
// }
|
||||
// std::cout<<std::endl;
|
||||
|
||||
// // example for exploring:
|
||||
// ubus::strings keys{"ipv4-address", "", ""};
|
||||
// for (auto x : ubus::call("network.interface.lan", "status").filter(keys)) {
|
||||
// std::cout<<blobmsg_name(x)<<": ";
|
||||
// switch (blob_id(x)) {
|
||||
// case BLOBMSG_TYPE_UNSPEC: std::cout<<"[unspecified]"; break;
|
||||
// case BLOBMSG_TYPE_ARRAY: std::cout<<"[array]"; break;
|
||||
// case BLOBMSG_TYPE_TABLE: std::cout<<"[table]"; break;
|
||||
// case BLOBMSG_TYPE_STRING: std::cout<<blobmsg_get_string(x); break;
|
||||
// case BLOBMSG_TYPE_INT64: std::cout<<blobmsg_get_u64(x); break;
|
||||
// case BLOBMSG_TYPE_INT32: std::cout<<blobmsg_get_u32(x); break;
|
||||
// case BLOBMSG_TYPE_INT16: std::cout<<blobmsg_get_u16(x); break;
|
||||
// case BLOBMSG_TYPE_BOOL: std::cout<<blobmsg_get_bool(x); break;
|
||||
// case BLOBMSG_TYPE_DOUBLE: std::cout<<blobmsg_get_double(x); break;
|
||||
// default: std::cout<<"[unknown]";
|
||||
// }
|
||||
// std::cout<<std::endl;
|
||||
// }
|
||||
|
||||
// // example for recursive exploring (output like from the original ubus call)
|
||||
// const auto explore = [](auto message) -> void
|
||||
// {
|
||||
// auto end = message.end();
|
||||
// auto explore_internal =
|
||||
// [&end](auto & explore_ref, auto it, size_t depth=1) -> void
|
||||
// {
|
||||
// std::cout<<std::endl;
|
||||
// bool first = true;
|
||||
// for (; it!=end; ++it) {
|
||||
// auto * attr = *it;
|
||||
// if (first) { first = false; }
|
||||
// else { std::cout<<",\n"; }
|
||||
// std::cout<<std::string(depth, '\t');
|
||||
// std::string name = blobmsg_name(attr);
|
||||
// if (name != "") { std::cout<<"\""<<name<<"\": "; }
|
||||
// switch (blob_id(attr)) {
|
||||
// case BLOBMSG_TYPE_UNSPEC: std::cout<<"(unspecified)"; break;
|
||||
// case BLOBMSG_TYPE_ARRAY:
|
||||
// std::cout<<"[";
|
||||
// explore_ref(explore_ref, ubus::iterator{attr}, depth+1);
|
||||
// std::cout<<"\n"<<std::string(depth, '\t')<<"]";
|
||||
// break;
|
||||
// case BLOBMSG_TYPE_TABLE:
|
||||
// std::cout<<"{";
|
||||
// explore_ref(explore_ref, ubus::iterator{attr}, depth+1);
|
||||
// std::cout<<"\n"<<std::string(depth, '\t')<<"}";
|
||||
// break;
|
||||
// case BLOBMSG_TYPE_STRING:
|
||||
// std::cout<<"\""<<blobmsg_get_string(attr)<<"\"";
|
||||
// break;
|
||||
// case BLOBMSG_TYPE_INT64:
|
||||
// std::cout<<blobmsg_get_u64(attr);
|
||||
// break;
|
||||
// case BLOBMSG_TYPE_INT32:
|
||||
// std::cout<<blobmsg_get_u32(attr);
|
||||
// break;
|
||||
// case BLOBMSG_TYPE_INT16:
|
||||
// std::cout<<blobmsg_get_u16(attr);
|
||||
// break;
|
||||
// case BLOBMSG_TYPE_BOOL:
|
||||
// std::cout<<(blobmsg_get_bool(attr) ? "true" : "false");
|
||||
// break;
|
||||
// case BLOBMSG_TYPE_DOUBLE:
|
||||
// std::cout<<blobmsg_get_double(attr);
|
||||
// break;
|
||||
// default: std::cout<<"(unknown)"; break;
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// std::cout<<"{";
|
||||
// explore_internal(explore_internal, message.begin());
|
||||
// std::cout<<"\n}"<<std::endl;
|
||||
// };
|
||||
// explore(ubus::call("network.interface.lan", "status"));
|
||||
|
||||
|
||||
|
||||
namespace ubus {
|
||||
|
||||
static constexpr int call_timeout = 500;
|
||||
|
||||
using msg_ptr = std::shared_ptr<const blob_attr>;
|
||||
|
||||
using strings = std::vector<std::string>;
|
||||
|
@ -130,7 +39,7 @@ inline auto concat(strings dest, strings src, Strings ...more)
|
|||
template<class S, class ...Strings>
|
||||
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<void>(cur.release()); } }
|
||||
inline ~iterator()
|
||||
{ if (cur.get()==this) { static_cast<void>(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<ubus_context, decltype(ubus_freeing)>
|
||||
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<blob_buf, decltype(blob_buf_freeing)>
|
||||
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 ~ubus() = delete;
|
||||
inline ~lock_shared_resources() { inuse.unlock(); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
auto call(const char * path, const char * method="", int timeout=500);
|
||||
template<class F>
|
||||
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); }
|
||||
|
||||
|
||||
|
||||
|
||||
// ------------------------- 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<iterator>{new iterator(tmp)};
|
||||
|
||||
struct new_iterator : public iterator // use private constructor:
|
||||
{ explicit new_iterator(iterator * par) : iterator{par} {} };
|
||||
cur = std::make_unique<new_iterator>(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<class F>
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue