From 96e9feb6b2e6e94238716982bc78f20f43b14377 Mon Sep 17 00:00:00 2001 From: ArnoStiefvater Date: Mon, 28 Jun 2021 16:07:22 +0200 Subject: [PATCH 01/23] Add MQTT support This is reintroduction after rebase. For details see Base: https://github.com/greenbone/gvm-libs/pull/505/commits Fix: https://github.com/greenbone/gvm-libs/pull/511/commits --- CHANGELOG.md | 7 ++ INSTALL.md | 2 + util/CMakeLists.txt | 17 ++++- util/mqtt.c | 178 ++++++++++++++++++++++++++++++++++++++++++++ util/mqtt.h | 43 +++++++++++ 5 files changed, 244 insertions(+), 3 deletions(-) create mode 100644 util/mqtt.c create mode 100644 util/mqtt.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fe650af5..bdafd8290 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Possibility to use lcrypt with `$6$` (sha512) for authentication [484](https://github.com/greenbone/gvm-libs/pull/484) - Add function to perform an alive test and get the amount of alive hosts. [495](https://github.com/greenbone/gvm-libs/pull/495) - Add functions for sentry integration. [#502](https://github.com/greenbone/gvm-libs/pull/502) [#506](https://github.com/greenbone/gvm-libs/pull/506) +- Add basic support for mqtt. + Original + [#505](https://github.com/greenbone/gvm-libs/pull/505) + [#511](https://github.com/greenbone/gvm-libs/pull/511). + Reintroduction after Rebase + [#538](https://github.com/greenbone/gvm-libs/pull/538) + ### Changed ### Fixed diff --git a/INSTALL.md b/INSTALL.md index 9d0db60e4..57753e400 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -71,6 +71,8 @@ Install prerequisites for optional features on Debian GNU/Linux 'Buster' 10: libldap2-dev \ libradcli-dev +Prerequisites for MQTT support: +* libpaho-mqtt-dev >= 1.3.8. This package is currently not available in debian buster stable. Could be installed from source, backports or unstable branch. Compiling gvm-libs ------------------ diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index d4b9d6ee4..3c460d93e 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -50,6 +50,17 @@ pkg_check_modules (REDIS REQUIRED hiredis>=0.10.1) # for fast XML we need libxml2 pkg_check_modules (LIBXML2 REQUIRED libxml-2.0>=2.0) +# for mqtt +# Optional for now because lib is currently not in debian buster stable. +find_library(LIBPAHO paho-mqtt3c) +message (STATUS "Looking for paho-mqtt3c ... ${LIBPAHO}") +if (NOT LIBPAHO) + message (STATUS "libpaho-mqtt3c is required for MQTTv5 support.") +else (LIBPAHO) + set (LIBPAHO_LDFLAGS "paho-mqtt3c") + add_definitions (-DHAVE_MQTT=1) +endif (NOT LIBPAHO) + #for gpgmeutils we need libgpgme set (GPGME_MIN_VERSION "1.7.0") message (STATUS "Looking for gpgme...") @@ -156,11 +167,11 @@ include_directories (${GLIB_INCLUDE_DIRS} ${GPGME_INCLUDE_DIRS} ${GCRYPT_INCLUDE ${LIBXML2_INCLUDE_DIRS}) set (FILES passwordbasedauthentication.c compressutils.c fileutils.c gpgmeutils.c kb.c ldaputils.c - nvticache.c radiusutils.c serverutils.c sshutils.c uuidutils.c + nvticache.c mqtt.c radiusutils.c serverutils.c sshutils.c uuidutils.c xmlutils.c) set (HEADERS passwordbasedauthentication.h authutils.h compressutils.h fileutils.h gpgmeutils.h kb.h - ldaputils.h nvticache.h radiusutils.h serverutils.h sshutils.h + ldaputils.h nvticache.h mqtt.h radiusutils.h serverutils.h sshutils.h uuidutils.h xmlutils.h) if (BUILD_STATIC) @@ -178,7 +189,7 @@ if (BUILD_SHARED) set_target_properties (gvm_util_shared PROPERTIES VERSION "${CPACK_PACKAGE_VERSION}") set_target_properties (gvm_util_shared PROPERTIES PUBLIC_HEADER "${HEADERS}") - target_link_libraries (gvm_util_shared LINK_PRIVATE ${GLIB_LDFLAGS} + target_link_libraries (gvm_util_shared LINK_PRIVATE ${LIBPAHO_LDFLAGS} ${GLIB_LDFLAGS} ${GIO_LDFLAGS} ${GPGME_LDFLAGS} ${ZLIB_LDFLAGS} ${RADIUS_LDFLAGS} ${LIBSSH_LDFLAGS} ${GNUTLS_LDFLAGS} ${GCRYPT_LDFLAGS} ${LDAP_LDFLAGS} ${REDIS_LDFLAGS} diff --git a/util/mqtt.c b/util/mqtt.c new file mode 100644 index 000000000..fb4ffe9d7 --- /dev/null +++ b/util/mqtt.c @@ -0,0 +1,178 @@ +/* Copyright (C) 2021 Greenbone Networks GmbH + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "mqtt.h" + +#include "uuidutils.h" /* gvm_uuid_make */ + +#include + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "lib mqtt" + +#define QOS 1 +#define TIMEOUT 10000L + +/** + * @brief Check for MQTT support + * + * @return 1 if gvm-libs has been built with mqtt, 0 otherwise. + */ +int +gvm_has_mqtt_support () +{ +#ifdef HAVE_MQTT + return 1; +#endif /* HAVE_MQTT */ + return 0; +} + +#ifdef HAVE_MQTT +/** + * Create a new mqtt client. + * + * @param server_uri URI of server. + * @param id Client id. + * + * @return mqtt client + */ +static MQTTClient +mqtt_create (const char *server_uri, char *id) +{ + MQTTClient client; + MQTTClient_createOptions create_opts = MQTTClient_createOptions_initializer; + create_opts.MQTTVersion = MQTTVERSION_5; + + int rc = MQTTClient_createWithOptions ( + &client, server_uri, id, MQTTCLIENT_PERSISTENCE_NONE, NULL, &create_opts); + + if (rc != MQTTCLIENT_SUCCESS) + { + MQTTClient_destroy (&client); + return NULL; + } + return client; +} +#endif /* HAVE_MQTT */ + +/** + * @brief connect to a mqtt broker. + * + * @param server_uri Address of the broker. + * + * @return Mqtt handle, NULL on error. + */ +mqtt_t * +mqtt_connect (const char *server_uri) +{ +#ifdef HAVE_MQTT + char *uuid; + int rc; + MQTTClient client; + mqtt_t *mqtt = NULL; + MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer5; + MQTTProperties connect_properties = MQTTProperties_initializer; + MQTTResponse resp; + + uuid = gvm_uuid_make (); + client = mqtt_create (server_uri, uuid); + if (!client) + return NULL; + + conn_opts.keepAliveInterval = 0; + conn_opts.cleanstart = 1; + conn_opts.MQTTVersion = MQTTVERSION_5; + + resp = MQTTClient_connect5 (client, &conn_opts, &connect_properties, NULL); + rc = resp.reasonCode; + MQTTProperties_free (&connect_properties); + if (rc != MQTTCLIENT_SUCCESS) + { + g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, + "%s: mqtt connection error to %s: %s", __func__, server_uri, + MQTTClient_strerror (rc)); + MQTTResponse_free (resp); + return NULL; + } + + mqtt = g_malloc0 (sizeof (mqtt)); + mqtt->client = client; + mqtt->addr = g_strdup (server_uri); + mqtt->client_id = uuid; + + return mqtt; +#else + (void) server_uri; + return NULL; +#endif /* HAVE_MQTT */ +} + +/** + * @brief Publish message on topic. + * + * @param mqtt MQTT handle. + * @param topic Topic to publish on. + * @param msg Message to publish on queue. + * + * @return 0 on success, negative errorcode on failure. + */ +int +mqtt_publish (mqtt_t *mqtt, const char *topic, const char *msg) +{ +#ifdef HAVE_MQTT + MQTTClient client; + MQTTClient_message pubmsg = MQTTClient_message_initializer; + MQTTClient_deliveryToken token; + MQTTResponse resp; + int rc; + + client = mqtt->client; + if (!client) + return -1; + + pubmsg.payload = (char *) msg; + pubmsg.payloadlen = (int) strlen (msg); + pubmsg.qos = QOS; + pubmsg.retained = 0; + + resp = MQTTClient_publishMessage5 (client, topic, &pubmsg, &token); + rc = resp.reasonCode; + if (rc != MQTTCLIENT_SUCCESS) + { + g_warning ("Failed to connect: %s", MQTTClient_strerror (rc)); + MQTTResponse_free (resp); + return -1; + } + + if ((rc = MQTTClient_waitForCompletion (client, token, TIMEOUT)) + != MQTTCLIENT_SUCCESS) + { + g_debug ("Message '%s' with delivery token %d could not be " + "published on topic %s", + msg, token, topic); + } + + return rc; +#else + (void) mqtt; + (void) topic; + (void) msg; + return -1; +#endif /* HAVE_MQTT */ +} diff --git a/util/mqtt.h b/util/mqtt.h new file mode 100644 index 000000000..dba28fa60 --- /dev/null +++ b/util/mqtt.h @@ -0,0 +1,43 @@ +/* Copyright (C) 2021 Greenbone Networks GmbH + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _GVM_MQTT_H +#define _GVM_MQTT_H + +#ifdef HAVE_MQTT +#include +#endif /* HAVE_MQTT*/ + +typedef struct +{ + void *client; + char *client_id; + char *addr; +} mqtt_t; + +int +gvm_has_mqtt_support (void); + +mqtt_t * +mqtt_connect (const char *); + +int +mqtt_publish (mqtt_t *, const char *, const char *); + +#endif /* _GVM_MQTT_H */ From 111c04b091471e3b40e290bf36cb173a514f8921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaspar=20L=C3=B6chte?= Date: Mon, 28 Jun 2021 21:32:39 +0200 Subject: [PATCH 02/23] Add docker file for gvm-libs-master-debian-buster-gcc-test --- .docker/test/gcc/Dockerfile | 50 +++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .docker/test/gcc/Dockerfile diff --git a/.docker/test/gcc/Dockerfile b/.docker/test/gcc/Dockerfile new file mode 100644 index 000000000..efe8c8895 --- /dev/null +++ b/.docker/test/gcc/Dockerfile @@ -0,0 +1,50 @@ +# gvm-libs-master-debian-buster-gcc-test + +# please follow docker best practices +# https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ + +# Use '-slim' image for reduced image size +FROM debian:buster-slim + +# Provides a Debian buster image with the core build dependencies for gvm-libs +LABEL module="gvm-libs" +LABEL branch="master" +LABEL platform="debian-buster" +LABEL compiler="gcc" +LABEL configuration="test" + +# This will make apt-get install without question +ARG DEBIAN_FRONTEND=noninteractive + +# Install core dependencies required for building gvm-libs +RUN apt-get update && apt-get install --no-install-recommends --assume-yes \ + ca-certificates \ + cmake \ + gcc \ + git \ + libglib2.0-dev \ + libgnutls28-dev \ + libgpgme-dev \ + libhiredis-dev \ + libpcap-dev \ + libssh-gcrypt-dev \ + libxml2-dev \ + libnet1-dev \ + make \ + pkg-config \ + uuid-dev \ + libssl-dev \ + && rm -rf /var/lib/apt/lists/* + +# clone and install mqtt paho +# workaround otherwise paho.mqtt.c creates man1 as a file +RUN mkdir /usr/local/share/man/man1 + +RUN git clone --depth 1 https://github.com/eclipse/paho.mqtt.c \ + && cd paho.mqtt.c \ + && make \ + && make install \ + && cd .. \ + && rm -rf paho.mqtt.c + +ENV LD_LIBRARY_PATH="/usr/local/lib" From 89e45a457360fac1d6ac8202828a498f80914b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaspar=20L=C3=B6chte?= Date: Mon, 28 Jun 2021 22:35:17 +0200 Subject: [PATCH 03/23] Add more dockerfiles --- .docker/deploy/clang/Dockerfile | 60 +++++++++++++++++++++++++++ .docker/deploy/gcc/Dockerfile | 60 +++++++++++++++++++++++++++ .docker/test/clang/Dockerfile | 72 +++++++++++++++++++++++++++++++++ .docker/test/gcc/Dockerfile | 21 ++++++++++ 4 files changed, 213 insertions(+) create mode 100644 .docker/deploy/clang/Dockerfile create mode 100644 .docker/deploy/gcc/Dockerfile create mode 100644 .docker/test/clang/Dockerfile diff --git a/.docker/deploy/clang/Dockerfile b/.docker/deploy/clang/Dockerfile new file mode 100644 index 000000000..c7c1045d6 --- /dev/null +++ b/.docker/deploy/clang/Dockerfile @@ -0,0 +1,60 @@ +# gvm-libs-master-debian-buster-gcc-test + +# please follow docker best practices +# https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ + +# Use '-slim' image for reduced image size +FROM debian:buster-slim + +# Provides a Debian buster image with the core build dependencies for gvm-libs +LABEL module="gvm-libs" +LABEL branch="master" +LABEL platform="debian-buster" +LABEL compiler="clang" +LABEL configuration="deploy" + +# This will make apt-get install without question +ARG DEBIAN_FRONTEND=noninteractive + +# Install core dependencies required for building gvm-libs +RUN apt-get update && apt-get install --assume-yes \ + clang \ + clang-format \ + clang-tools \ + cmake \ + git \ + libglib2.0-dev \ + libgnutls28-dev \ + libgpgme-dev \ + libhiredis-dev \ + libpcap-dev \ + libnet1-dev \ + libssh-gcrypt-dev \ + libxml2-dev \ + pkg-config \ + uuid-dev \ + libssl-dev \ + && rm -rf /var/lib/apt/lists/* + +# clone and install mqtt paho +# workaround otherwise paho.mqtt.c creates man1 as a file +RUN mkdir /usr/local/share/man/man1 + +RUN git clone --depth 1 https://github.com/eclipse/paho.mqtt.c \ + && cd paho.mqtt.c \ + && make \ + && make install \ + && cd .. \ + && rm -rf paho.mqtt.c + +ENV LD_LIBRARY_PATH="/usr/local/lib" + +# clone and install gvm-libs +RUN git clone --depth 1 \ + https://github.com/greenbone/gvm-libs.git \ + -b master && \ + cd gvm-libs && \ + mkdir build && \ + cd build && \ + cmake -DCMAKE_BUILD_TYPE=Release .. && \ + make install diff --git a/.docker/deploy/gcc/Dockerfile b/.docker/deploy/gcc/Dockerfile new file mode 100644 index 000000000..d661e78ba --- /dev/null +++ b/.docker/deploy/gcc/Dockerfile @@ -0,0 +1,60 @@ +# gvm-libs-master-debian-buster-gcc-deploy + +# please follow docker best practices +# https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ + +# Use '-slim' image for reduced image size +FROM debian:buster-slim + +# Provides a Debian buster image with the core build dependencies for gvm-libs +LABEL module="gvm-libs" +LABEL branch="master" +LABEL platform="debian-buster" +LABEL compiler="gcc" +LABEL configuration="deploy" + +# This will make apt-get install without question +ARG DEBIAN_FRONTEND=noninteractive + +# Install core dependencies required for building gvm-libs +RUN apt-get update && apt-get install --no-install-recommends --assume-yes \ + ca-certificates \ + cmake \ + gcc \ + git \ + libglib2.0-dev \ + libgnutls28-dev \ + libgpgme-dev \ + libhiredis-dev \ + libpcap-dev \ + libssh-gcrypt-dev \ + libxml2-dev \ + libnet1-dev \ + make \ + pkg-config \ + uuid-dev \ + libssl-dev \ + && rm -rf /var/lib/apt/lists/* + +# clone and install mqtt paho +# workaround otherwise paho.mqtt.c creates man1 as a file +RUN mkdir /usr/local/share/man/man1 + +RUN git clone --depth 1 https://github.com/eclipse/paho.mqtt.c \ + && cd paho.mqtt.c \ + && make \ + && make install \ + && cd .. \ + && rm -rf paho.mqtt.c + +ENV LD_LIBRARY_PATH="/usr/local/lib" + +# clone and install gvm-libs +RUN git clone --depth 1 \ + https://github.com/greenbone/gvm-libs.git \ + -b master && \ + cd gvm-libs && \ + mkdir build && \ + cd build && \ + cmake -DCMAKE_BUILD_TYPE=Release .. && \ + make install diff --git a/.docker/test/clang/Dockerfile b/.docker/test/clang/Dockerfile new file mode 100644 index 000000000..24d015ef3 --- /dev/null +++ b/.docker/test/clang/Dockerfile @@ -0,0 +1,72 @@ +# gvm-libs-master-debian-buster-gcc-test + +# please follow docker best practices +# https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ + +# Use '-slim' image for reduced image size +FROM debian:buster-slim + +# Provides a Debian buster image with the core build dependencies for gvm-libs +LABEL module="gvm-libs" +LABEL branch="master" +LABEL platform="debian-buster" +LABEL compiler="clang" +LABEL configuration="test" + +# This will make apt-get install without question +ARG DEBIAN_FRONTEND=noninteractive + +# Install core dependencies required for building gvm-libs +RUN apt-get update && apt-get install --assume-yes \ + clang \ + clang-format \ + clang-tools \ + cmake \ + git \ + libglib2.0-dev \ + libgnutls28-dev \ + libgpgme-dev \ + libhiredis-dev \ + libpcap-dev \ + libnet1-dev \ + libssh-gcrypt-dev \ + libxml2-dev \ + pkg-config \ + uuid-dev \ + libssl-dev \ + && rm -rf /var/lib/apt/lists/* + +# clone and install mqtt paho +# workaround otherwise paho.mqtt.c creates man1 as a file +RUN mkdir /usr/local/share/man/man1 + +RUN git clone --depth 1 https://github.com/eclipse/paho.mqtt.c \ + && cd paho.mqtt.c \ + && make \ + && make install \ + && cd .. \ + && rm -rf paho.mqtt.c + +ENV LD_LIBRARY_PATH="/usr/local/lib" + +# Install Debian core dependencies required for testing gvm-libs +# support and not yet installed as dependencies of gvm-libs-core +RUN apt-get update && apt-get install --assume-yes \ + lcov \ + libical-dev \ + libpq-dev \ + libnet1-dev \ + postgresql-server-dev-all \ + xsltproc \ + && rm -rf /var/lib/apt/lists/* + +# install cgreen for unit tests +RUN git clone --depth 1 https://github.com/cgreen-devs/cgreen.git \ + && cd cgreen \ + && make \ + && make test \ + && make install \ + && cd .. \ + && rm -rf cgreen + +ENV LD_LIBRARY_PATH="/usr/local/lib" diff --git a/.docker/test/gcc/Dockerfile b/.docker/test/gcc/Dockerfile index efe8c8895..374a6e6b1 100644 --- a/.docker/test/gcc/Dockerfile +++ b/.docker/test/gcc/Dockerfile @@ -47,4 +47,25 @@ RUN git clone --depth 1 https://github.com/eclipse/paho.mqtt.c \ && cd .. \ && rm -rf paho.mqtt.c +# Install Debian core dependencies required for testing gvm-libs +# support and not yet installed as dependencies of gvm-libs-core +RUN apt-get update && apt-get install --assume-yes \ + g++ \ + lcov \ + libical-dev \ + libpq-dev \ + libnet1-dev \ + postgresql-server-dev-all \ + xsltproc \ + && rm -rf /var/lib/apt/lists/* + +# install cgreen for unit tests +RUN git clone --depth 1 https://github.com/cgreen-devs/cgreen.git \ + && cd cgreen \ + && make \ + && make test \ + && make install \ + && cd .. \ + && rm -rf cgreen + ENV LD_LIBRARY_PATH="/usr/local/lib" From 974e4697c8b74a5e3cd11171d9b4e65aec924aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaspar=20L=C3=B6chte?= Date: Wed, 30 Jun 2021 11:06:45 +0200 Subject: [PATCH 04/23] Add dockerfiles for middleware branch --- .docker/deploy/clang/Dockerfile | 6 +++--- .docker/deploy/gcc/Dockerfile | 6 +++--- .docker/test/clang/Dockerfile | 4 ++-- .docker/test/gcc/Dockerfile | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.docker/deploy/clang/Dockerfile b/.docker/deploy/clang/Dockerfile index c7c1045d6..7436a5649 100644 --- a/.docker/deploy/clang/Dockerfile +++ b/.docker/deploy/clang/Dockerfile @@ -1,4 +1,4 @@ -# gvm-libs-master-debian-buster-gcc-test +# gvm-libs-middleware-debian-buster-gcc-test # please follow docker best practices # https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ @@ -8,7 +8,7 @@ FROM debian:buster-slim # Provides a Debian buster image with the core build dependencies for gvm-libs LABEL module="gvm-libs" -LABEL branch="master" +LABEL branch="middleware" LABEL platform="debian-buster" LABEL compiler="clang" LABEL configuration="deploy" @@ -52,7 +52,7 @@ ENV LD_LIBRARY_PATH="/usr/local/lib" # clone and install gvm-libs RUN git clone --depth 1 \ https://github.com/greenbone/gvm-libs.git \ - -b master && \ + -b middleware && \ cd gvm-libs && \ mkdir build && \ cd build && \ diff --git a/.docker/deploy/gcc/Dockerfile b/.docker/deploy/gcc/Dockerfile index d661e78ba..ff994ca3d 100644 --- a/.docker/deploy/gcc/Dockerfile +++ b/.docker/deploy/gcc/Dockerfile @@ -1,4 +1,4 @@ -# gvm-libs-master-debian-buster-gcc-deploy +# gvm-libs-middleware-debian-buster-gcc-deploy # please follow docker best practices # https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ @@ -8,7 +8,7 @@ FROM debian:buster-slim # Provides a Debian buster image with the core build dependencies for gvm-libs LABEL module="gvm-libs" -LABEL branch="master" +LABEL branch="middleware" LABEL platform="debian-buster" LABEL compiler="gcc" LABEL configuration="deploy" @@ -52,7 +52,7 @@ ENV LD_LIBRARY_PATH="/usr/local/lib" # clone and install gvm-libs RUN git clone --depth 1 \ https://github.com/greenbone/gvm-libs.git \ - -b master && \ + -b middleware && \ cd gvm-libs && \ mkdir build && \ cd build && \ diff --git a/.docker/test/clang/Dockerfile b/.docker/test/clang/Dockerfile index 24d015ef3..faa175c0d 100644 --- a/.docker/test/clang/Dockerfile +++ b/.docker/test/clang/Dockerfile @@ -1,4 +1,4 @@ -# gvm-libs-master-debian-buster-gcc-test +# gvm-libs-middleware-debian-buster-gcc-test # please follow docker best practices # https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ @@ -8,7 +8,7 @@ FROM debian:buster-slim # Provides a Debian buster image with the core build dependencies for gvm-libs LABEL module="gvm-libs" -LABEL branch="master" +LABEL branch="middleware" LABEL platform="debian-buster" LABEL compiler="clang" LABEL configuration="test" diff --git a/.docker/test/gcc/Dockerfile b/.docker/test/gcc/Dockerfile index 374a6e6b1..f3c39d764 100644 --- a/.docker/test/gcc/Dockerfile +++ b/.docker/test/gcc/Dockerfile @@ -1,4 +1,4 @@ -# gvm-libs-master-debian-buster-gcc-test +# gvm-libs-middleware-debian-buster-gcc-test # please follow docker best practices # https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ @@ -8,7 +8,7 @@ FROM debian:buster-slim # Provides a Debian buster image with the core build dependencies for gvm-libs LABEL module="gvm-libs" -LABEL branch="master" +LABEL branch="middleware" LABEL platform="debian-buster" LABEL compiler="gcc" LABEL configuration="test" From 93392e4125ad2501287d65e22e3cf8a75547d2e3 Mon Sep 17 00:00:00 2001 From: ArnoStiefvater Date: Tue, 6 Jul 2021 13:12:36 +0200 Subject: [PATCH 05/23] Refactor MQTT handling Remove feature guards. Add function for single message publish. Getters and setters. Reset function. Init mqtt_t on publish if mqtt_t is NULL. --- util/mqtt.c | 299 +++++++++++++++++++++++++++++++++++++++++++--------- util/mqtt.h | 12 +-- 2 files changed, 257 insertions(+), 54 deletions(-) diff --git a/util/mqtt.c b/util/mqtt.c index fb4ffe9d7..376d41ef0 100644 --- a/util/mqtt.c +++ b/util/mqtt.c @@ -19,10 +19,10 @@ #include "mqtt.h" +/** TODO: Remove dependency ../base/prefs.h **/ +#include "../base/prefs.h" #include "uuidutils.h" /* gvm_uuid_make */ -#include - #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "lib mqtt" @@ -30,37 +30,108 @@ #define TIMEOUT 10000L /** - * @brief Check for MQTT support + * @brief Get server uri as specified in the openvas conf file. * - * @return 1 if gvm-libs has been built with mqtt, 0 otherwise. + * @return Server URI, NULL if not found. */ -int -gvm_has_mqtt_support () +static const char * +mqtt_get_server_uri () +{ + return prefs_get ("mqtt_server_uri"); +} + +/** + * @brief Disconnect from the Broker. + * + * @param mqtt mqtt_t + * + * @return 0 on success, -1 on error. + */ +static int +mqtt_disconnect (mqtt_t *mqtt) { -#ifdef HAVE_MQTT - return 1; -#endif /* HAVE_MQTT */ + int rc; + + rc = MQTTClient_disconnect5 (mqtt->client, 200, + MQTTREASONCODE_NORMAL_DISCONNECTION, NULL); + if (rc != MQTTCLIENT_SUCCESS) + { + g_warning ("Failed to disconnect: %s", MQTTClient_strerror (rc)); + return -1; + } + return 0; } -#ifdef HAVE_MQTT /** - * Create a new mqtt client. + * @brief Destroy the mqtt client inside mqtt_t struct * - * @param server_uri URI of server. - * @param id Client id. + * @param[in] mqtt mqtt_t handle. * - * @return mqtt client + */ +static void +mqtt_client_destroy (mqtt_t *mqtt) +{ + MQTTClient client; + client = (MQTTClient) mqtt->client; + + if (client != NULL) + { + MQTTClient_destroy (client); + client = NULL; + } + + return; +} +/** + * @brief Destroy the mqtt_t data. + * + * @param mqtt mqtt_t + */ +static void +mqtt_client_data_destroy (mqtt_t *mqtt) +{ + g_free (mqtt->addr); + g_free (mqtt->client_id); + g_free (mqtt); + mqtt = NULL; +} + +/** + * @brief Destroy mqtt handle and mqtt_t. + * + * @param mqtt mqtt_t + */ +void +mqtt_reset (mqtt_t *mqtt) +{ + mqtt_client_destroy (mqtt); + mqtt_client_data_destroy (mqtt); + return; +} + +/** + * @brief Create a new mqtt client. + * + * @param mqtt mqtt_t + * + * @return mqtt client or NULL on error. */ static MQTTClient -mqtt_create (const char *server_uri, char *id) +mqtt_create (mqtt_t *mqtt) { MQTTClient client; MQTTClient_createOptions create_opts = MQTTClient_createOptions_initializer; create_opts.MQTTVersion = MQTTVERSION_5; - int rc = MQTTClient_createWithOptions ( - &client, server_uri, id, MQTTCLIENT_PERSISTENCE_NONE, NULL, &create_opts); + if (mqtt == NULL) + return NULL; + if (mqtt->addr == NULL || mqtt->client_id == NULL) + return NULL; + + int rc = MQTTClient_createWithOptions (&client, mqtt->addr, mqtt->client_id, + MQTTCLIENT_PERSISTENCE_NONE, NULL, + &create_opts); if (rc != MQTTCLIENT_SUCCESS) { @@ -69,29 +140,115 @@ mqtt_create (const char *server_uri, char *id) } return client; } -#endif /* HAVE_MQTT */ /** - * @brief connect to a mqtt broker. + * @brief Set a random client ID. * - * @param server_uri Address of the broker. + * @param mqtt mqtt_t * - * @return Mqtt handle, NULL on error. + * @return Client ID which was set, NULL on failure. */ -mqtt_t * -mqtt_connect (const char *server_uri) +char * +mqtt_set_client_id (mqtt_t *mqtt) { -#ifdef HAVE_MQTT + if (mqtt == NULL) + return NULL; + char *uuid; + + uuid = gvm_uuid_make (); + mqtt->client_id = uuid; + + return uuid; +} + +/** + * @brief Set Server Addr. + * + * @param mqtt mqtt_T + * @param server_uri URI of server. E.g "tcp://127.0.0.1:1883" + * + * @return 0 on success, NULL on error. + */ +static void +mqtt_set_server_addr (mqtt_t *mqtt, const char *server_uri) +{ + if (mqtt == NULL) + { + g_warning ("%s:Can not set server addr on unitialized mqtt handle.", + __func__); + return; + } + + mqtt->addr = g_strdup (server_uri); +} + +/** + * @brief Set client handle + * + * @param mqtt mqtt_t + * @param client Client to set + * + */ +static void +mqtt_set_client (mqtt_t *mqtt, MQTTClient client) +{ + if (mqtt == NULL) + { + g_warning ("%s: Can not set clien on uninitialized mqtt handle.", + __func__); + return; + } + mqtt->client = client; + return; +} + +/** + * @brief Init mqtt_t + * + * @param server_uri Server URI + * + * @return New mqtt_t, NULL on error + */ +mqtt_t * +mqtt_init (const char *server_uri) +{ + mqtt_t *mqtt = NULL; + + mqtt = g_malloc0 (sizeof (mqtt)); + + // Set random uuid as client id + if (mqtt_set_client_id (mqtt) == NULL) + { + g_warning ("%s: Could not set client id.", __func__); + g_free (mqtt); + return NULL; + } + mqtt_set_server_addr (mqtt, server_uri); + mqtt_set_client (mqtt, NULL); + + return mqtt; +} + +/** + * @brief Make new client and connect to mqtt broker. + * + * @param mqtt Initialized mqtt_t + * + * @return mqtt_t handle, NULL on error. + */ +static mqtt_t * +mqtt_connect (mqtt_t *mqtt) +{ int rc; MQTTClient client; - mqtt_t *mqtt = NULL; MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer5; MQTTProperties connect_properties = MQTTProperties_initializer; MQTTResponse resp; - uuid = gvm_uuid_make (); - client = mqtt_create (server_uri, uuid); + if (mqtt == NULL) + return NULL; + client = mqtt_create (mqtt); if (!client) return NULL; @@ -105,22 +262,15 @@ mqtt_connect (const char *server_uri) if (rc != MQTTCLIENT_SUCCESS) { g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, - "%s: mqtt connection error to %s: %s", __func__, server_uri, + "%s: mqtt connection error to %s: %s", __func__, mqtt->addr, MQTTClient_strerror (rc)); MQTTResponse_free (resp); return NULL; } - mqtt = g_malloc0 (sizeof (mqtt)); - mqtt->client = client; - mqtt->addr = g_strdup (server_uri); - mqtt->client_id = uuid; + mqtt_set_client (mqtt, client); return mqtt; -#else - (void) server_uri; - return NULL; -#endif /* HAVE_MQTT */ } /** @@ -130,21 +280,36 @@ mqtt_connect (const char *server_uri) * @param topic Topic to publish on. * @param msg Message to publish on queue. * - * @return 0 on success, negative errorcode on failure. + * @return 0 on success, <0 on failure. */ int mqtt_publish (mqtt_t *mqtt, const char *topic, const char *msg) { -#ifdef HAVE_MQTT MQTTClient client; MQTTClient_message pubmsg = MQTTClient_message_initializer; MQTTClient_deliveryToken token; MQTTResponse resp; int rc; + const char *mqtt_server_uri; + + // init mqtt and make new connection + if (mqtt == NULL) + { + mqtt_server_uri = mqtt_get_server_uri (); + if (mqtt_server_uri) + mqtt = mqtt_init (mqtt_server_uri); + if (mqtt == NULL) + return -1; + mqtt = mqtt_connect (mqtt); + if (mqtt == NULL) + return -2; + } client = mqtt->client; - if (!client) - return -1; + if (client == NULL) + { + return -3; + } pubmsg.payload = (char *) msg; pubmsg.payloadlen = (int) strlen (msg); @@ -157,7 +322,7 @@ mqtt_publish (mqtt_t *mqtt, const char *topic, const char *msg) { g_warning ("Failed to connect: %s", MQTTClient_strerror (rc)); MQTTResponse_free (resp); - return -1; + return -4; } if ((rc = MQTTClient_waitForCompletion (client, token, TIMEOUT)) @@ -169,10 +334,50 @@ mqtt_publish (mqtt_t *mqtt, const char *topic, const char *msg) } return rc; -#else - (void) mqtt; - (void) topic; - (void) msg; - return -1; -#endif /* HAVE_MQTT */ +} + +/** + * @brief Send a single message. + * + * This functions creates a mqtt handle, connects, sends the message, closes + * the connection and destroys the handler. + * This function should not be chosen for repeated and frequent messaging. Its + * meant for Error messages and the likes emitted by openvas. + * + * @param topic Topic to publish to + * @param msg Message to publish + * + * @return 0 on success, <0 on failure. + */ +int +mqtt_publish_single_message (const char *topic, const char *msg) +{ + const char *mqtt_server_uri; + mqtt_t *mqtt = NULL; + + mqtt_server_uri = mqtt_get_server_uri (); + if (mqtt_server_uri) + mqtt = mqtt_init (mqtt_server_uri); + if (mqtt == NULL) + return -1; + mqtt = mqtt_connect (mqtt); + if (mqtt == NULL) + { + mqtt_reset (mqtt); + return -2; + } + if (mqtt_publish (mqtt, topic, msg) != 0) + { + mqtt_disconnect (mqtt); + mqtt_reset (mqtt); + return -3; + } + if (mqtt_disconnect (mqtt) != 0) + { + mqtt_reset (mqtt); + return -4; + } + mqtt_reset (mqtt); + + return 0; } diff --git a/util/mqtt.h b/util/mqtt.h index dba28fa60..ae901d882 100644 --- a/util/mqtt.h +++ b/util/mqtt.h @@ -20,9 +20,7 @@ #ifndef _GVM_MQTT_H #define _GVM_MQTT_H -#ifdef HAVE_MQTT #include -#endif /* HAVE_MQTT*/ typedef struct { @@ -32,12 +30,12 @@ typedef struct } mqtt_t; int -gvm_has_mqtt_support (void); - -mqtt_t * -mqtt_connect (const char *); +mqtt_publish (mqtt_t *, const char *, const char *); int -mqtt_publish (mqtt_t *, const char *, const char *); +mqtt_publish_single_message (const char *, const char *); + +void +mqtt_reset (mqtt_t *); #endif /* _GVM_MQTT_H */ From 349df995a599d5a9492d8637c4a529dee4ce7bd1 Mon Sep 17 00:00:00 2001 From: ArnoStiefvater Date: Tue, 13 Jul 2021 13:50:47 +0200 Subject: [PATCH 06/23] Refactor MQTT handling Hide mqtt_t. Fix mqtt_reset(). --- util/mqtt.c | 352 ++++++++++++++++++++++++++++++++-------------------- util/mqtt.h | 23 ++-- 2 files changed, 232 insertions(+), 143 deletions(-) diff --git a/util/mqtt.c b/util/mqtt.c index 376d41ef0..0c884e53e 100644 --- a/util/mqtt.c +++ b/util/mqtt.c @@ -17,27 +17,88 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ +/** + * @file + * @brief Implementation of API to handle MQTT communication. + * + * This file contains all methods to handle MQTT communication. + * + * Before communicating via MQTT a handle has to be created and a connection + * established. This is done by calling mqtt_init(). Mmessages can be + * published via mqtt_publish() afterwards. + * + * mqtt_init() should be called only once at program init. + * After forking mqtt_reset() has to be called in the child. mqtt_publish() can + * be used after mqtt_reset(). No additional mqtt_init() is needed. A new + * connection will be established on first call to publish for the current + * process. + * + * mqtt_publish_single_message() is a convenience function for sending single + * messages. Do not send repeated messages via this function as a new connection + * is established every call. + */ + #include "mqtt.h" -/** TODO: Remove dependency ../base/prefs.h **/ -#include "../base/prefs.h" #include "uuidutils.h" /* gvm_uuid_make */ +#include + #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "lib mqtt" #define QOS 1 #define TIMEOUT 10000L +typedef struct +{ + void *client; + char *client_id; +} mqtt_t; + +static const char *global_server_uri = NULL; +static mqtt_t *global_mqtt_client = NULL; + /** - * @brief Get server uri as specified in the openvas conf file. + * @brief Set the global mqtt server URI. + + * @param server_uri_in Server uri to set. + */ +static void +mqtt_set_global_server_uri (const char *server_uri_in) +{ + global_server_uri = server_uri_in; +} + +/** + * @brief Get global server URI. * * @return Server URI, NULL if not found. */ static const char * -mqtt_get_server_uri () +mqtt_get_global_server_uri () +{ + return global_server_uri; +} + +/** + * @brief + * + * @return Get global client. + */ +static mqtt_t * +mqtt_get_global_client () { - return prefs_get ("mqtt_server_uri"); + return global_mqtt_client; +} + +/** + * @brief Set global client. + */ +static void +mqtt_set_global_client (mqtt_t *mqtt) +{ + global_mqtt_client = mqtt; } /** @@ -64,7 +125,7 @@ mqtt_disconnect (mqtt_t *mqtt) } /** - * @brief Destroy the mqtt client inside mqtt_t struct + * @brief Destroy the MQTTClient client of the mqtt_t * * @param[in] mqtt mqtt_t handle. * @@ -72,41 +133,52 @@ mqtt_disconnect (mqtt_t *mqtt) static void mqtt_client_destroy (mqtt_t *mqtt) { + if (mqtt == NULL) + return; + MQTTClient client; client = (MQTTClient) mqtt->client; if (client != NULL) { - MQTTClient_destroy (client); + MQTTClient_destroy (&client); client = NULL; } return; } + /** * @brief Destroy the mqtt_t data. * * @param mqtt mqtt_t */ static void -mqtt_client_data_destroy (mqtt_t *mqtt) +mqtt_client_data_destroy (mqtt_t **mqtt) { - g_free (mqtt->addr); - g_free (mqtt->client_id); - g_free (mqtt); - mqtt = NULL; + g_free ((*mqtt)->client_id); + g_free (*mqtt); + *mqtt = NULL; } /** - * @brief Destroy mqtt handle and mqtt_t. - * - * @param mqtt mqtt_t + * @brief Destroy MQTTClient handle and free mqtt_t. */ void -mqtt_reset (mqtt_t *mqtt) +mqtt_reset () { + g_debug ("%s: start", __func__); + mqtt_t *mqtt = mqtt_get_global_client (); + + if (mqtt == NULL) + return; + mqtt_client_destroy (mqtt); - mqtt_client_data_destroy (mqtt); + mqtt_client_data_destroy (&mqtt); + + mqtt_set_global_client (mqtt); + + g_debug ("%s: end", __func__); return; } @@ -115,7 +187,7 @@ mqtt_reset (mqtt_t *mqtt) * * @param mqtt mqtt_t * - * @return mqtt client or NULL on error. + * @return MQTTClient or NULL on error. */ static MQTTClient mqtt_create (mqtt_t *mqtt) @@ -124,17 +196,17 @@ mqtt_create (mqtt_t *mqtt) MQTTClient_createOptions create_opts = MQTTClient_createOptions_initializer; create_opts.MQTTVersion = MQTTVERSION_5; - if (mqtt == NULL) - return NULL; - if (mqtt->addr == NULL || mqtt->client_id == NULL) + if (mqtt == NULL || mqtt->client_id == NULL) return NULL; - int rc = MQTTClient_createWithOptions (&client, mqtt->addr, mqtt->client_id, - MQTTCLIENT_PERSISTENCE_NONE, NULL, - &create_opts); + int rc = MQTTClient_createWithOptions ( + &client, mqtt_get_global_server_uri (), mqtt->client_id, + MQTTCLIENT_PERSISTENCE_NONE, NULL, &create_opts); if (rc != MQTTCLIENT_SUCCESS) { + g_warning ("%s: Error creating MQTTClient: %s", __func__, + MQTTClient_strerror (rc)); MQTTClient_destroy (&client); return NULL; } @@ -148,7 +220,7 @@ mqtt_create (mqtt_t *mqtt) * * @return Client ID which was set, NULL on failure. */ -char * +static char * mqtt_set_client_id (mqtt_t *mqtt) { if (mqtt == NULL) @@ -163,71 +235,19 @@ mqtt_set_client_id (mqtt_t *mqtt) } /** - * @brief Set Server Addr. - * - * @param mqtt mqtt_T - * @param server_uri URI of server. E.g "tcp://127.0.0.1:1883" - * - * @return 0 on success, NULL on error. - */ -static void -mqtt_set_server_addr (mqtt_t *mqtt, const char *server_uri) -{ - if (mqtt == NULL) - { - g_warning ("%s:Can not set server addr on unitialized mqtt handle.", - __func__); - return; - } - - mqtt->addr = g_strdup (server_uri); -} - -/** - * @brief Set client handle - * - * @param mqtt mqtt_t - * @param client Client to set + * @brief Set MQTTClient of mqtt_t * + * @return 0 on success, -1 on failure. */ -static void +static int mqtt_set_client (mqtt_t *mqtt, MQTTClient client) { if (mqtt == NULL) { - g_warning ("%s: Can not set clien on uninitialized mqtt handle.", - __func__); - return; + return -1; } mqtt->client = client; - return; -} - -/** - * @brief Init mqtt_t - * - * @param server_uri Server URI - * - * @return New mqtt_t, NULL on error - */ -mqtt_t * -mqtt_init (const char *server_uri) -{ - mqtt_t *mqtt = NULL; - - mqtt = g_malloc0 (sizeof (mqtt)); - - // Set random uuid as client id - if (mqtt_set_client_id (mqtt) == NULL) - { - g_warning ("%s: Could not set client id.", __func__); - g_free (mqtt); - return NULL; - } - mqtt_set_server_addr (mqtt, server_uri); - mqtt_set_client (mqtt, NULL); - - return mqtt; + return 0; } /** @@ -235,10 +255,10 @@ mqtt_init (const char *server_uri) * * @param mqtt Initialized mqtt_t * - * @return mqtt_t handle, NULL on error. + * @return 0 on success, <0 on error. */ -static mqtt_t * -mqtt_connect (mqtt_t *mqtt) +static int +mqtt_connect (mqtt_t *mqtt, const char *server_uri) { int rc; MQTTClient client; @@ -247,10 +267,11 @@ mqtt_connect (mqtt_t *mqtt) MQTTResponse resp; if (mqtt == NULL) - return NULL; + return -1; + client = mqtt_create (mqtt); if (!client) - return NULL; + return -2; conn_opts.keepAliveInterval = 0; conn_opts.cleanstart = 1; @@ -262,53 +283,74 @@ mqtt_connect (mqtt_t *mqtt) if (rc != MQTTCLIENT_SUCCESS) { g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, - "%s: mqtt connection error to %s: %s", __func__, mqtt->addr, + "%s: mqtt connection error to %s: %s", __func__, server_uri, MQTTClient_strerror (rc)); MQTTResponse_free (resp); - return NULL; + return -3; } mqtt_set_client (mqtt, client); - return mqtt; + return 0; +} + +/** + * @brief Init MQTT communication + * + * @param server_uri Server URI + * + * @return 0 on success, <0 on error. + */ +int +mqtt_init (const char *server_uri) +{ + g_debug ("%s: start", __func__); + mqtt_t *mqtt = NULL; + + mqtt = g_malloc0 (sizeof (mqtt_t)); + const char *global_server_uri; + // Set random uuid as client id + if (mqtt_set_client_id (mqtt) == NULL) + { + g_warning ("%s: Could not set client id.", __func__); + g_free (mqtt); + mqtt = NULL; + return -1; + } + g_debug ("%s: client id set: %s", __func__, mqtt->client_id); + global_server_uri = mqtt_get_global_server_uri (); + if (global_server_uri == NULL) + mqtt_set_global_server_uri (server_uri); + mqtt_connect (mqtt, global_server_uri); + + mqtt_set_global_client (mqtt); + + g_debug ("%s: end", __func__); + return 0; } /** - * @brief Publish message on topic. + * @brief Use the provided client to publish message on a topic * - * @param mqtt MQTT handle. + * @param mqtt mqtt_t * @param topic Topic to publish on. * @param msg Message to publish on queue. * * @return 0 on success, <0 on failure. */ int -mqtt_publish (mqtt_t *mqtt, const char *topic, const char *msg) +mqtt_client_publish (mqtt_t *mqtt, const char *topic, const char *msg) { MQTTClient client; MQTTClient_message pubmsg = MQTTClient_message_initializer; MQTTClient_deliveryToken token; MQTTResponse resp; int rc; - const char *mqtt_server_uri; - - // init mqtt and make new connection - if (mqtt == NULL) - { - mqtt_server_uri = mqtt_get_server_uri (); - if (mqtt_server_uri) - mqtt = mqtt_init (mqtt_server_uri); - if (mqtt == NULL) - return -1; - mqtt = mqtt_connect (mqtt); - if (mqtt == NULL) - return -2; - } client = mqtt->client; if (client == NULL) { - return -3; + return -1; } pubmsg.payload = (char *) msg; @@ -322,7 +364,7 @@ mqtt_publish (mqtt_t *mqtt, const char *topic, const char *msg) { g_warning ("Failed to connect: %s", MQTTClient_strerror (rc)); MQTTResponse_free (resp); - return -4; + return -2; } if ((rc = MQTTClient_waitForCompletion (client, token, TIMEOUT)) @@ -336,48 +378,94 @@ mqtt_publish (mqtt_t *mqtt, const char *topic, const char *msg) return rc; } +/** + * @brief Publish a message on topic using the global client + * + * @param topic topic + * @param msg message + * + * @return 0 on success, <0 on error. + */ +int +mqtt_publish (const char *topic, const char *msg) +{ + mqtt_t *mqtt = NULL; + const char *server_uri; + int rc = 0; + + // init new global client if it was mqtt_reset() + if ((mqtt_get_global_client ()) == NULL) + { + server_uri = mqtt_get_global_server_uri (); + if (server_uri == NULL) + { + g_warning ("%s: mqtt_init() has to be called once at program start " + "else the server URI is not set. ", + __func__); + return -1; + } + mqtt_init (server_uri); + } + mqtt = mqtt_get_global_client (); + + rc = mqtt_client_publish (mqtt, topic, msg); + + return rc; +} + /** * @brief Send a single message. * * This functions creates a mqtt handle, connects, sends the message, closes * the connection and destroys the handler. * This function should not be chosen for repeated and frequent messaging. Its - * meant for Error messages and the likes emitted by openvas. + * meant for error messages and the likes emitted by openvas. * - * @param topic Topic to publish to - * @param msg Message to publish + * @param server_uri_in Server URI + * @param topic Topic to publish to + * @param msg Message to publish * * @return 0 on success, <0 on failure. */ int -mqtt_publish_single_message (const char *topic, const char *msg) +mqtt_publish_single_message (const char *server_uri_in, const char *topic, + const char *msg) { - const char *mqtt_server_uri; + const char *server_uri; mqtt_t *mqtt = NULL; + int ret = 0; - mqtt_server_uri = mqtt_get_server_uri (); - if (mqtt_server_uri) - mqtt = mqtt_init (mqtt_server_uri); - if (mqtt == NULL) - return -1; - mqtt = mqtt_connect (mqtt); - if (mqtt == NULL) + // If server_uri is NULL try to get global + if (server_uri_in == NULL) { - mqtt_reset (mqtt); - return -2; + server_uri = mqtt_get_global_server_uri (); + if (server_uri == NULL) + { + g_warning ( + "%s: No server URI provided and no global server URI available.", + __func__); + return -1; + } } - if (mqtt_publish (mqtt, topic, msg) != 0) + else { - mqtt_disconnect (mqtt); - mqtt_reset (mqtt); - return -3; + server_uri = server_uri_in; } - if (mqtt_disconnect (mqtt) != 0) + + mqtt = g_malloc0 (sizeof (mqtt_t)); + // Set random uuid as client id + if (mqtt_set_client_id (mqtt) == NULL) { - mqtt_reset (mqtt); - return -4; + g_warning ("%s: Could not set client id.", __func__); + g_free (mqtt); + return -2; } - mqtt_reset (mqtt); + mqtt_connect (mqtt, server_uri); + mqtt_client_publish (mqtt, topic, msg); - return 0; + mqtt_disconnect (mqtt); + mqtt_client_destroy (mqtt); + mqtt_client_data_destroy (&mqtt); + + return ret; } diff --git a/util/mqtt.h b/util/mqtt.h index ae901d882..d1f6e74d5 100644 --- a/util/mqtt.h +++ b/util/mqtt.h @@ -17,25 +17,26 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ +/** + * @file + * @brief Protos for MQTT handling. + */ + #ifndef _GVM_MQTT_H #define _GVM_MQTT_H #include -typedef struct -{ - void *client; - char *client_id; - char *addr; -} mqtt_t; - int -mqtt_publish (mqtt_t *, const char *, const char *); +mqtt_init (const char *); + +void +mqtt_reset (); int -mqtt_publish_single_message (const char *, const char *); +mqtt_publish (const char *, const char *); -void -mqtt_reset (mqtt_t *); +int +mqtt_publish_single_message (const char *, const char *, const char *); #endif /* _GVM_MQTT_H */ From 939fc24b10163d477b89c9f4d0aabd0a6dd87d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaspar=20L=C3=B6chte?= Date: Wed, 14 Jul 2021 16:41:46 +0200 Subject: [PATCH 07/23] Small adjustments on the CI --- .github/workflows/ci-c.yml | 10 +++++----- .github/workflows/docker-ci.yml | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci-c.yml b/.github/workflows/ci-c.yml index ba2e09f30..18b586e66 100644 --- a/.github/workflows/ci-c.yml +++ b/.github/workflows/ci-c.yml @@ -24,8 +24,8 @@ jobs: strategy: matrix: container: - - greenbone/gvm-libs-master-clang-testing - - greenbone/gvm-libs-master-gcc-testing + - greenbone/gvm-libs-middleware-clang-testing + - greenbone/gvm-libs-middleware-gcc-testing container: ${{ matrix.container }} steps: - uses: actions/checkout@v2.3.4 @@ -42,8 +42,8 @@ jobs: strategy: matrix: container: - - greenbone/gvm-libs-master-clang-testing - - greenbone/gvm-libs-master-gcc-testing + - greenbone/gvm-libs-middleware-clang-testing + - greenbone/gvm-libs-middleware-gcc-testing container: ${{ matrix.container }} steps: - uses: actions/checkout@v2.3.4 @@ -56,7 +56,7 @@ jobs: scan_build: name: Scan-build gvm-libs with clang runs-on: 'ubuntu-latest' - container: greenbone/gvm-libs-master-clang-testing + container: greenbone/gvm-libs-middleware-clang-testing steps: - uses: actions/checkout@v2.3.4 - name: Configure and Compile gvm-libs diff --git a/.github/workflows/docker-ci.yml b/.github/workflows/docker-ci.yml index e4d0d7e12..0d77696e2 100644 --- a/.github/workflows/docker-ci.yml +++ b/.github/workflows/docker-ci.yml @@ -29,7 +29,7 @@ jobs: echo $BRANCH if [ $BRANCH = "master" ]; \ then VERSION=master; \ - else VERSION=$(echo "$BRANCH" | sed 's/gvm-libs-//g' -); \ + else VERSION=$(echo "$BRANCH" | sed 's/gvm-libs-//g' -); \ fi; echo "VERSION=$VERSION" >> $GITHUB_ENV - name: Set up Docker Buildx @@ -76,7 +76,7 @@ jobs: echo $BRANCH if [ $BRANCH = "master" ]; \ then VERSION=master; \ - else VERSION=$(echo "$BRANCH" | sed 's/gvm-libs-//g' -); \ + else VERSION=$(echo "$BRANCH" | sed 's/gvm-libs-//g' -); \ fi; echo "VERSION=$VERSION" >> $GITHUB_ENV - name: Set up Docker Buildx From 79ea1662c2c07266698f039cafe0106858d835cf Mon Sep 17 00:00:00 2001 From: ArnoStiefvater Date: Tue, 20 Jul 2021 12:44:22 +0200 Subject: [PATCH 08/23] Add function for checking init status --- util/mqtt.c | 26 ++++++++++++++++++++++++-- util/mqtt.h | 4 ++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/util/mqtt.c b/util/mqtt.c index 0c884e53e..be587ac55 100644 --- a/util/mqtt.c +++ b/util/mqtt.c @@ -42,8 +42,6 @@ #include "uuidutils.h" /* gvm_uuid_make */ -#include - #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "lib mqtt" @@ -58,6 +56,29 @@ typedef struct static const char *global_server_uri = NULL; static mqtt_t *global_mqtt_client = NULL; +static gboolean mqtt_initialized = FALSE; + +/** + * @brief Set the global init status. + + * @param Status Status of initialization. + */ +static void +mqtt_set_initialized_status (gboolean status) +{ + mqtt_initialized = status; +} + +/** + * @brief Get the global init status. + * + * @return Initialization status of mqtt handling. + */ +gboolean +mqtt_is_initialized () +{ + return mqtt_initialized; +} /** * @brief Set the global mqtt server URI. @@ -324,6 +345,7 @@ mqtt_init (const char *server_uri) mqtt_connect (mqtt, global_server_uri); mqtt_set_global_client (mqtt); + mqtt_set_initialized_status (TRUE); g_debug ("%s: end", __func__); return 0; diff --git a/util/mqtt.h b/util/mqtt.h index d1f6e74d5..7cddd73b6 100644 --- a/util/mqtt.h +++ b/util/mqtt.h @@ -26,10 +26,14 @@ #define _GVM_MQTT_H #include +#include int mqtt_init (const char *); +gboolean +mqtt_is_initialized (); + void mqtt_reset (); From 2582fb540fa3bd8f867ea38265d05568a23fcea5 Mon Sep 17 00:00:00 2001 From: ArnoStiefvater Date: Wed, 21 Jul 2021 13:22:07 +0200 Subject: [PATCH 09/23] Add changelog entries for middleware branch --- CHANGELOG.md | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b90b5f4b..5675cfb42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,21 +4,33 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). -## [21.10] (unreleased) +## [Middleware] (unmerged) ### Added -- Add support for volatile keys. [#460](https://github.com/greenbone/gvm-libs/pull/460) -- Possibility to use lcrypt with `$6$` (sha512) for authentication [484](https://github.com/greenbone/gvm-libs/pull/484) -- Add function to perform an alive test and get the amount of alive hosts. [495](https://github.com/greenbone/gvm-libs/pull/495) -- Add functions for sentry integration. [#502](https://github.com/greenbone/gvm-libs/pull/502) [#506](https://github.com/greenbone/gvm-libs/pull/506) - Add basic support for mqtt. Original [#505](https://github.com/greenbone/gvm-libs/pull/505) [#511](https://github.com/greenbone/gvm-libs/pull/511). Reintroduction after Rebase [#538](https://github.com/greenbone/gvm-libs/pull/538) +- Add function for mqtt init status [#567](https://github.com/greenbone/gvm-libs/pull/567) +### Changed + +- Refactor MQTT handling [#562](https://github.com/greenbone/gvm-libs/pull/562) + +### Fixed +### Removed + +## [21.10] (unreleased) + +### Added + +- Add support for volatile keys. [#460](https://github.com/greenbone/gvm-libs/pull/460) +- Possibility to use lcrypt with `$6$` (sha512) for authentication [484](https://github.com/greenbone/gvm-libs/pull/484) +- Add function to perform an alive test and get the amount of alive hosts. [495](https://github.com/greenbone/gvm-libs/pull/495) +- Add functions for sentry integration. [#502](https://github.com/greenbone/gvm-libs/pull/502) [#506](https://github.com/greenbone/gvm-libs/pull/506) ### Changed ### Fixed From d461a475ffc00a0d1a99deef353e39f3006a705a Mon Sep 17 00:00:00 2001 From: Juan Jose Nicola Date: Mon, 26 Jul 2021 01:20:09 -0500 Subject: [PATCH 10/23] Add function to get the severity_vector, otherwise the cvss_base_vector. --- CHANGELOG.md | 1 + base/nvti.c | 30 ++++++++++++++++++++++++++++++ base/nvti.h | 2 ++ 3 files changed, 33 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5675cfb42..9e1bf286a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). Reintroduction after Rebase [#538](https://github.com/greenbone/gvm-libs/pull/538) - Add function for mqtt init status [#567](https://github.com/greenbone/gvm-libs/pull/567) +- Add function to get the severity_vector, otherwise the cvss_base_vector. [#568](https://github.com/greenbone/gvm-libs/pull/568) ### Changed diff --git a/base/nvti.c b/base/nvti.c index c203f9a03..2c80025ee 100644 --- a/base/nvti.c +++ b/base/nvti.c @@ -936,6 +936,36 @@ nvti_severity_score (const nvti_t *n) return score; } +/** + * @brief Get the severity score + * + * Extended severity was introduced but still not all + * vts are using it. Therefore it must be check if + * we can calculate the score from the severity_vector tag + * or we have to calculate it from the deprecated + * cvss_base_vector tag. + * + * @param n The NVT Info structure. + * + * @return The severity_vector if present or cvss_base_vector otherwise. + * NULL indicates an error. Must be free()'d by the caller. + */ +gchar * +nvti_severity_vector_from_tag (const nvti_t *n) +{ + gchar *vector; + + /* Currently, only one severity_vector can be stored as tag. + * Therfore we just check this one. */ + vector = nvti_get_tag (n, "severity_vector"); + if (vector) + return vector; + + vector = nvti_get_tag (n, "cvss_base_vector"); + + return vector; +} + /** * @brief Get the solution. * diff --git a/base/nvti.h b/base/nvti.h index f8c0c0d88..f228995f5 100644 --- a/base/nvti.h +++ b/base/nvti.h @@ -105,6 +105,8 @@ vtseverity_t * nvti_vtseverity (const nvti_t *, guint); double nvti_severity_score (const nvti_t *); +gchar * +nvti_severity_vector_from_tag (const nvti_t *); nvti_t * nvti_new (void); From f489c9fde556749563ff0bae693345c4974c1641 Mon Sep 17 00:00:00 2001 From: Juan Jose Nicola Date: Mon, 26 Jul 2021 01:52:55 -0500 Subject: [PATCH 11/23] Add tests --- base/nvti_tests.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/base/nvti_tests.c b/base/nvti_tests.c index c2a6b7f71..dae80bf4c 100644 --- a/base/nvti_tests.c +++ b/base/nvti_tests.c @@ -141,6 +141,48 @@ Ensure (nvti, nvtis_add_does_not_use_oid_as_key) assert_that (nvtis_lookup (nvtis, "2"), is_null); } +/* nvti severity vector */ + +Ensure (nvti, nvti_get_severity_vector_both) +{ + nvti_t *nvti; + + nvti = nvti_new (); + nvti_set_tag (nvti, "cvss_base_vector=DEF"); + nvti_set_tag (nvti, "severity_vector=ABC"); + + assert_that (nvti_severity_vector_from_tag (nvti), + is_equal_to_string ("ABC")); + + nvti_free (nvti); +} + +Ensure (nvti, nvti_get_severity_vector_no_cvss_base) +{ + nvti_t *nvti; + + nvti = nvti_new (); + nvti_set_tag (nvti, "severity_vector=ABC"); + + assert_that (nvti_severity_vector_from_tag (nvti), + is_equal_to_string ("ABC")); + + nvti_free (nvti); +} + +Ensure (nvti, nvti_get_severity_vector_no_severity_vector) +{ + nvti_t *nvti; + + nvti = nvti_new (); + nvti_set_tag (nvti, "cvss_base_vector=DEF"); + + assert_that (nvti_severity_vector_from_tag (nvti), + is_equal_to_string ("DEF")); + + nvti_free (nvti); +} + /* Test suite. */ int @@ -163,6 +205,11 @@ main (int argc, char **argv) add_test_with_context (suite, nvti, nvtis_add_does_not_use_oid_as_key); + add_test_with_context (suite, nvti, nvti_get_severity_vector_both); + add_test_with_context (suite, nvti, + nvti_get_severity_vector_no_severity_vector); + add_test_with_context (suite, nvti, nvti_get_severity_vector_no_cvss_base); + if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); From aecb14324dfb5f870031aeaa11cda7d85d6afa54 Mon Sep 17 00:00:00 2001 From: Juan Jose Nicola Date: Tue, 27 Jul 2021 01:23:41 -0500 Subject: [PATCH 12/23] Fix docstrings --- base/nvti.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/nvti.c b/base/nvti.c index 2c80025ee..a896e5eb4 100644 --- a/base/nvti.c +++ b/base/nvti.c @@ -940,9 +940,9 @@ nvti_severity_score (const nvti_t *n) * @brief Get the severity score * * Extended severity was introduced but still not all - * vts are using it. Therefore it must be check if + * vts are using it. Therefore it must be checked if * we can calculate the score from the severity_vector tag - * or we have to calculate it from the deprecated + * or if we have to calculate it from the deprecated * cvss_base_vector tag. * * @param n The NVT Info structure. From 31945758feebac713e551603195fa5a44074cfeb Mon Sep 17 00:00:00 2001 From: Philipp Eder Date: Tue, 3 Aug 2021 18:15:53 +0200 Subject: [PATCH 13/23] Add: subscribe and retrieve message from mqtt To retrieve messages 1. mqtt_subscribe 1. mqtt_retrieve_message 1. mqtt_unsubscribe are implemented. Since at least in openvas most retrieving functionalities are done a in request/response fashion `mqtt_retrieve_message` is written in a blocking way instead of using the callback functionality of paho. With that we have fine granular control over threads and processes and can decide how we want to treat message retrieval in more abstract libraries. There is a small example on how to use the mqtt_* api retrieve messages: ``` \#include \#include \#include \#include \#define TOPIC "#" void signalhandler (int signum) { printf ("Caught %d, reset mqtt\n", signum); mqtt_unsubscribe (TOPIC); mqtt_reset (); exit (0); } int main () { signal (SIGINT, signalhandler); int rc; if ((rc = mqtt_init ("localhost:9138")) != 0) { printf ("init returned %d, quitting\n", rc); goto exit; } if ((rc = mqtt_subscribe (TOPIC)) != 0) { printf ("subscribe returned %d, quitting\n", rc); goto exit; } while (1) { char *topic; int topic_len; char *payload; int payload_len; if ((rc = mqtt_retrieve_message (&topic, &topic_len, &payload, &payload_len)) == -1) { printf ("unable to retrieve message, quitting\n"); goto exit; } if (rc == 0) printf ("[%d] Got message: %s on topic %s\n", payload_len, payload != NULL ? payload : "N/A", topic != NULL ? topic : "N/A"); else rc = 0; if (payload != NULL) free (payload); if (topic != NULL) free (topic); } exit: mqtt_unsubscribe (TOPIC); mqtt_reset (); return rc; } ``` to compile it please install libgvm and build it via: ``` gcc $(pkg-config --cflags glib-2.0) main.c -lgvm_util -lgvm_base $(pkg-config --libs glib-2.0) ``` --- .gitignore | 7 ++ util/mqtt.c | 242 ++++++++++++++++++++++++++++++++++++++++++++++++++-- util/mqtt.h | 9 ++ 3 files changed, 251 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 1b763adf4..72a1e7979 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,9 @@ build/ .ccls +# clangd +# generated by +# cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 +compile_commands.json +.cache/ +# cmake +CMakeFiles/ diff --git a/util/mqtt.c b/util/mqtt.c index be587ac55..05bd2d54d 100644 --- a/util/mqtt.c +++ b/util/mqtt.c @@ -42,6 +42,9 @@ #include "uuidutils.h" /* gvm_uuid_make */ +#include +#include + #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "lib mqtt" @@ -197,7 +200,7 @@ mqtt_reset () mqtt_client_destroy (mqtt); mqtt_client_data_destroy (&mqtt); - mqtt_set_global_client (mqtt); + mqtt_set_global_client (NULL); g_debug ("%s: end", __func__); return; @@ -207,11 +210,12 @@ mqtt_reset () * @brief Create a new mqtt client. * * @param mqtt mqtt_t + * @param address address of the broker * * @return MQTTClient or NULL on error. */ static MQTTClient -mqtt_create (mqtt_t *mqtt) +mqtt_create (mqtt_t *mqtt, const char *address) { MQTTClient client; MQTTClient_createOptions create_opts = MQTTClient_createOptions_initializer; @@ -220,9 +224,9 @@ mqtt_create (mqtt_t *mqtt) if (mqtt == NULL || mqtt->client_id == NULL) return NULL; - int rc = MQTTClient_createWithOptions ( - &client, mqtt_get_global_server_uri (), mqtt->client_id, - MQTTCLIENT_PERSISTENCE_NONE, NULL, &create_opts); + int rc = MQTTClient_createWithOptions (&client, address, mqtt->client_id, + MQTTCLIENT_PERSISTENCE_NONE, NULL, + &create_opts); if (rc != MQTTCLIENT_SUCCESS) { @@ -290,7 +294,7 @@ mqtt_connect (mqtt_t *mqtt, const char *server_uri) if (mqtt == NULL) return -1; - client = mqtt_create (mqtt); + client = mqtt_create (mqtt, server_uri); if (!client) return -2; @@ -342,7 +346,7 @@ mqtt_init (const char *server_uri) global_server_uri = mqtt_get_global_server_uri (); if (global_server_uri == NULL) mqtt_set_global_server_uri (server_uri); - mqtt_connect (mqtt, global_server_uri); + mqtt_connect (mqtt, server_uri); mqtt_set_global_client (mqtt); mqtt_set_initialized_status (TRUE); @@ -491,3 +495,227 @@ mqtt_publish_single_message (const char *server_uri_in, const char *topic, return ret; } + +/** + * @brief subscribes to a single topic. + * + * mqtt_subscribe_r uses given mqtt_t to subscribe with given qos to given + * topic. + * + * To be able to subscribe to a topic the client needs to be connected to a + * broker. + * + * @param mqtt_t contains the mqtt client + * @param qos quality of service of messages within topic + * @param topic Topic to subscribe to + * + * @return 0 on success, -1 when given mqtt is not useable, -2 when subscription + * failed. + */ +int +mqtt_subscribe_r (mqtt_t *mqtt, int qos, const char *topic) +{ + if (mqtt == NULL || mqtt->client == NULL) + { + return -1; + } + MQTTSubscribe_options opts = MQTTSubscribe_options_initializer; + MQTTProperties props = MQTTProperties_initializer; + MQTTResponse resp = + MQTTClient_subscribe5 (mqtt->client, topic, qos, &opts, &props); + if (resp.reasonCode != MQTTREASONCODE_GRANTED_QOS_1) + { + return -2; + } + return 0; +} + +/** + * @brief subscribes to a single topic. + * + * mqtt_subscribe uses global mqtt_t to subscribe with global qos to given + * topic. + * + * To be able to subscribe to a topic the client needs to be connected to a + * broker. To do that call `mqtt_init` before `mqtt_subscribe`. + * + * + * @param topic Topic to subscribe to + * + * @return 0 on success, -1 when mqtt is not initialized, -2 when subscription + * failed. + */ +int +mqtt_subscribe (const char *topic) +{ + return mqtt_subscribe_r (mqtt_get_global_client (), QOS, topic); +} + +/** + * @brief unsubscribe a single topic. + * + * This function unsubscribes given client from a given topic. + * + * @param mqtt_t contains the mqtt client + * @param topic Topic to unsubscribe from + * + * @return 0 on success, -1 when given mqtt is not useable, -2 when unsubscribe + * failed. + */ +int +mqtt_unsubscribe_r (mqtt_t *mqtt, const char *topic) +{ + if (mqtt == NULL || mqtt->client == NULL) + { + return -1; + } + + if (MQTTClient_unsubscribe (mqtt->client, topic) != MQTTCLIENT_SUCCESS) + { + return -2; + } + + return 0; +} + +/** + * @brief unsubscribe a single topic. + * + * This function unsubscribes global client from a given topic. + * + * @param topic Topic to unsubscribe from + * + * @return 0 on success, -1 when given mqtt is not useable, -2 when unsubscribe + * failed. + */ +int +mqtt_unsubscribe (const char *topic) +{ + return mqtt_unsubscribe_r (mqtt_get_global_client (), topic); +} + +/** + * @brief wait for a given timeout in ms to retrieve any message of subscribed + * topics + * + * This function performs a synchronous receive of incoming messages. + * Using this function allows a single-threaded client subscriber application to + * be written. When called, this function blocks until the next message arrives + * or the specified timeout expires. + * + * Important note: The application must free() the memory allocated + * to the topic and payload when processing is complete. + * @param mqtt an already created and connected mqtt client. + * @param[out] topic The address of a pointer to a topic. This function + * allocates the memory for the topic and returns it to the application + * by setting topic to point to the topic. + * @param[out] topic_len The length of the topic. + * @param[out] payload The address of a pointer to the received message. This + * function allocates the memory for the payload and returns it to the + * application by setting payload to point to the received message. + * The pointer is set to NULL if the timeout expires. + * @param[out] payload_len The length of the payload. + * @param timeout The length of time to wait for a message in milliseconds. + * @return 0 on message retrieved, 1 on no message retrieved and -1 on an error. + */ +int +mqtt_retrieve_message_r (mqtt_t *mqtt, char **topic, int *topic_len, + char **payload, int *payload_len, + const unsigned int timeout) +{ + int rc = -1; + char *tmp = NULL; + MQTTClient_message *message = NULL; + if (mqtt == NULL || mqtt->client == NULL) + { + g_warning ("mqtt is not initialized."); + goto exit; + } + // copy from tmp into topic to make free work as usual and don't force the + // user to double check topic_len and topic + rc = MQTTClient_receive (mqtt->client, &tmp, topic_len, &message, timeout); + if (rc == MQTTCLIENT_SUCCESS || rc == MQTTCLIENT_TOPICNAME_TRUNCATED) + { + // successfully checked for new messages but we didn't get any + if (message) + { + g_debug ("%s: got message %s (%d) on topic %s (%d) \n", __func__, + (char *) message->payload, message->payloadlen, tmp, + *topic_len); + + if ((*topic = calloc (1, *topic_len)) == NULL) + { + goto exit; + } + rc = 0; + if ((strncpy (*topic, tmp, *topic_len)) == NULL) + { + g_warning ("unable to copy topic"); + rc = -1; + goto exit; + } + + *payload_len = message->payloadlen; + *payload = calloc (1, message->payloadlen); + if ((strncpy (*payload, (char *) message->payload, + message->payloadlen)) + == NULL) + { + g_warning ("unable to copy payload"); + rc = -1; + goto exit; + } + } + else + { + rc = 1; + *payload = NULL; + *payload_len = 0; + *topic = NULL; + *topic_len = 0; + } + } + else + { + rc = -1; + } + +exit: + if (message != NULL) + MQTTClient_freeMessage (&message); + if (tmp != NULL) + MQTTClient_free (tmp); + + return rc; +} + +/** + * @brief wait for a given timeout in ms to retrieve any message of subscribed + * topics + * + * This function performs a synchronous receive of incoming messages. + * Using this function allows a single-threaded client subscriber application to + * be written. When called, this function blocks until the next message arrives + * or the specified timeout expires. + * + * Important note: The application must free() the memory allocated + * to the topic and payload when processing is complete. + * @param[out] topic The address of a pointer to a topic. This function + * allocates the memory for the topic and returns it to the application + * by setting topic to point to the topic. + * @param[out] topic_len The length of the topic. + * @param[out] payload The address of a pointer to the received message. This + * function allocates the memory for the payload and returns it to the + * application by setting payload to point to the received message. + * The pointer is set to NULL if the timeout expires. + * @param[out] payload_len The length of the payload. + * @param timeout The length of time to wait for a message in milliseconds. + * @return 0 on message retrieved, 1 on no message retrieved and -1 on an error. + */ +int +mqtt_retrieve_message (char **topic, int *topic_len, char **payload, + int *payload_len) +{ + return mqtt_retrieve_message_r (mqtt_get_global_client (), topic, topic_len, + payload, payload_len, 501); +} diff --git a/util/mqtt.h b/util/mqtt.h index 7cddd73b6..e92173899 100644 --- a/util/mqtt.h +++ b/util/mqtt.h @@ -43,4 +43,13 @@ mqtt_publish (const char *, const char *); int mqtt_publish_single_message (const char *, const char *, const char *); +int +mqtt_subscribe (const char *); + +int +mqtt_retrieve_message (char **, int *, char **, int *); + +int +mqtt_unsubscribe (const char *); + #endif /* _GVM_MQTT_H */ From 14f37d16073ca7580c1a4ee274e755d7a4e6742a Mon Sep 17 00:00:00 2001 From: Juan Jose Nicola Date: Thu, 12 Aug 2021 08:30:47 -0500 Subject: [PATCH 14/23] Remove timeout from the nvti structure. Because it is now handle as script preference. --- base/nvti.c | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/base/nvti.c b/base/nvti.c index a896e5eb4..becb7c315 100644 --- a/base/nvti.c +++ b/base/nvti.c @@ -441,7 +441,6 @@ typedef struct nvti GSList *prefs; /**< @brief Collection of NVT preferences */ // The following are not settled yet. - gint timeout; /**< @brief Default timeout time for this NVT */ gint category; /**< @brief The category, this NVT belongs to */ gchar *family; /**< @brief Family the NVT belongs to */ } nvti_t; @@ -1242,20 +1241,6 @@ nvti_pref (const nvti_t *n, guint p) return n ? g_slist_nth_data (n->prefs, p) : NULL; } -/** - * @brief Get the timeout for this NVT. - * - * @param n The NVT Info structure of which the timeout should - * be returned. - * - * @return The timeout integer number. A value <= 0 indicates it is not set. - */ -gint -nvti_timeout (const nvti_t *n) -{ - return n ? n->timeout : -1; -} - /** * @brief Get the category for this NVT. * @@ -1838,25 +1823,6 @@ nvti_set_family (nvti_t *n, const gchar *family) return 0; } -/** - * @brief Set the timeout of a NVT Info. - * - * @param n The NVT Info structure. - * - * @param timeout The timeout to set. Values <= 0 will indicate it is not set. - * - * @return 0 for success. Anything else indicates an error. - */ -int -nvti_set_timeout (nvti_t *n, const gint timeout) -{ - if (!n) - return -1; - - n->timeout = timeout; - return 0; -} - /** * @brief Set the category type of a NVT Info. * From 3817f9e51d0b8cc30586f9d9ac46f5b5adf05afa Mon Sep 17 00:00:00 2001 From: Juan Jose Nicola Date: Thu, 12 Aug 2021 08:35:58 -0500 Subject: [PATCH 15/23] Remove NVT_TIMEOUT_POS from the redis structure. The timeout is not stored under the redis key `nvt:` anymore. --- util/kb.c | 5 ++--- util/kb.h | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/util/kb.c b/util/kb.c index c2ac8b9c1..0f533887b 100644 --- a/util/kb.c +++ b/util/kb.c @@ -955,7 +955,6 @@ redis_get_nvt_all (kb_t kb, const char *oid) nvti_add_refs (nvti, "bid", rep->element[NVT_BIDS_POS]->str, ""); nvti_add_refs (nvti, NULL, rep->element[NVT_XREFS_POS]->str, ""); nvti_set_category (nvti, atoi (rep->element[NVT_CATEGORY_POS]->str)); - nvti_set_timeout (nvti, atoi (rep->element[NVT_TIMEOUT_POS]->str)); nvti_set_family (nvti, rep->element[NVT_FAMILY_POS]->str); nvti_set_name (nvti, rep->element[NVT_NAME_POS]->str); @@ -1560,12 +1559,12 @@ redis_add_nvt (kb_t kb, const nvti_t *nvt, const char *filename) kbr = redis_kb (kb); rep = redis_cmd ( - kbr, "RPUSH nvt:%s %s %s %s %s %s %s %s %s %s %s %s %d %d %s %s", + kbr, "RPUSH nvt:%s %s %s %s %s %s %s %s %s %s %s %d %d %s %s", nvti_oid (nvt), filename, nvti_required_keys (nvt) ?: "", nvti_mandatory_keys (nvt) ?: "", nvti_excluded_keys (nvt) ?: "", nvti_required_udp_ports (nvt) ?: "", nvti_required_ports (nvt) ?: "", nvti_dependencies (nvt) ?: "", nvti_tag (nvt) ?: "", cves ?: "", bids ?: "", - xrefs ?: "", nvti_category (nvt), nvti_timeout (nvt), nvti_family (nvt), + xrefs ?: "", nvti_category (nvt), nvti_family (nvt), nvti_name (nvt)); g_free (cves); g_free (bids); diff --git a/util/kb.h b/util/kb.h index a14609e24..63767de4f 100644 --- a/util/kb.h +++ b/util/kb.h @@ -69,7 +69,6 @@ enum kb_nvt_pos NVT_BIDS_POS, NVT_XREFS_POS, NVT_CATEGORY_POS, - NVT_TIMEOUT_POS, NVT_FAMILY_POS, NVT_NAME_POS, NVT_TIMESTAMP_POS, From ff415bd49bec4826d5ef7701db819dff3c55f7e4 Mon Sep 17 00:00:00 2001 From: Juan Jose Nicola Date: Thu, 12 Aug 2021 08:42:23 -0500 Subject: [PATCH 16/23] Remove nvticache_get_timeout() The timeout must be get from script preferences. It was currently not used by libs or scanner. --- util/nvticache.c | 20 -------------------- util/nvticache.h | 3 --- 2 files changed, 23 deletions(-) diff --git a/util/nvticache.c b/util/nvticache.c index 2a3f1b22e..0840a5d64 100644 --- a/util/nvticache.c +++ b/util/nvticache.c @@ -410,26 +410,6 @@ nvticache_get_category (const char *oid) return category; } -/** - * @brief Get the Timeout from a plugin OID. - * - * @param[in] oid OID to match. - * - * @return Timeout matching OID, -1 otherwise. - */ -int -nvticache_get_timeout (const char *oid) -{ - int timeout; - char *timeout_s; - - assert (cache_kb); - timeout_s = kb_nvt_get (cache_kb, oid, NVT_TIMEOUT_POS); - timeout = atoi (timeout_s); - g_free (timeout_s); - return timeout; -} - /** * @brief Get the name from a plugin OID. * diff --git a/util/nvticache.h b/util/nvticache.h index 6bbbf71a6..62f5cd506 100644 --- a/util/nvticache.h +++ b/util/nvticache.h @@ -105,9 +105,6 @@ nvticache_get_required_udp_ports (const char *); int nvticache_get_category (const char *); -int -nvticache_get_timeout (const char *); - char * nvticache_get_dependencies (const char *); From 695c5d8e0bc6d1de7c56387513b44bbf8a7f1a3d Mon Sep 17 00:00:00 2001 From: Juan Jose Nicola Date: Thu, 12 Aug 2021 09:34:39 -0500 Subject: [PATCH 17/23] Define fixed ID for the timeout nvt preference. --- base/nvti.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/base/nvti.h b/base/nvti.h index f228995f5..6e3dd6daa 100644 --- a/base/nvti.h +++ b/base/nvti.h @@ -29,6 +29,8 @@ #include +#define NVTPREF_TIMEOUT_ID 0 + typedef struct nvtpref nvtpref_t; nvtpref_t * From fa1bc0765810384302012b65bda7d7f6be3a9c15 Mon Sep 17 00:00:00 2001 From: Juan Jose Nicola Date: Thu, 12 Aug 2021 09:45:41 -0500 Subject: [PATCH 18/23] Fix format --- util/kb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/util/kb.c b/util/kb.c index 0f533887b..d061eb374 100644 --- a/util/kb.c +++ b/util/kb.c @@ -1564,8 +1564,7 @@ redis_add_nvt (kb_t kb, const nvti_t *nvt, const char *filename) nvti_mandatory_keys (nvt) ?: "", nvti_excluded_keys (nvt) ?: "", nvti_required_udp_ports (nvt) ?: "", nvti_required_ports (nvt) ?: "", nvti_dependencies (nvt) ?: "", nvti_tag (nvt) ?: "", cves ?: "", bids ?: "", - xrefs ?: "", nvti_category (nvt), nvti_family (nvt), - nvti_name (nvt)); + xrefs ?: "", nvti_category (nvt), nvti_family (nvt), nvti_name (nvt)); g_free (cves); g_free (bids); g_free (xrefs); From 557083bc7236a82dca6abd72ec36461676e9913a Mon Sep 17 00:00:00 2001 From: Juan Jose Nicola Date: Fri, 13 Aug 2021 02:04:46 -0500 Subject: [PATCH 19/23] Fix type when add nvt to redis --- util/kb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/kb.c b/util/kb.c index d061eb374..f6f1f30a9 100644 --- a/util/kb.c +++ b/util/kb.c @@ -1559,7 +1559,7 @@ redis_add_nvt (kb_t kb, const nvti_t *nvt, const char *filename) kbr = redis_kb (kb); rep = redis_cmd ( - kbr, "RPUSH nvt:%s %s %s %s %s %s %s %s %s %s %s %d %d %s %s", + kbr, "RPUSH nvt:%s %s %s %s %s %s %s %s %s %s %s %s %d %s %s", nvti_oid (nvt), filename, nvti_required_keys (nvt) ?: "", nvti_mandatory_keys (nvt) ?: "", nvti_excluded_keys (nvt) ?: "", nvti_required_udp_ports (nvt) ?: "", nvti_required_ports (nvt) ?: "", From 922b77ea18e93f70f2c964b4d16557b12494da2a Mon Sep 17 00:00:00 2001 From: Juan Jose Nicola Date: Mon, 16 Aug 2021 02:08:17 -0500 Subject: [PATCH 20/23] Remove prefs_nvt_timeout --- base/prefs.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/base/prefs.c b/base/prefs.c index 083ecc2b0..8d88d68ee 100644 --- a/base/prefs.c +++ b/base/prefs.c @@ -203,23 +203,3 @@ prefs_dump (void) } } } - -/** - * @brief Returns the timeout defined by the client or 0 if none was set. - * - * @param oid OID of NVT to ask timeout value of. - * - * @return 0 if no timeout for the NVT oid was found, timeout in seconds - * otherwise. - */ -int -prefs_nvt_timeout (const char *oid) -{ - char *pref_name = g_strdup_printf ("timeout.%s", oid); - const char *val = prefs_get (pref_name); - int timeout = (val ? atoi (val) : 0); - - g_free (pref_name); - - return timeout; -} From a31972912b3a6929e59ace87086a6eff41bfa271 Mon Sep 17 00:00:00 2001 From: Juan Jose Nicola Date: Mon, 16 Aug 2021 05:27:18 -0500 Subject: [PATCH 21/23] Update Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e1bf286a..84c350f3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed - Refactor MQTT handling [#562](https://github.com/greenbone/gvm-libs/pull/562) +- Handle script timeout as script preference with ID 0 [#578](https://github.com/greenbone/gvm-libs/pull/578) ### Fixed ### Removed From 827d671e19ba41ce60f6988379b28517b1fb9939 Mon Sep 17 00:00:00 2001 From: Juan Jose Nicola Date: Wed, 1 Sep 2021 07:11:04 -0500 Subject: [PATCH 22/23] Fix prototype Avoid warning/error when the compiler uses the -Werror=strict-prototypes flag --- CHANGELOG.md | 2 ++ util/mqtt.h | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84c350f3d..dce544be7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Handle script timeout as script preference with ID 0 [#578](https://github.com/greenbone/gvm-libs/pull/578) ### Fixed +- Fix prototypes in mqtt.h. [#584](https://github.com/greenbone/gvm-libs/pull/584) + ### Removed ## [21.10] (unreleased) diff --git a/util/mqtt.h b/util/mqtt.h index e92173899..bb57365ce 100644 --- a/util/mqtt.h +++ b/util/mqtt.h @@ -32,10 +32,10 @@ int mqtt_init (const char *); gboolean -mqtt_is_initialized (); +mqtt_is_initialized (void); void -mqtt_reset (); +mqtt_reset (void); int mqtt_publish (const char *, const char *); From 8ff2a3a8bb28516f342faa4509bae14f5f136a93 Mon Sep 17 00:00:00 2001 From: Christoph Kraemer Date: Tue, 28 Sep 2021 12:04:29 +0200 Subject: [PATCH 23/23] duplicate function for host and vhost --- CHANGELOG.md | 1 + base/hosts.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ base/hosts.h | 5 +++++ 3 files changed, 65 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dce544be7..00fa8b390 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#538](https://github.com/greenbone/gvm-libs/pull/538) - Add function for mqtt init status [#567](https://github.com/greenbone/gvm-libs/pull/567) - Add function to get the severity_vector, otherwise the cvss_base_vector. [#568](https://github.com/greenbone/gvm-libs/pull/568) +- Add function to duplicate host and vhost objects [#590](https://github.com/greenbone/gvm-libs/pull/590) ### Changed diff --git a/base/hosts.c b/base/hosts.c index b252b6b93..fd4a3f588 100644 --- a/base/hosts.c +++ b/base/hosts.c @@ -908,6 +908,28 @@ gvm_vhost_free (gpointer vhost) g_free (vhost); } +/** + * @brief Creates a deep copy of a gvm_vhost_t object. + * + * @param vhost source vhost + * @param data dummy for g_slist_copy_deep + * @return gpointer copy of vhost + */ +gpointer +gvm_duplicate_vhost (gconstpointer vhost, gpointer data) +{ + (void) (data); + gvm_vhost_t *ret = NULL; + + if (!vhost) + return NULL; + + ret = gvm_vhost_new (g_strdup (((gvm_vhost_t *) vhost)->value), + g_strdup (((gvm_vhost_t *) vhost)->source)); + + return ret; +} + /** * @brief Creates a new gvm_host_t object. * @@ -1986,6 +2008,43 @@ gvm_host_find_in_hosts (const gvm_host_t *host, const struct in6_addr *addr, return NULL; } +/** + * @brief Creates a deep copy of a host. gvm_host_free has to be called on it. + * + * @param host source host + * @return gvm_host_t* copy of host + */ +gvm_host_t * +gvm_duplicate_host (gvm_host_t *host) +{ + gvm_host_t *ret = NULL; + + if (host == NULL) + return NULL; + + ret = gvm_host_new (); + + ret->type = host->type; + switch (host->type) + { + case HOST_TYPE_NAME: + ret->name = g_strdup (host->name); + break; + case HOST_TYPE_IPV4: + ret->addr.s_addr = host->addr.s_addr; + break; + case HOST_TYPE_IPV6: + ret->addr6.__in6_u = host->addr6.__in6_u; + break; + default: + g_free (ret); + return NULL; + } + ret->vhosts = g_slist_copy_deep (host->vhosts, gvm_duplicate_vhost, NULL); + + return ret; +} + /** * @brief Returns whether a host has an equal host in a hosts collection. * eg. 192.168.10.1 has an equal in list created from diff --git a/base/hosts.h b/base/hosts.h index d8268b424..1689f6bf7 100644 --- a/base/hosts.h +++ b/base/hosts.h @@ -189,6 +189,11 @@ gvm_host_add_reverse_lookup (gvm_host_t *); void gvm_host_free (gpointer); +gpointer gvm_duplicate_vhost (gconstpointer, gpointer); + +gvm_host_t * +gvm_duplicate_host (gvm_host_t *); + /* Miscellaneous functions */ gvm_vhost_t *