#include <stdarg.h>
#include <string.h>
#include <signal.h>
+#include <sys/signalfd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <syslog.h>
#include <glib.h>
-#include <glib-unix.h>
static struct nflog_handle *logh = NULL;
static struct nlif_handle *nlifh = NULL;
GMainLoop *main_loop;
+gboolean foreground = FALSE;
+gboolean debug = FALSE;
+
/*
LOG FORMAT:
#define PIDFILE "/var/run/pvefw-logger.pid"
#define LQ_LEN 512
-#define LE_MAX (512 - 16) // try to fit into 512 bytes
+#define LE_MAX (512 - 4) // try to fit into 512 bytes
#define MAX_CHAIN_LEN 28
char buf[LE_MAX];
};
+#define STATIC_ASSERT(cond) \
+ extern void pve_static_assert(int test[(cond) ? 1 : -1])
+
+STATIC_ASSERT(sizeof(struct log_entry) == 512);
+
int outfd = -1;
gboolean terminate_threads = FALSE;
continue;
}
+ if (debug) fputs(le->buf, stdout);
+
int res = safe_write(outfd, le->buf, le->len);
g_free(le);
}
-#define LEPRINTF(format, ...) { if (le->len < LE_MAX) le->len += snprintf(le->buf + le->len, LE_MAX - le->len, format, ##__VA_ARGS__); }
-#define LEPRINTTIME(sec) { time_t tmp_sec = sec; if (le->len < (LE_MAX - 30)) le->len += strftime(le->buf + le->len, LE_MAX - le->len, "%d/%b/%Y:%H:%M:%S %z ", localtime(&tmp_sec)); }
+#define LEPRINTF(format, ...) \
+ do { \
+ if (le->len < LE_MAX) \
+ le->len += snprintf(le->buf + le->len, LE_MAX - le->len, format, ##__VA_ARGS__); \
+ } while (0)
+#define LEPRINTTIME(sec) \
+ do { \
+ time_t tmp_sec = sec; \
+ if (le->len < (LE_MAX - 30)) \
+ le->len += strftime(le->buf + le->len, LE_MAX - le->len, "%d/%b/%Y:%H:%M:%S %z ", localtime(&tmp_sec)); \
+ } while (0)
static void
log_status_message(guint loglevel, const char *fmt, ...)
return 0;
}
+static int
+print_ipproto(struct log_entry *le, char * nexthdr, int payload_len, u_int8_t proto)
+{
+ switch (proto) {
+ case IPPROTO_TCP:
+ print_tcp(le, (struct tcphdr *)nexthdr, payload_len);
+ break;
+ case IPPROTO_UDP:
+ print_udp(le, (struct udphdr *)nexthdr, payload_len);
+ break;
+ case IPPROTO_ICMP:
+ print_icmp(le, (struct icmphdr *)nexthdr, payload_len);
+ break;
+ case IPPROTO_SCTP:
+ print_sctp(le, (struct sctphdr *)nexthdr, payload_len);
+ break;
+ case IPPROTO_AH:
+ LEPRINTF("PROTO=AH ");
+ break;
+ case IPPROTO_ESP:
+ LEPRINTF("PROTO=ESP ");
+ break;
+ case IPPROTO_IGMP:
+ LEPRINTF("PROTO=IGMP ");
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
static int
print_iphdr(struct log_entry *le, char * payload, int payload_len)
{
void *nexthdr = (u_int32_t *)h + h->ihl;
payload_len -= h->ihl * 4;
- switch (h->protocol) {
- case IPPROTO_TCP:
- print_tcp(le, (struct tcphdr *)nexthdr, payload_len);
- break;
- case IPPROTO_UDP:
- print_udp(le, (struct udphdr *)nexthdr, payload_len);
- break;
- case IPPROTO_ICMP:
- print_icmp(le, (struct icmphdr *)nexthdr, payload_len);
- break;
- case IPPROTO_SCTP:
- print_sctp(le, (struct sctphdr *)nexthdr, payload_len);
- break;
- case IPPROTO_AH:
- LEPRINTF("PROTO=AH ");
- break;
- case IPPROTO_ESP:
- LEPRINTF("PROTO=ESP ");
- break;
- case IPPROTO_IGMP:
- LEPRINTF("PROTO=IGMP ");
- break;
- default:
+ if (print_ipproto(le, nexthdr, payload_len, h->protocol) < 0) {
LEPRINTF("PROTO=%u ", h->protocol);
}
}
static gboolean
-terminate_request(gpointer data)
+signal_read_cb(GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
{
- terminate_threads = TRUE;
+ int rv = 0;
+ struct signalfd_siginfo si;
- log_status_message(5, "received terminate request (signal)");
+ int fd = g_io_channel_unix_get_fd(source);
- g_main_loop_quit(main_loop);
+ if ((rv = read(fd, &si, sizeof(si))) && rv >= 0) {
+ terminate_threads = TRUE;
+ log_status_message(5, "received terminate request (signal)");
+ g_main_loop_quit(main_loop);
+ }
return TRUE;
}
-
int
main(int argc, char *argv[])
{
int lockfd = -1;
- gboolean foreground = FALSE;
- gboolean wrote_pidfile = FALSE;
+ int sigfd = -1;
- g_thread_init(NULL);
+ gboolean wrote_pidfile = FALSE;
openlog("pvepw-logger", LOG_CONS|LOG_PID, LOG_DAEMON);
+ GOptionContext *context;
+
+ GOptionEntry entries[] = {
+ { "debug", 'd', 0, G_OPTION_ARG_NONE, &debug, "Turn on debug messages", NULL },
+ { "foreground", 'f', 0, G_OPTION_ARG_NONE, &foreground, "Do not daemonize server", NULL },
+ { NULL },
+ };
+
+ context = g_option_context_new("");
+ g_option_context_add_main_entries (context, entries, NULL);
+
+ GError *err = NULL;
+ if (!g_option_context_parse (context, &argc, &argv, &err)) {
+ fprintf(stderr, "error: %s\n", err->message);
+ fprintf(stderr, "%s", g_option_context_get_help(context, FALSE, NULL));
+ g_error_free (err);
+ exit(-1);
+ }
+
+ if (optind < argc) {
+ fprintf(stderr, "error: too many arguments\n");
+ fprintf(stderr, "%s", g_option_context_get_help(context, FALSE, NULL));
+ exit(-1);
+ }
+
+ g_option_context_free(context);
+
+ if (debug) foreground = TRUE;
+
if ((lockfd = open(LOCKFILE, O_RDWR|O_CREAT|O_APPEND, 0644)) == -1) {
- fprintf(stderr, "unable to create lock '%s': %s", LOCKFILE, strerror (errno) );
+ fprintf(stderr, "unable to create lock '%s': %s\n", LOCKFILE, strerror (errno) );
exit(-1);
}
for (int i = 10; i >= 0; i--) {
if (flock(lockfd, LOCK_EX|LOCK_NB) != 0) {
if (!i) {
- fprintf(stderr, "unable to aquire lock '%s': %s", LOCKFILE, strerror (errno));
+ fprintf(stderr, "unable to aquire lock '%s': %s\n", LOCKFILE, strerror (errno));
exit(-1);
}
if (i == 10)
}
if ((outfd = open(LOGFILE, O_WRONLY|O_CREAT|O_APPEND, 0644)) == -1) {
- fprintf(stderr, "unable to open file '%s': %s", LOGFILE, strerror (errno));
+ fprintf(stderr, "unable to open file '%s': %s\n", LOGFILE, strerror (errno));
exit(-1);
}
struct nflog_g_handle *qh = nflog_bind_group(logh, 0);
if (!qh) {
- fprintf(stderr, "no handle for group 1\n");
+ fprintf(stderr, "no nflog handle for group 0\n");
exit(-1);
}
exit(-1);
}
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+
+ if ((sigfd = signalfd(-1, &mask, SFD_NONBLOCK)) < 0) {
+ fprintf(stderr, "unable to open signalfd: %s\n", strerror (errno));
+ exit(-1);
+ }
+
if (!foreground) {
pid_t cpid = fork();
g_io_add_watch(nflog_ch, G_IO_IN, nflog_read_cb, NULL);
+ GIOChannel *sig_ch = g_io_channel_unix_new(sigfd);
+ if (!g_io_add_watch(sig_ch, G_IO_IN, signal_read_cb, NULL)) {
+ exit(-1);
+ }
+
GThread *wthread = g_thread_new("log_writer_thread", log_writer_thread, NULL);
main_loop = g_main_loop_new(NULL, TRUE);
- g_unix_signal_add(SIGINT, terminate_request, NULL);
- g_unix_signal_add(SIGTERM, terminate_request, NULL);
-
g_main_loop_run(main_loop);
log_status_message(5, "stopping pvefw logger");