ulogd: Backport JSON network patch
authorRosen Penev <rosenp@gmail.com>
Mon, 29 Jul 2019 00:59:10 +0000 (17:59 -0700)
committerRosen Penev <rosenp@gmail.com>
Wed, 31 Jul 2019 22:33:00 +0000 (15:33 -0700)
It was requested in #9065 .

Cleaned up Makefile slightly.

Removed inactive maintainer.

Added PKG_BUILD_PARALLEL for faster compilation.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
(cherry-picked from 23a36b00e243137d50b8c6c0edd58f4446b6714e)

net/ulogd/Makefile
net/ulogd/patches/010-json-remote.patch [new file with mode: 0644]

index 201f05f25456a94f1c4de5f28b9ef07c7c70e0cc..8a6ffabb09cedb882a04faf4b33e039a5034b450 100644 (file)
@@ -9,26 +9,33 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=ulogd
 PKG_VERSION:=2.0.7
-PKG_RELEASE:=1
+PKG_RELEASE:=2
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
 PKG_SOURCE_URL:=https://netfilter.org/projects/ulogd/files/ \
        ftp://ftp.netfilter.org/pub/ulogd/
 PKG_HASH:=990a05494d9c16029ba0a83f3b7294fc05c756546b8d60d1c1572dc25249a92b
 
-PKG_LICENSE:=GPL-2.0
+PKG_MAINTAINER:=
+PKG_LICENSE:=GPL-2.0-only
 PKG_LICENSE_FILES:=COPYING
-PKG_MAINTAINER:=Nicolas Thill <nico@openwrt.org>
 
-PKG_FIXUP:=autoreconf
 PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=1
+
+PKG_BUILD_DEPENDS:=libnetfilter-acct libnetfilter-conntrack libnetfilter-log
+PKG_CONFIG_DEPENDS:= \
+       CONFIG_PACKAGE_ulogd-mod-dbi \
+       CONFIG_PACKAGE_ulogd-mod-mysql \
+       CONFIG_PACKAGE_ulogd-mod-pgsql \
+       CONFIG_PACKAGE_ulogd-mod-sqlite
 
 include $(INCLUDE_DIR)/package.mk
 
 define Package/ulogd/Default
   SECTION:=net
   CATEGORY:=Network
-  URL:=http://www.netfilter.org/projects/ulogd/index.html
+  URL:=https://www.netfilter.org/projects/ulogd/index.html
 endef
 
 define Package/ulogd
@@ -114,21 +121,10 @@ define Package/ulogd-mod-extra
   TITLE:=Extra plugins
 endef
 
-PKG_BUILD_DEPENDS:=libnetfilter-acct libnetfilter-conntrack libnetfilter-log
-
-PKG_CONFIG_DEPENDS:= \
-       CONFIG_PACKAGE_ulogd-mod-dbi \
-       CONFIG_PACKAGE_ulogd-mod-mysql \
-       CONFIG_PACKAGE_ulogd-mod-pgsql \
-       CONFIG_PACKAGE_ulogd-mod-sqlite \
-
-TARGET_CFLAGS += \
-       -D_GNU_SOURCE \
-
 CONFIGURE_ARGS += \
        --enable-nfacct \
        --enable-nfct \
-       --enable-nflog \
+       --enable-nflog
 
 ifneq ($(DEVELOPER)$(SDK)$(CONFIG_PACKAGE_ulogd-mod-dbi),)
        CONFIGURE_ARGS += --with-dbi \
