From b2802ee5082902d6a7599ad25f99fcd588e48eeb Mon Sep 17 00:00:00 2001 From: jikui Date: Sat, 30 Jan 2021 17:14:31 +0800 Subject: [PATCH] support remote syslog Signed-off-by: jikui --- 0020-support-remote-syslog.patch | 679 +++++++++++++++++++++++++++++++ lxc.spec | 9 +- 2 files changed, 687 insertions(+), 1 deletion(-) create mode 100644 0020-support-remote-syslog.patch diff --git a/0020-support-remote-syslog.patch b/0020-support-remote-syslog.patch new file mode 100644 index 0000000..b4fa48e --- /dev/null +++ b/0020-support-remote-syslog.patch @@ -0,0 +1,679 @@ +From 0de8398a660f95e85140cfb4037c0b3eaaa65402 Mon Sep 17 00:00:00 2001 +From: jikui +Date: Wed, 3 Feb 2021 16:07:55 +0800 +Subject: [PATCH] support remote syslog + +Signed-off-by: jikui +--- + src/lxc/Makefile.am | 6 +- + src/lxc/confile.c | 26 +++ + src/lxc/remote_syslog.c | 433 ++++++++++++++++++++++++++++++++++++++++ + src/lxc/remote_syslog.h | 21 ++ + src/lxc/terminal.c | 40 ++-- + src/lxc/terminal.h | 6 + + 6 files changed, 518 insertions(+), 14 deletions(-) + create mode 100644 src/lxc/remote_syslog.c + create mode 100644 src/lxc/remote_syslog.h + +diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am +index dc49c7e..4ef3196 100644 +--- a/src/lxc/Makefile.am ++++ b/src/lxc/Makefile.am +@@ -59,7 +59,8 @@ noinst_HEADERS += isulad_utils.h path.h \ + json/logger_json_file.h \ + json/oci_runtime_spec.h \ + json/read-file.h \ +- exec_commands.h ++ exec_commands.h \ ++ remote_syslog.h + endif + + if IS_BIONIC +@@ -174,7 +175,8 @@ liblxc_la_SOURCES += isulad_utils.c isulad_utils.h \ + json/oci_runtime_spec.c json/oci_runtime_spec.h \ + json/read-file.c json/read-file.h \ + cgroups/isulad_cgfsng.c \ +- exec_commands.c exec_commands.h ++ exec_commands.c exec_commands.h \ ++ remote_syslog.c remote_syslog.h + + else + liblxc_la_SOURCES += cgroups/cgfsng.c +diff --git a/src/lxc/confile.c b/src/lxc/confile.c +index f108b37..4cf58ba 100644 +--- a/src/lxc/confile.c ++++ b/src/lxc/confile.c +@@ -158,6 +158,7 @@ lxc_config_define(systemd); + lxc_config_define(console_log_driver); + lxc_config_define(console_syslog_tag); + lxc_config_define(console_syslog_facility); ++lxc_config_define(console_syslog_address); + lxc_config_define(selinux_mount_context); + #endif + +@@ -283,6 +284,7 @@ static struct lxc_config_t config_jump_table[] = { + { "lxc.console.logdriver", set_config_console_log_driver, get_config_console_log_driver, clr_config_console_log_driver, }, + { "lxc.console.syslog_tag", set_config_console_syslog_tag, get_config_console_syslog_tag, clr_config_console_syslog_tag, }, + { "lxc.console.syslog_facility", set_config_console_syslog_facility, get_config_console_syslog_facility, clr_config_console_syslog_facility, }, ++ { "lxc.console.syslog_address", set_config_console_syslog_address, get_config_console_syslog_address, clr_config_console_syslog_address, }, + { "lxc.selinux.mount_context", set_config_selinux_mount_context, get_config_selinux_mount_context, clr_config_selinux_mount_context, }, + #endif + }; +@@ -6687,6 +6689,16 @@ static int set_config_console_syslog_facility(const char *key, const char *value + return 0; + } + ++static int set_config_console_syslog_address(const char *key, const char *value, ++ struct lxc_conf *lxc_conf, void *data) ++{ ++ if (value == NULL) { ++ return -1; ++ } ++ ++ return set_config_string_item(&lxc_conf->console.log_address, value); ++} ++ + static int set_config_selinux_mount_context(const char *key, const char *value, + struct lxc_conf *lxc_conf, void *data) + { +@@ -6715,6 +6727,12 @@ static int get_config_console_syslog_facility(const char *key, char *retv, int i + return lxc_get_conf_int(c, retv, inlen, c->console.log_syslog_facility); + } + ++static int get_config_console_syslog_address(const char *key, char *retv, int inlen, ++ struct lxc_conf *c, void *data) ++{ ++ return lxc_get_conf_str(retv, inlen, c->console.log_address); ++} ++ + static int get_config_selinux_mount_context(const char *key, char *retv, int inlen, + struct lxc_conf *c, void *data) + { +@@ -6744,6 +6762,14 @@ static inline int clr_config_console_syslog_facility(const char *key, + return 0; + } + ++static inline int clr_config_console_syslog_address(const char *key, ++ struct lxc_conf *c, void *data) ++{ ++ free(c->console.log_address); ++ c->console.log_address = NULL; ++ return 0; ++} ++ + static inline int clr_config_selinux_mount_context(const char *key, + struct lxc_conf *c, void *data) + { +diff --git a/src/lxc/remote_syslog.c b/src/lxc/remote_syslog.c +new file mode 100644 +index 0000000..a9e8ff5 +--- /dev/null ++++ b/src/lxc/remote_syslog.c +@@ -0,0 +1,433 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2021. Allrights reserved ++ * Description: isulad remote syslog ++ * Author: jikui ++ * Create: 2021-01-28 ++******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "remote_syslog.h" ++#include "log.h" ++ ++#pragma GCC diagnostic ignored "-Wformat-nonliteral" ++ ++#define ADDRESS_REGEX \ ++ "^[a-zA-Z]{3}(\\+)?[a-zA-Z]{0,3}:\\/\\/[0-9a-zA-Z.-]+:([0-9]{1,5}|syslog)$" ++ ++struct log_info { ++ int pri; ++ char *tag; ++ char *msg; ++}; ++ ++lxc_log_define(remote_syslog, lxc); ++ ++static int parse_type(const char *str, char **type) ++{ ++ if (str == NULL) { ++ return -1; ++ } ++ ++ if (strcasecmp(str, "tcp") == 0) { ++ *type = strdup("tcp"); ++ } else if (strcasecmp(str, "udp") == 0) { ++ *type = strdup("udp"); ++ } else if (strcasecmp(str, "tcp+tls") == 0) { ++ *type = strdup("tcp"); ++ } else { ++ return -1; ++ } ++ ++ if (*type == NULL) { ++ ERROR("Out of memory"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int parse_ip(const char *str, char **ip) ++{ ++ if (str == NULL) { ++ return -1; ++ } ++ ++ str += 2; ++ if ((*ip = strdup(str)) == NULL) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int parse_port(const char *str, char **port) ++{ ++ if (str == NULL) { ++ return -1; ++ } ++ ++ if ((*port = strdup(str)) == NULL) { ++ return -1; ++ } ++ return 0; ++} ++ ++static int valid_address(const char *address) ++{ ++#define MATCH_NUM 1 ++ int status = 0; ++ regmatch_t pmatch[MATCH_NUM] = { { 0 } }; ++ regex_t reg; ++ ++ regcomp(®, ADDRESS_REGEX, REG_EXTENDED); ++ status = regexec(®, address, MATCH_NUM, pmatch, 0); ++ regfree(®); ++ ++ if (status != 0) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int parse_address(const char *address, char **type, char **ip, char **port) ++{ ++ int ret = 0; ++ char *tmp_address = NULL; ++ char *p = NULL; ++ ++ if (valid_address(address) != 0) { ++ ERROR("Not valid address"); ++ return -1; ++ } ++ ++ if ((tmp_address = strdup(address)) == NULL) { ++ ERROR("Out of memory!"); ++ return -1; ++ } ++ ++ p = strtok(tmp_address, ":"); ++ if (parse_type(p, type) != 0) { ++ ERROR("Unknown socket type!"); ++ ret = -1; ++ goto out; ++ } ++ ++ p = strtok(NULL, ":"); ++ if (parse_ip(p, ip) != 0) { ++ ERROR("Iligal ip address!"); ++ ret = -1; ++ goto out; ++ } ++ ++ p = strtok(NULL, ":"); ++ if (parse_port(p, port) != 0) { ++ ERROR("Iligal port!"); ++ ret = -1; ++ goto out; ++ } ++ ++out: ++ free(tmp_address); ++ return ret; ++} ++ ++ ++static int do_init(const char *type, const char *ip, const char *port) ++{ ++ struct addrinfo hints; ++ struct addrinfo *res = NULL; ++ int sock = -1; ++ int ret = 0; ++ ++ if(type == NULL || ip == NULL || port == NULL) { ++ ERROR("Para error!"); ++ ret = -1; ++ goto out; ++ } ++ ++ memset(&hints, 0, sizeof(hints)); ++ if (strcmp(type, "udp") == 0) { ++ hints.ai_socktype = SOCK_DGRAM; ++ } else { ++ hints.ai_socktype = SOCK_STREAM; ++ } ++ ++ hints.ai_family = AF_UNSPEC; ++ getaddrinfo(ip, port, &hints, &res); ++ ++ if (res == NULL) { ++ ret = -1; ++ goto out; ++ } ++ sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); ++ if (sock < 0) { ++ ERROR("Create sock err!"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (connect(sock, res->ai_addr, res->ai_addrlen) != 0) { ++ ERROR("Conn err!"); ++ ret = -1; ++ goto out; ++ } ++ ret = sock; ++ ++out: ++ freeaddrinfo(res); ++ return ret; ++} ++ ++static char *get_time() ++{ ++#define SYSLOG_TIME_BUFF_SIZE 50 ++ char *time = NULL; ++ struct timeval tv; ++ struct tm *tm = NULL; ++ char fmt[SYSLOG_TIME_BUFF_SIZE] = { 0 }; ++ size_t len = 0; ++ ++ gettimeofday(&tv, NULL); ++ if ((tm = localtime(&tv.tv_sec)) == NULL) { ++ ERROR("Get localtime error!"); ++ return NULL; ++ } ++ ++ len = strftime(fmt, sizeof(fmt), "%Y-%m-%dT%H:%M:%S.%%06u%z ", tm); ++ fmt[len - 1] = fmt[len - 2]; ++ fmt[len - 2] = fmt[len - 3]; ++ fmt[len - 3] = ':'; ++ ++ if ((time = (char *)calloc(SYSLOG_TIME_BUFF_SIZE, sizeof(char))) == NULL) { ++ ERROR("Out of memory!"); ++ goto out; ++ } ++ ++ if (snprintf(time, SYSLOG_TIME_BUFF_SIZE - 1, fmt, tv.tv_usec) <= 0) { ++ ERROR("Format time error"); ++ goto out; ++ } ++ ++ return time; ++ ++out: ++ free(time); ++ return NULL; ++} ++ ++static char *get_hostname_local() ++{ ++#define SYSLOG_HOSTNAME_BUFF_SIZE 256 ++ char *hostname = NULL; ++ if ((hostname = (char *)calloc(SYSLOG_HOSTNAME_BUFF_SIZE, sizeof(char))) == NULL) { ++ ERROR("Out of memory!"); ++ return NULL; ++ } ++ ++ gethostname(hostname, SYSLOG_HOSTNAME_BUFF_SIZE); ++ return hostname; ++} ++ ++static char *pack_head(const struct log_info *log) ++{ ++#define SYSLOG_COMMON_BUFF_SIZE (17 * 1024) ++ char *head = NULL; ++ char *hostname = NULL; ++ char *current_time = NULL; ++ ++ if ((hostname = get_hostname_local()) == NULL) { ++ hostname = strdup("-"); ++ } ++ ++ if ((current_time = get_time()) == NULL) { ++ current_time = strdup("-"); ++ } ++ ++ if ((head = (char *)calloc(SYSLOG_COMMON_BUFF_SIZE, sizeof(char))) == NULL) { ++ ERROR("Out of memory!"); ++ goto out; ++ } ++ ++ snprintf(head, SYSLOG_COMMON_BUFF_SIZE - 1, "<%d>1 %s %s %s %d %s %s ", ++ log->pri, ++ current_time, ++ hostname, ++ log->tag, ++ getpid(), ++ log->tag, ++ "-"); ++out: ++ free(current_time); ++ free(hostname); ++ return head; ++} ++ ++static struct msghdr *pack_msg(const struct log_info *log) ++{ ++ struct msghdr *message = NULL; ++ struct iovec *iov = NULL; ++ char *head = NULL; ++ char *msg = NULL; ++ int iovlen = 2; ++ ++ if ((message = (struct msghdr *)calloc(1, sizeof(struct msghdr))) == NULL) { ++ ERROR("Out of memory!"); ++ return NULL; ++ } ++ ++ if ((iov = (struct iovec *)calloc(iovlen, sizeof(struct iovec))) == NULL) { ++ ERROR("Out of merroy!"); ++ goto err_out; ++ } ++ ++ if ((head = pack_head(log)) == NULL) { ++ ERROR("Pack head error!"); ++ goto err_out; ++ } ++ ++ if ((msg = strdup(log->msg)) == NULL) { ++ ERROR("Out of memory!"); ++ goto err_out; ++ } ++ ++ iov[0].iov_base = (void *)head; ++ iov[0].iov_len = strlen(head); ++ iov[1].iov_base = (void *)msg; ++ iov[1].iov_len = strlen(msg); ++ message->msg_iov = iov; ++ message->msg_iovlen = iovlen; ++ return message; ++ ++err_out: ++ free(msg); ++ free(head); ++ free(iov); ++ free(message); ++ return NULL; ++} ++ ++static void do_free_msghdr(struct msghdr *message) ++{ ++ int i; ++ ++ for (i = 0; i < message->msg_iovlen; i++) { ++ free(message->msg_iov[i].iov_base); ++ message->msg_iov[i].iov_base = NULL; ++ } ++ free(message->msg_iov); ++ message->msg_iov = NULL; ++ free(message); ++ message = NULL; ++} ++ ++static void do_free_log_info(struct log_info *log) ++{ ++ if (log == NULL) { ++ return; ++ } ++ ++ free(log->tag); ++ log->tag = NULL; ++ free(log->msg); ++ log->msg = NULL; ++ free(log); ++ log = NULL; ++} ++ ++int syslog_socket_init(const char *address) ++{ ++ int ret = 0; ++ char *conn_type = NULL; ++ char *ip = NULL; ++ char *port = NULL; ++ ++ if (address == NULL) { ++ ERROR("Init socket error!"); ++ return -1; ++ } ++ ++ if (parse_address(address, &conn_type, &ip, &port) != 0) { ++ ERROR("Parse address error!"); ++ ret = -1; ++ goto out; ++ } ++ ++ ret = do_init(conn_type, ip, port); ++ ++out: ++ free(port); ++ free(ip); ++ free(conn_type); ++ return ret; ++} ++ ++int syslog_send_msg(int sock, int facility, const char *tag, const char *msg) ++{ ++ struct msghdr *msg_head = NULL; ++ struct log_info *info = NULL; ++ ssize_t ret = 0; ++ ++ if (sock < 0 || tag == NULL || msg == NULL) { ++ ERROR("Before send msg error!"); ++ return -1; ++ } ++ ++ if ((info = (struct log_info *)calloc(1, sizeof(struct log_info))) == NULL) { ++ ERROR("Out of memory!"); ++ return -1; ++ } ++ info->pri = facility; ++ if ((info->tag = strdup(tag)) == NULL) { ++ ERROR("Out of memory!"); ++ ret = -1; ++ goto out; ++ } ++ ++ if ((info->msg = strdup(msg)) == NULL) { ++ ERROR("Out of memory!"); ++ ret = -1; ++ goto out; ++ } ++ ++ if ((msg_head = pack_msg(info)) == NULL) { ++ ERROR("Pack age msg err!"); ++ return -1; ++ } ++ ++ ++ ret = sendmsg(sock, msg_head, 0); ++ if (ret < 0) { ++ ERROR("Send msg err!"); ++ goto out; ++ } ++ ++out: ++ do_free_msghdr(msg_head); ++ do_free_log_info(info); ++ return ret; ++} ++ ++ ++void syslog_sock_close(int sock) ++{ ++ close(sock); ++} +diff --git a/src/lxc/remote_syslog.h b/src/lxc/remote_syslog.h +new file mode 100644 +index 0000000..6c8fe97 +--- /dev/null ++++ b/src/lxc/remote_syslog.h +@@ -0,0 +1,21 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2021. Allrights reserved ++ * Description: isulad remote syslog ++ * Author: jikui ++ * Create: 2021-01-28 ++******************************************************************************/ ++#ifndef __iSULAD_REMOTE_SYSLOG_H ++#define __iSULAD_REMOTE_SYSLOG_H ++ ++#ifdef HAVE_ISULAD ++#include ++ ++int syslog_socket_init(const char* address); ++ ++int syslog_send_msg(int sock, int facility, const char *tag, const char *msg); ++ ++void syslog_sock_close(int sock); ++#endif ++ ++#endif +diff --git a/src/lxc/terminal.c b/src/lxc/terminal.c +index 1e467f5..ed7c30a 100644 +--- a/src/lxc/terminal.c ++++ b/src/lxc/terminal.c +@@ -30,6 +30,7 @@ + #include "utils.h" + #ifdef HAVE_ISULAD + #include "logger_json_file.h" ++#include "remote_syslog.h" + #include "include/strlcpy.h" + #endif + +@@ -582,8 +583,12 @@ cleanup: + + static ssize_t isulad_logger_syslog_write(struct lxc_terminal *terminal, const char *buf) + { ++ if (terminal->log_address == NULL) { + syslog(LOG_INFO, "%s", buf); + return 0; ++ } ++ ++ return syslog_send_msg(terminal->log_sock, terminal->log_syslog_facility, terminal->log_syslog_tag, buf); + } + + static inline bool is_syslog(const char *driver) +@@ -1420,9 +1425,15 @@ void lxc_terminal_delete(struct lxc_terminal *terminal) + terminal->log_fd = -1; + + #ifdef HAVE_ISULAD +- if (is_syslog(terminal->log_driver)) { +- closelog(); +- free(terminal->log_driver); ++ if (is_syslog(terminal->log_driver)) { ++ if (terminal->log_address == NULL) { ++ closelog(); ++ free(terminal->log_driver); ++ } else { ++ syslog_sock_close(terminal->log_sock); ++ free(terminal->log_driver); ++ free(terminal->log_address); ++ } + } + /* isulad: close all pipes */ + if (terminal->pipes[0][0] >= 0) +@@ -1817,16 +1828,20 @@ int lxc_terminal_setup(struct lxc_conf *conf) + return -1; + + #ifdef HAVE_ISULAD +- if (is_syslog(terminal->log_driver)) { +- if (terminal->log_syslog_tag == NULL) { +- terminal->log_syslog_tag = malloc(16 * sizeof(char)); +- (void)strlcpy(terminal->log_syslog_tag, conf->name, 16); +- } +- if (terminal->log_syslog_facility <= 0) { +- terminal->log_syslog_facility = LOG_DAEMON; +- } +- openlog(terminal->log_syslog_tag, LOG_PID, terminal->log_syslog_facility); ++ if (is_syslog(terminal->log_driver)) { ++ if (terminal->log_syslog_tag == NULL) { ++ terminal->log_syslog_tag = malloc(16 * sizeof(char)); ++ (void)strlcpy(terminal->log_syslog_tag, conf->name, 16); ++ } ++ if (terminal->log_syslog_facility <= 0) { ++ terminal->log_syslog_facility = LOG_DAEMON; ++ } ++ if (terminal->log_address == NULL) { ++ openlog(terminal->log_syslog_tag, LOG_PID, terminal->log_syslog_facility); ++ } else { ++ terminal->log_sock = syslog_socket_init(terminal->log_address); + } ++ } + #endif + ret = lxc_terminal_create_log_file(terminal); + if (ret < 0) +@@ -2107,6 +2122,7 @@ void lxc_terminal_init(struct lxc_terminal *terminal) + terminal->pipes[1][1] = -1; + terminal->pipes[2][0] = -1; + terminal->pipes[2][1] = -1; ++ terminal->log_sock = -1; + lxc_list_init(&terminal->fifos); + #endif + } +diff --git a/src/lxc/terminal.h b/src/lxc/terminal.h +index 9de4cd0..f531d8b 100644 +--- a/src/lxc/terminal.h ++++ b/src/lxc/terminal.h +@@ -83,11 +83,17 @@ struct lxc_terminal { + /* driver of log, support file and syslog */ + char *log_driver; + ++ /* syslog server address of log, support tcp and udp ptotocal */ ++ char *log_address; ++ + /* syslog tag for every log */ + char *log_syslog_tag; + + /* syslog facility */ + int log_syslog_facility; ++ ++ /* syslog fd */ ++ int log_sock; + #endif + }; + +-- +2.25.1 + diff --git a/lxc.spec b/lxc.spec index 45a55a7..141377b 100644 --- a/lxc.spec +++ b/lxc.spec @@ -1,4 +1,4 @@ -%global _release 2021012801 +%global _release 2021020301 Name: lxc Version: 4.0.3 @@ -27,6 +27,7 @@ Patch0016: 0016-avoid-using-void-pointers-in-caclulation.patch Patch0017: 0017-fix-compilation-errors-without-libcap.patch Patch0018: 0018-IO-fix-io-data-miss-when-exec-with-pipes.patch Patch0019: 0019-metrics-add-total_inactive_file-metric-for-memory.patch +Patch0020: 0020-support-remote-syslog.patch BuildRequires: systemd-units git libtool graphviz docbook2X doxygen chrpath BuildRequires: pkgconfig(libseccomp) @@ -198,6 +199,12 @@ make check %{_mandir}/*/man7/%{name}* %changelog +* Wed Feb 03 2021 jikui - 4.0.3-2021020301 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: support remote syslog + * Thu Jan 28 2021 lifeng - 4.0.3-2021012801 - Type:enhancement - ID:NA -- Gitee