From 23a36b00e243137d50b8c6c0edd58f4446b6714e Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sun, 28 Jul 2019 17:59:10 -0700 Subject: [PATCH] ulogd: Backport JSON network patch It was requested in #9065 . Cleaned up Makefile slightly. Removed inactive maintainer. Added PKG_BUILD_PARALLEL for faster compilation. Signed-off-by: Rosen Penev --- net/ulogd/Makefile | 30 +- net/ulogd/patches/010-json-remote.patch | 441 ++++++++++++++++++++++++ 2 files changed, 454 insertions(+), 17 deletions(-) create mode 100644 net/ulogd/patches/010-json-remote.patch diff --git a/net/ulogd/Makefile b/net/ulogd/Makefile index 201f05f254..8a6ffabb09 100644 --- a/net/ulogd/Makefile +++ b/net/ulogd/Makefile @@ -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 -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 index 0000000000..a250e06312 --- /dev/null +++ b/net/ulogd/patches/010-json-remote.patch @@ -0,0 +1,441 @@ +From 9d9ea2cd70a369a7f665a322e6c53631e01a2570 Mon Sep 17 00:00:00 2001 +From: Andreas Jaggi +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 +Signed-off-by: Pablo Neira Ayuso +--- + 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 + #include ++#include + #include + #include + #include + #include ++#include ++#include ++#include ++#include + #include + #include + #include +@@ -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 + -- 2.30.2