diff --git a/net/ulogd/patches/010-json-remote.patch b/net/ulogd/patches/010-json-remote.patch
new file mode 100644 (file)
index 0000000..a250e06
--- /dev/null
@@ -0,0 +1,441 @@
+From 9d9ea2cd70a369a7f665a322e6c53631e01a2570 Mon Sep 17 00:00:00 2001
+From: Andreas Jaggi <andreas.jaggi@waterwave.ch>
+Date: Wed, 30 May 2018 22:15:36 +0200
+Subject: ulogd: json: send messages to a remote host / unix socket
+
+Extend the JSON output plugin so that the generated JSON stream can be
+sent to a remote host via TCP/UDP or to a local unix socket.
+
+Signed-off-by: Andreas Jaggi <andreas.jaggi@waterwave.ch>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+---
+ output/ulogd_output_JSON.c | 291 +++++++++++++++++++++++++++++++++++++++++----
+ ulogd.conf.in              |  11 ++
+ 2 files changed, 281 insertions(+), 21 deletions(-)
+
+diff --git a/output/ulogd_output_JSON.c b/output/ulogd_output_JSON.c
+index 4d8e3e9..6edfa90 100644
+--- a/output/ulogd_output_JSON.c
++++ b/output/ulogd_output_JSON.c
+@@ -20,10 +20,15 @@
+ #include <stdio.h>
+ #include <stdlib.h>
++#include <unistd.h>
+ #include <string.h>
+ #include <time.h>
+ #include <errno.h>
+ #include <inttypes.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <netdb.h>
+ #include <ulogd/ulogd.h>
+ #include <ulogd/conffile.h>
+ #include <jansson.h>
+@@ -36,6 +41,10 @@
+ #define ULOGD_JSON_DEFAULT_DEVICE "Netfilter"
+ #endif
++#define host_ce(x)    (x->ces[JSON_CONF_HOST])
++#define port_ce(x)    (x->ces[JSON_CONF_PORT])
++#define mode_ce(x)    (x->ces[JSON_CONF_MODE])
++#define file_ce(x)    (x->ces[JSON_CONF_FILENAME])
+ #define unlikely(x) __builtin_expect((x),0)
+ struct json_priv {
+@@ -44,6 +53,15 @@ struct json_priv {
+       int usec_idx;
+       long cached_gmtoff;
+       char cached_tz[6];      /* eg +0200 */
++      int mode;
++      int sock;
++};
++
++enum json_mode {
++      JSON_MODE_FILE = 0,
++      JSON_MODE_TCP,
++      JSON_MODE_UDP,
++      JSON_MODE_UNIX
+ };
+ enum json_conf {
+@@ -53,6 +71,9 @@ enum json_conf {
+       JSON_CONF_EVENTV1,
+       JSON_CONF_DEVICE,
+       JSON_CONF_BOOLEAN_LABEL,
++      JSON_CONF_MODE,
++      JSON_CONF_HOST,
++      JSON_CONF_PORT,
+       JSON_CONF_MAX
+ };
+@@ -95,15 +116,167 @@ static struct config_keyset json_kset = {
+                       .options = CONFIG_OPT_NONE,
+                       .u = { .value = 0 },
+               },
++              [JSON_CONF_MODE] = {
++                      .key = "mode",
++                      .type = CONFIG_TYPE_STRING,
++                      .options = CONFIG_OPT_NONE,
++                      .u = { .string = "file" },
++              },
++              [JSON_CONF_HOST] = {
++                      .key = "host",
++                      .type = CONFIG_TYPE_STRING,
++                      .options = CONFIG_OPT_NONE,
++                      .u = { .string = "127.0.0.1" },
++              },
++              [JSON_CONF_PORT] = {
++                      .key = "port",
++                      .type = CONFIG_TYPE_STRING,
++                      .options = CONFIG_OPT_NONE,
++                      .u = { .string = "12345" },
++              },
+       },
+ };
++static void close_socket(struct json_priv *op) {
++      if (op->sock != -1) {
++              close(op->sock);
++              op->sock = -1;
++      }
++}
++
++static int _connect_socket_unix(struct ulogd_pluginstance *pi)
++{
++      struct json_priv *op = (struct json_priv *) &pi->private;
++      struct sockaddr_un u_addr;
++      int sfd;
++
++      close_socket(op);
++
++      ulogd_log(ULOGD_DEBUG, "connecting to unix:%s\n",
++                file_ce(pi->config_kset).u.string);
++
++      sfd = socket(AF_UNIX, SOCK_STREAM, 0);
++      if (sfd == -1) {
++              return -1;
++      }
++      u_addr.sun_family = AF_UNIX;
++      strncpy(u_addr.sun_path, file_ce(pi->config_kset).u.string,
++              sizeof(u_addr.sun_path) - 1);
++      if (connect(sfd, (struct sockaddr *) &u_addr, sizeof(struct sockaddr_un)) == -1) {
++              close(sfd);
++              return -1;
++      }
++
++      op->sock = sfd;
++
++      return 0;
++}
++
++static int _connect_socket_net(struct ulogd_pluginstance *pi)
++{
++      struct json_priv *op = (struct json_priv *) &pi->private;
++      struct addrinfo hints;
++      struct addrinfo *result, *rp;
++      int sfd, s;
++
++      close_socket(op);
++
++      ulogd_log(ULOGD_DEBUG, "connecting to %s:%s\n",
++                host_ce(pi->config_kset).u.string,
++                port_ce(pi->config_kset).u.string);
++
++      memset(&hints, 0, sizeof(struct addrinfo));
++      hints.ai_family = AF_UNSPEC;
++      hints.ai_socktype = op->mode == JSON_MODE_UDP ? SOCK_DGRAM : SOCK_STREAM;
++      hints.ai_protocol = 0;
++      hints.ai_flags = 0;
++
++      s = getaddrinfo(host_ce(pi->config_kset).u.string,
++                      port_ce(pi->config_kset).u.string, &hints, &result);
++      if (s != 0) {
++              ulogd_log(ULOGD_ERROR, "getaddrinfo: %s\n", gai_strerror(s));
++              return -1;
++      }
++
++      for (rp = result; rp != NULL; rp = rp->ai_next) {
++              int on = 1;
++
++              sfd = socket(rp->ai_family, rp->ai_socktype,
++                              rp->ai_protocol);
++              if (sfd == -1)
++                      continue;
++
++              setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR,
++                         (char *) &on, sizeof(on));
++
++              if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
++                      break;
++
++              close(sfd);
++      }
++
++      freeaddrinfo(result);
++
++      if (rp == NULL) {
++              return -1;
++      }
++
++      op->sock = sfd;
++
++      return 0;
++}
++
++static int _connect_socket(struct ulogd_pluginstance *pi)
++{
++      struct json_priv *op = (struct json_priv *) &pi->private;
++
++      if (op->mode == JSON_MODE_UNIX)
++              return _connect_socket_unix(pi);
++      else
++              return _connect_socket_net(pi);
++}
++
++static int json_interp_socket(struct ulogd_pluginstance *upi, char *buf, int buflen)
++{
++      struct json_priv *opi = (struct json_priv *) &upi->private;
++      int ret = 0;
++
++      if (opi->sock != -1)
++              ret = send(opi->sock, buf, buflen, MSG_NOSIGNAL);
++      free(buf);
++      if (ret != buflen) {
++              ulogd_log(ULOGD_ERROR, "Failure sending message: %s\n",
++                        strerror(errno));
++              if (ret == -1 || opi->sock == -1)
++                      return _connect_socket(upi);
++              else
++                      return ULOGD_IRET_ERR;
++      }
++
++      return ULOGD_IRET_OK;
++}
++
++static int json_interp_file(struct ulogd_pluginstance *upi, char *buf)
++{
++      struct json_priv *opi = (struct json_priv *) &upi->private;
++
++      fprintf(opi->of, "%s", buf);
++      free(buf);
++
++      if (upi->config_kset->ces[JSON_CONF_SYNC].u.value != 0)
++              fflush(opi->of);
++
++      return ULOGD_IRET_OK;
++}
++
+ #define MAX_LOCAL_TIME_STRING 38
+ static int json_interp(struct ulogd_pluginstance *upi)
+ {
+       struct json_priv *opi = (struct json_priv *) &upi->private;
+       unsigned int i;
++      char *buf;
++      int buflen;
+       json_t *msg;
+       msg = json_object();
+@@ -218,34 +391,65 @@ static int json_interp(struct ulogd_pluginstance *upi)
+               }
+       }
+-      json_dumpf(msg, opi->of, 0);
+-      fprintf(opi->of, "\n");
++      buf = json_dumps(msg, 0);
+       json_decref(msg);
++      if (buf == NULL) {
++              ulogd_log(ULOGD_ERROR, "Could not create message\n");
++              return ULOGD_IRET_ERR;
++      }
++      buflen = strlen(buf);
++      buf = realloc(buf, sizeof(char)*(buflen+2));
++      if (buf == NULL) {
++              ulogd_log(ULOGD_ERROR, "Could not create message\n");
++              return ULOGD_IRET_ERR;
++      }
++      strncat(buf, "\n", 1);
++      buflen++;
+-      if (upi->config_kset->ces[JSON_CONF_SYNC].u.value != 0)
+-              fflush(opi->of);
++      if (opi->mode == JSON_MODE_FILE)
++              return json_interp_file(upi, buf);
++      else
++              return json_interp_socket(upi, buf, buflen);
++}
+-      return ULOGD_IRET_OK;
++static void reopen_file(struct ulogd_pluginstance *upi)
++{
++      struct json_priv *oi = (struct json_priv *) &upi->private;
++      FILE *old = oi->of;
++
++      ulogd_log(ULOGD_NOTICE, "JSON: reopening logfile\n");
++      oi->of = fopen(upi->config_kset->ces[0].u.string, "a");
++      if (!oi->of) {
++              ulogd_log(ULOGD_ERROR, "can't open JSON "
++                                     "log file: %s\n",
++                        strerror(errno));
++              oi->of = old;
++      } else {
++              fclose(old);
++      }
++}
++
++static void reopen_socket(struct ulogd_pluginstance *upi)
++{
++      ulogd_log(ULOGD_NOTICE, "JSON: reopening socket\n");
++      if (_connect_socket(upi) < 0) {
++              ulogd_log(ULOGD_ERROR, "can't open JSON "
++                                     "socket: %s\n",
++                        strerror(errno));
++      }
+ }
+ static void sighup_handler_print(struct ulogd_pluginstance *upi, int signal)
+ {
+       struct json_priv *oi = (struct json_priv *) &upi->private;
+-      FILE *old = oi->of;
+       switch (signal) {
+       case SIGHUP:
+-              ulogd_log(ULOGD_NOTICE, "JSON: reopening logfile\n");
+-              oi->of = fopen(upi->config_kset->ces[0].u.string, "a");
+-              if (!oi->of) {
+-                      ulogd_log(ULOGD_ERROR, "can't open JSON "
+-                                             "log file: %s\n",
+-                                strerror(errno));
+-                      oi->of = old;
+-              } else {
+-                      fclose(old);
+-              }
++              if (oi->mode == JSON_MODE_FILE)
++                      reopen_file(upi);
++              else
++                      reopen_socket(upi);
+               break;
+       default:
+               break;
+@@ -255,6 +459,8 @@ static void sighup_handler_print(struct ulogd_pluginstance *upi, int signal)
+ static int json_configure(struct ulogd_pluginstance *upi,
+                           struct ulogd_pluginstance_stack *stack)
+ {
++      struct json_priv *op = (struct json_priv *) &upi->private;
++      char *mode_str = mode_ce(upi->config_kset).u.string;
+       int ret;
+       ret = ulogd_wildcard_inputkeys(upi);
+@@ -265,13 +471,25 @@ static int json_configure(struct ulogd_pluginstance *upi,
+       if (ret < 0)
+               return ret;
++      if (!strcasecmp(mode_str, "udp")) {
++              op->mode = JSON_MODE_UDP;
++      } else if (!strcasecmp(mode_str, "tcp")) {
++              op->mode = JSON_MODE_TCP;
++      } else if (!strcasecmp(mode_str, "unix")) {
++              op->mode = JSON_MODE_UNIX;
++      } else if (!strcasecmp(mode_str, "file")) {
++              op->mode = JSON_MODE_FILE;
++      } else {
++              ulogd_log(ULOGD_ERROR, "unknown mode '%s'\n", mode_str);
++              return -EINVAL;
++      }
++
+       return 0;
+ }
+-static int json_init(struct ulogd_pluginstance *upi)
++static int json_init_file(struct ulogd_pluginstance *upi)
+ {
+       struct json_priv *op = (struct json_priv *) &upi->private;
+-      unsigned int i;
+       op->of = fopen(upi->config_kset->ces[0].u.string, "a");
+       if (!op->of) {
+@@ -280,6 +498,27 @@ static int json_init(struct ulogd_pluginstance *upi)
+               return -1;
+       }
++      return 0;
++}
++
++static int json_init_socket(struct ulogd_pluginstance *upi)
++{
++      struct json_priv *op = (struct json_priv *) &upi->private;
++
++      if (host_ce(upi->config_kset).u.string == NULL)
++              return -1;
++      if (port_ce(upi->config_kset).u.string == NULL)
++              return -1;
++
++      op->sock = -1;
++      return _connect_socket(upi);
++}
++
++static int json_init(struct ulogd_pluginstance *upi)
++{
++      struct json_priv *op = (struct json_priv *) &upi->private;
++      unsigned int i;
++
+       /* search for time */
+       op->sec_idx = -1;
+       op->usec_idx = -1;
+@@ -293,15 +532,25 @@ static int json_init(struct ulogd_pluginstance *upi)
+       *op->cached_tz = '\0';
+-      return 0;
++      if (op->mode == JSON_MODE_FILE)
++              return json_init_file(upi);
++      else
++              return json_init_socket(upi);
++}
++
++static void close_file(FILE *of) {
++      if (of != stdout)
++              fclose(of);
+ }
+ static int json_fini(struct ulogd_pluginstance *pi)
+ {
+       struct json_priv *op = (struct json_priv *) &pi->private;
+-      if (op->of != stdout)
+-              fclose(op->of);
++      if (op->mode == JSON_MODE_FILE)
++              close_file(op->of);
++      else
++              close_socket(op);
+       return 0;
+ }
+diff --git a/ulogd.conf.in b/ulogd.conf.in
+index 62222db..99cfc24 100644
+--- a/ulogd.conf.in
++++ b/ulogd.conf.in
+@@ -213,6 +213,17 @@ sync=1
+ # Uncomment the following line to use JSON v1 event format that
+ # can provide better compatility with some JSON file reader.
+ #eventv1=1
++# Uncomment the following lines to send the JSON logs to a remote host via UDP
++#mode="udp"
++#host="192.0.2.10"
++#port="10210"
++# Uncomment the following lines to send the JSON logs to a remote host via TCP
++#mode="tcp"
++#host="192.0.2.10"
++#port="10210"
++# Uncomment the following lines to send the JSON logs to a local unix socket
++#mode="unix"
++#file="/var/run/ulogd.socket"
+ [pcap1]
+ #default file is /var/log/ulogd.pcap
+-- 
+cgit v1.2.1
+