]> git.proxmox.com Git - pve-firewall.git/blob - src/pvefw-logger.c
make LEPRINT* macros safe to use with if/else pairs
[pve-firewall.git] / src / pvefw-logger.c
1 /*
2
3 Copyright (C) 2014 Proxmox Server Solutions GmbH
4
5 This software is written by Proxmox Server Solutions GmbH <support@proxmox.com>
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Affero General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 Author: Dietmar Maurer <dietmar@proxmox.com>
21
22 */
23
24 #define _GNU_SOURCE
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <signal.h>
32 #include <sys/signalfd.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <arpa/inet.h>
38 #include <sys/socket.h>
39 #include <sys/file.h>
40 #include <linux/netlink.h>
41 #include <libnfnetlink/libnfnetlink.h>
42 #include <libnetfilter_log/libnetfilter_log.h>
43 #include <netinet/ip.h>
44 #include <netinet/ip_icmp.h>
45 #include <netinet/udp.h>
46 #include <netinet/tcp.h>
47 #include <netinet/if_ether.h>
48 #include <syslog.h>
49
50 #include <glib.h>
51
52 static struct nflog_handle *logh = NULL;
53 static struct nlif_handle *nlifh = NULL;
54 GMainLoop *main_loop;
55
56 gboolean foreground = FALSE;
57 gboolean debug = FALSE;
58
59 /*
60
61 LOG FORMAT:
62
63 Special care was taken to allow fast parsing (and filer messages for a singl VM).
64
65 <VMID> <LOGLEVEL> <CHAIN> <TIME> <TIMEZONE> <MSG>
66
67 Example:
68
69 117 6 tap117i0-IN 14/Mar/2014:12:47:07 +0100 policy REJECT: IN=vmbr1 ...
70
71 */
72
73 #define LOGFILE "/var/log/pve-firewall.log"
74
75 #define LOCKFILE "/var/lock/pvefw-logger.lck"
76 #define PIDFILE "/var/run/pvefw-logger.pid"
77
78 #define LQ_LEN 512
79 #define LE_MAX (512 - 4) // try to fit into 512 bytes
80
81 #define MAX_CHAIN_LEN 28
82
83 struct log_entry {
84 guint32 len; // max LE_MAX chars
85 char buf[LE_MAX];
86 };
87
88 #define STATIC_ASSERT(cond) \
89 extern void pve_static_assert(int test[(cond) ? 1 : -1])
90
91 STATIC_ASSERT(sizeof(struct log_entry) == 512);
92
93 int outfd = -1;
94
95 gboolean terminate_threads = FALSE;
96
97 static gboolean write_pidfile(pid_t pid)
98 {
99 gboolean res;
100
101 char *strpid = g_strdup_printf("%d\n", pid);
102 res = g_file_set_contents(PIDFILE, strpid, strlen(strpid), NULL);
103 g_free(strpid);
104
105 return res;
106 }
107
108 static GAsyncQueue *queue;
109
110 ssize_t
111 safe_write(int fd, char *buf, size_t count)
112 {
113 ssize_t n;
114
115 do {
116 n = write(fd, buf, count);
117 } while (n < 0 && errno == EINTR);
118
119 return n;
120 }
121
122 static gpointer
123 log_writer_thread(gpointer data)
124 {
125 while (1) {
126 struct log_entry *le = (struct log_entry *)g_async_queue_timeout_pop(queue, 250000);
127 if (le == NULL) {
128 if (terminate_threads) {
129 return NULL;
130 }
131 continue;
132 }
133
134 if (debug) fputs(le->buf, stdout);
135
136 int res = safe_write(outfd, le->buf, le->len);
137
138 g_free(le);
139
140 if (res < 0) {
141 syslog(3, "writing log failed, stopping daemon - %s", strerror (errno));
142 g_main_loop_quit(main_loop);
143 return NULL;
144 }
145 }
146
147 return NULL;
148 }
149
150 static int skipped_logs = 0;
151
152 static void log_status_message(guint loglevel, const char *fmt, ...);
153
154 static void
155 queue_log_entry(struct log_entry *le)
156 {
157 gint len = g_async_queue_length(queue);
158
159 if (skipped_logs > 0) {
160 if (len >= (LQ_LEN - 1)) {
161 skipped_logs++;
162 } else {
163 int skip_tmp = skipped_logs;
164 skipped_logs = 0; // clear before calling log_status_message()
165 log_status_message(3, "skipped %d log entries (queue full)", skip_tmp);
166 g_async_queue_push(queue, le);
167 }
168 } else {
169 if (len >= LQ_LEN) {
170 skipped_logs++;
171 } else {
172 g_async_queue_push(queue, le);
173 }
174 }
175 }
176
177
178 #define LEPRINTF(format, ...) \
179 do { \
180 if (le->len < LE_MAX) \
181 le->len += snprintf(le->buf + le->len, LE_MAX - le->len, format, ##__VA_ARGS__); \
182 } while (0)
183 #define LEPRINTTIME(sec) \
184 do { \
185 time_t tmp_sec = sec; \
186 if (le->len < (LE_MAX - 30)) \
187 le->len += strftime(le->buf + le->len, LE_MAX - le->len, "%d/%b/%Y:%H:%M:%S %z ", localtime(&tmp_sec)); \
188 } while (0)
189
190 static void
191 log_status_message(guint loglevel, const char *fmt, ...)
192 {
193 va_list ap;
194 va_start(ap, fmt);
195
196 if (loglevel > 7 ) loglevel = 7; // syslog defines level 0-7
197
198 struct log_entry *le = g_new0(struct log_entry, 1);
199
200 LEPRINTF("0 %d - ", loglevel);
201
202 LEPRINTTIME(time(NULL));
203
204 le->len += vsnprintf(le->buf + le->len, LE_MAX - le->len, fmt, ap);
205
206 LEPRINTF("\n");
207
208 queue_log_entry(le);
209
210 // also log to syslog
211
212 vsyslog(loglevel, fmt, ap);
213 }
214
215 static int
216 print_tcp(struct log_entry *le, struct tcphdr *h, int payload_len)
217 {
218 LEPRINTF("PROTO=TCP ");
219
220 if (payload_len < sizeof(struct tcphdr)) {
221 LEPRINTF("LEN=%d ", payload_len);
222 LEPRINTF("INVALID=LEN ");
223 return -1;
224 }
225
226 LEPRINTF("SPT=%u DPT=%u ", ntohs(h->source), ntohs(h->dest));
227 LEPRINTF("SEQ=%u ACK=%u ", ntohl(h->seq), ntohl(h->ack_seq));
228 LEPRINTF("WINDOW=%u ", ntohs(h->window));
229
230 if (h->urg) LEPRINTF("URG ");
231 if (h->ack) LEPRINTF("ACK ");
232 if (h->psh) LEPRINTF("PSH ");
233 if (h->rst) LEPRINTF("RST ");
234 if (h->syn) LEPRINTF("SYN ");
235 if (h->fin) LEPRINTF("FIN ");
236
237 if (h->urg) LEPRINTF("URGP=%u ",ntohs(h->urg_ptr));
238
239 return 0;
240 }
241
242 static int
243 print_udp(struct log_entry *le, struct udphdr *h, int payload_len)
244 {
245 LEPRINTF("PROTO=UDP ");
246
247 if (payload_len < sizeof(struct udphdr)) {
248 LEPRINTF("LEN=%d ", payload_len);
249 LEPRINTF("INVALID=LEN ");
250 return -1;
251 }
252
253 LEPRINTF("SPT=%u DPT=%u LEN=%u", ntohs(h->source), ntohs(h->dest), ntohs(h->len));
254
255 return 0;
256 }
257
258 static int
259 print_icmp(struct log_entry *le, struct icmphdr *h, int payload_len)
260 {
261 char tmp[INET_ADDRSTRLEN];
262 u_int32_t gateway;
263
264 LEPRINTF("PROTO=ICMP ");
265
266 if (payload_len < sizeof(struct icmphdr)) {
267 LEPRINTF("LEN=%d ", payload_len);
268 LEPRINTF("INVALID=LEN ");
269 return -1;
270 }
271
272 LEPRINTF("TYPE=%u CODE=%u ", h->type, h->code);
273
274 switch (h->type) {
275 case ICMP_ECHO:
276 case ICMP_ECHOREPLY:
277 LEPRINTF("ID=%u SEQ=%u ", ntohs(h->un.echo.id), ntohs(h->un.echo.sequence));
278 break;
279 case ICMP_PARAMETERPROB:
280 LEPRINTF("PARAMETER=%u ", ntohl(h->un.gateway) >> 24);
281 break;
282 case ICMP_REDIRECT:
283 gateway = ntohl(h->un.gateway);
284 inet_ntop(AF_INET, &gateway, tmp, sizeof(tmp));
285 LEPRINTF("GATEWAY=%s ", tmp);
286 break;
287 case ICMP_DEST_UNREACH:
288 if (h->code == ICMP_FRAG_NEEDED) {
289 LEPRINTF("MTU=%u ", ntohs(h->un.frag.mtu));
290 }
291 break;
292 }
293
294 return 0;
295 }
296
297 /* Section 3.1. SCTP Common Header Format */
298 typedef struct sctphdr {
299 __be16 source;
300 __be16 dest;
301 __be32 vtag;
302 __be32 checksum;
303 } __attribute__((packed)) sctp_sctphdr_t;
304
305 static int
306 print_sctp(struct log_entry *le, struct sctphdr *h, int payload_len)
307 {
308 LEPRINTF("PROTO=SCTP ");
309
310 if (payload_len < sizeof(struct sctphdr)) {
311 LEPRINTF("LEN=%d ", payload_len);
312 LEPRINTF("INVALID=LEN ");
313 return -1;
314 }
315
316 LEPRINTF("SPT=%u DPT=%u ", ntohs(h->source), ntohs(h->dest));
317
318 return 0;
319 }
320
321 static int
322 print_iphdr(struct log_entry *le, char * payload, int payload_len)
323 {
324 if (payload_len < sizeof(struct iphdr)) {
325 LEPRINTF("LEN=%d ", payload_len);
326 LEPRINTF("INVALID=LEN ");
327 return -1;
328 }
329
330 struct iphdr *h = (struct iphdr *)payload;
331
332 if (payload_len <= (u_int32_t)(h->ihl * 4)) {
333 LEPRINTF("INVALID=IHL ");
334 return -1;
335 }
336
337 char tmp[INET_ADDRSTRLEN];
338
339 inet_ntop(AF_INET, &h->saddr, tmp, sizeof(tmp));
340 LEPRINTF("SRC=%s ", tmp);
341 inet_ntop(AF_INET, &h->daddr, tmp, sizeof(tmp));
342 LEPRINTF("DST=%s ", tmp);
343
344 LEPRINTF("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ",
345 ntohs(h->tot_len), h->tos & IPTOS_TOS_MASK,
346 h->tos & IPTOS_PREC_MASK, h->ttl, ntohs(h->id));
347
348 short ip_off = ntohs(h->frag_off);
349 if (ip_off & IP_OFFMASK)
350 LEPRINTF("FRAG=%u ", ip_off & IP_OFFMASK);
351
352 if (ip_off & IP_DF) LEPRINTF("DF ");
353 if (ip_off & IP_MF) LEPRINTF("MF ");
354
355 void *nexthdr = (u_int32_t *)h + h->ihl;
356 payload_len -= h->ihl * 4;
357
358 switch (h->protocol) {
359 case IPPROTO_TCP:
360 print_tcp(le, (struct tcphdr *)nexthdr, payload_len);
361 break;
362 case IPPROTO_UDP:
363 print_udp(le, (struct udphdr *)nexthdr, payload_len);
364 break;
365 case IPPROTO_ICMP:
366 print_icmp(le, (struct icmphdr *)nexthdr, payload_len);
367 break;
368 case IPPROTO_SCTP:
369 print_sctp(le, (struct sctphdr *)nexthdr, payload_len);
370 break;
371 case IPPROTO_AH:
372 LEPRINTF("PROTO=AH ");
373 break;
374 case IPPROTO_ESP:
375 LEPRINTF("PROTO=ESP ");
376 break;
377 case IPPROTO_IGMP:
378 LEPRINTF("PROTO=IGMP ");
379 break;
380 default:
381 LEPRINTF("PROTO=%u ", h->protocol);
382 }
383
384 return 0;
385 }
386
387 static int
388 print_ip6hdr(struct log_entry *le, char * payload, int payload_len)
389 {
390 LEPRINTF("IPV6 logging not implemented ");
391
392 return 0;
393 }
394
395 // ebtables -I FORWARD --nflog --nflog-group 0
396 static int
397 print_arp(struct log_entry *le, struct ether_arp *h, int payload_len)
398 {
399 if (payload_len < sizeof(struct ether_arp)) {
400 LEPRINTF("LEN=%d ", payload_len);
401 LEPRINTF("INVALID=LEN ");
402 return -1;
403 }
404
405 LEPRINTF("SRC=%u.%u.%u.%u ", h->arp_spa[0], h->arp_spa[1],
406 h->arp_spa[2], h->arp_spa[3]);
407
408 LEPRINTF("DST=%u.%u.%u.%u ", h->arp_tpa[0], h->arp_tpa[1],
409 h->arp_tpa[2], h->arp_tpa[3]);
410
411 LEPRINTF("PROTO=ARP ");
412
413 unsigned short code = ntohs(h->arp_op);
414 switch (code) {
415 case ARPOP_REQUEST:
416 LEPRINTF("REQUEST ");
417 break;
418 case ARPOP_REPLY:
419 LEPRINTF("REPLY MAC=%02x:%02x:%02x:%02x:%02x:%02x ",
420 h->arp_sha[0], h->arp_sha[1], h->arp_sha[2],
421 h->arp_sha[3], h->arp_sha[4], h->arp_sha[5]);
422 break;
423 case ARPOP_NAK:
424 LEPRINTF("NAK ");
425 break;
426 default:
427 LEPRINTF("CODE=%u ", code);
428 }
429
430
431 // LEPRINTF("HTYPE=%u ", ntohs(h->arp_hrd));
432
433 // LEPRINTF("PTYPE=%u ", ntohs(h->arp_pro));
434
435 return 0;
436 }
437
438
439 static int print_pkt(struct log_entry *le, struct nflog_data *ldata, u_int8_t family)
440 {
441 u_int32_t mark = nflog_get_nfmark(ldata);
442 u_int32_t indev = nflog_get_indev(ldata);
443 u_int32_t outdev = nflog_get_outdev(ldata);
444 u_int32_t physindev = nflog_get_physindev(ldata);
445 u_int32_t physoutdev = nflog_get_physoutdev(ldata);
446
447 char *prefix = nflog_get_prefix(ldata);
448 char *payload;
449 char devname[256];
450
451 guint32 vmid = 0;
452
453 guint8 log_level = 6; // info
454
455 char *chain_name = "-";
456
457 if (prefix != NULL) {
458 // Note: parse ":$vmid:$loglevel:$chain: $msg"
459 if (prefix[0] == ':') {
460 char *p = prefix + 1;
461 guint32 tmpid = 0;
462 while(*p >= '0' && *p <= '9') { tmpid *= 10; tmpid += *p - '0'; p++; }
463
464 if ((*p == ':') &&
465 (p[1] >= '0' && p[1] <= '7') &&
466 (p[2] == ':')) {
467
468 guint8 tmp_level = p[1] - '0'; // store for later use
469 char *chain_start = p + 3; // store for later use
470 p = chain_start;
471 while (*p && *p != ':' && *p != ' ') p++;
472 int len = p - chain_start;
473
474 if (*p == ':' && p[1] == ' ' && len && (len <= MAX_CHAIN_LEN)) {
475 // parsing successful
476
477 *p = 0; // terminate string
478
479 vmid = tmpid;
480 log_level = tmp_level;
481 chain_name = chain_start;
482 prefix = p + 2; // the rest
483 }
484 }
485 }
486 }
487
488 LEPRINTF("%d ", vmid);
489
490 LEPRINTF("%d ", log_level);
491
492 LEPRINTF("%s ", chain_name);
493
494 struct timeval ts;
495 nflog_get_timestamp(ldata, &ts);
496
497 LEPRINTTIME(ts.tv_sec);
498
499 if (prefix != NULL) {
500 LEPRINTF("%s", prefix);
501 }
502
503 if (indev > 0) {
504 if (nlif_index2name(nlifh, indev, devname) != -1) {
505 LEPRINTF("IN=%s ", devname);
506 } else {
507 LEPRINTF("IN=%u ", indev);
508 }
509 }
510
511 if (outdev > 0) {
512 if (nlif_index2name(nlifh, outdev, devname) != -1) {
513 LEPRINTF("OUT=%s ", devname);
514 } else {
515 LEPRINTF("OUT=%u ", outdev);
516 }
517 }
518
519 if (physindev > 0) {
520 if (nlif_index2name(nlifh, physindev, devname) != -1) {
521 LEPRINTF("PHYSIN=%s ", devname);
522 } else {
523 LEPRINTF("PHYSIN=%u ", physindev);
524 }
525 }
526
527 if (physoutdev > 0) {
528 if (nlif_index2name(nlifh, physoutdev, devname) != -1) {
529 LEPRINTF("PHYSOUT=%s ", devname);
530 } else {
531 LEPRINTF("PHYSOUT=%u ", physoutdev);
532 }
533 }
534
535 int payload_len = nflog_get_payload(ldata, &payload);
536
537 int hwhdrlen = nflog_get_msg_packet_hwhdrlen(ldata);
538 if (hwhdrlen > 0) {
539 unsigned char *hwhdr = (unsigned char *)nflog_get_msg_packet_hwhdr(ldata);
540 if (hwhdr != NULL) {
541 int i;
542 LEPRINTF("MAC=");
543 for (i = 0; i < hwhdrlen; i++) {
544 LEPRINTF("%02x", hwhdr[i]);
545 if (i < (hwhdrlen -1 )) LEPRINTF(":");
546 }
547 LEPRINTF(" ");
548 }
549 }
550
551 u_int16_t hw_protocol = 0;
552 struct nfulnl_msg_packet_hdr *ph = NULL;
553
554 switch (family) {
555 case AF_INET:
556 print_iphdr(le, payload, payload_len);
557 break;
558 case AF_INET6:
559 print_ip6hdr(le, payload, payload_len);
560 break;
561 case AF_BRIDGE:
562 ph = nflog_get_msg_packet_hdr(ldata);
563 if (ph) hw_protocol = ntohs(ph->hw_protocol);
564
565 switch (hw_protocol) {
566 case ETH_P_IP:
567 print_iphdr(le, payload, payload_len);
568 break;
569 case ETH_P_IPV6:
570 print_ip6hdr(le, payload, payload_len);
571 break;
572 case ETH_P_ARP:
573 print_arp(le, (struct ether_arp *)payload, payload_len);
574 break;
575 }
576 break;
577 }
578
579 if (mark) LEPRINTF("mark=%u ", mark);
580
581
582 return 0;
583
584 }
585
586 static int
587 nflog_cb(struct nflog_g_handle *gh, struct nfgenmsg *nfmsg,
588 struct nflog_data *nfa, void *data)
589 {
590 struct log_entry *le = g_new0(struct log_entry, 1);
591
592 print_pkt(le, nfa, nfmsg->nfgen_family);
593
594 LEPRINTF("\n"); // add newline
595
596 queue_log_entry(le);
597
598 return 0;
599 }
600
601 static gboolean
602 nflog_read_cb(GIOChannel *source,
603 GIOCondition condition,
604 gpointer data)
605 {
606 int rv = 0;
607 gchar buf[8192];
608
609 int fd = g_io_channel_unix_get_fd(source);
610
611 if ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
612 nflog_handle_packet(logh, buf, rv);
613 }
614
615 return TRUE;
616 }
617
618 static gboolean
619 nlif_read_cb(GIOChannel *source,
620 GIOCondition condition,
621 gpointer data)
622 {
623 static int last_res = 0;
624 int res;
625
626 if ((res = nlif_catch(nlifh)) < 0) {
627 if (last_res == 0) { // only report once
628 log_status_message(3, "nlif_catch failed (res = %d)", res);
629 }
630 last_res = res;
631 } else {
632 last_res = 0;
633 }
634
635 return TRUE;
636 }
637
638 static gboolean
639 signal_read_cb(GIOChannel *source,
640 GIOCondition condition,
641 gpointer data)
642 {
643 int rv = 0;
644 struct signalfd_siginfo si;
645
646 int fd = g_io_channel_unix_get_fd(source);
647
648 if ((rv = read(fd, &si, sizeof(si))) && rv >= 0) {
649 terminate_threads = TRUE;
650 log_status_message(5, "received terminate request (signal)");
651 g_main_loop_quit(main_loop);
652 }
653
654 return TRUE;
655 }
656
657 int
658 main(int argc, char *argv[])
659 {
660 int lockfd = -1;
661 int sigfd = -1;
662
663 gboolean wrote_pidfile = FALSE;
664
665 openlog("pvepw-logger", LOG_CONS|LOG_PID, LOG_DAEMON);
666
667 GOptionContext *context;
668
669 GOptionEntry entries[] = {
670 { "debug", 'd', 0, G_OPTION_ARG_NONE, &debug, "Turn on debug messages", NULL },
671 { "foreground", 'f', 0, G_OPTION_ARG_NONE, &foreground, "Do not daemonize server", NULL },
672 { NULL },
673 };
674
675 context = g_option_context_new("");
676 g_option_context_add_main_entries (context, entries, NULL);
677
678 GError *err = NULL;
679 if (!g_option_context_parse (context, &argc, &argv, &err)) {
680 fprintf(stderr, "error: %s\n", err->message);
681 fprintf(stderr, "%s", g_option_context_get_help(context, FALSE, NULL));
682 g_error_free (err);
683 exit(-1);
684 }
685
686 if (optind < argc) {
687 fprintf(stderr, "error: too many arguments\n");
688 fprintf(stderr, "%s", g_option_context_get_help(context, FALSE, NULL));
689 exit(-1);
690 }
691
692 g_option_context_free(context);
693
694 if (debug) foreground = TRUE;
695
696 if ((lockfd = open(LOCKFILE, O_RDWR|O_CREAT|O_APPEND, 0644)) == -1) {
697 fprintf(stderr, "unable to create lock '%s': %s\n", LOCKFILE, strerror (errno) );
698 exit(-1);
699 }
700
701 for (int i = 10; i >= 0; i--) {
702 if (flock(lockfd, LOCK_EX|LOCK_NB) != 0) {
703 if (!i) {
704 fprintf(stderr, "unable to aquire lock '%s': %s\n", LOCKFILE, strerror (errno));
705 exit(-1);
706 }
707 if (i == 10)
708 fprintf(stderr, "unable to aquire lock '%s' - trying again.\n", LOCKFILE);
709
710 sleep(1);
711 }
712 }
713
714 if ((outfd = open(LOGFILE, O_WRONLY|O_CREAT|O_APPEND, 0644)) == -1) {
715 fprintf(stderr, "unable to open file '%s': %s\n", LOGFILE, strerror (errno));
716 exit(-1);
717 }
718
719 if ((logh = nflog_open()) == NULL) {
720 fprintf(stderr, "unable to open nflog\n");
721 exit(-1);
722 }
723
724 if (!nflog_bind_pf(logh, AF_INET) <= 0) {
725 fprintf(stderr, "nflog_bind_pf AF_INET failed\n");
726 exit(-1);
727 }
728
729 #if 0
730 if (!nflog_bind_pf(logh, AF_INET6) <= 0) {
731 fprintf(stderr, "nflog_bind_pf AF_INET6 failed\n");
732 exit(-1);
733 }
734 #endif
735
736 if (!nflog_bind_pf(logh, AF_BRIDGE) <= 0) {
737 fprintf(stderr, "nflog_bind_pf AF_BRIDGE failed\n");
738 exit(-1);
739 }
740
741 struct nflog_g_handle *qh = nflog_bind_group(logh, 0);
742 if (!qh) {
743 fprintf(stderr, "no nflog handle for group 0\n");
744 exit(-1);
745 }
746
747 if (nflog_set_mode(qh, NFULNL_COPY_PACKET, 0xffff) < 0) {
748 fprintf(stderr, "can't set packet copy mode\n");
749 exit(-1);
750 }
751
752 if ((nlifh = nlif_open()) == NULL) {
753 fprintf(stderr, "unable to open netlink interface handle\n");
754 exit(-1);
755 }
756
757 sigset_t mask;
758 sigemptyset(&mask);
759 sigaddset(&mask, SIGINT);
760 sigaddset(&mask, SIGTERM);
761
762 sigprocmask(SIG_BLOCK, &mask, NULL);
763
764 if ((sigfd = signalfd(-1, &mask, SFD_NONBLOCK)) < 0) {
765 fprintf(stderr, "unable to open signalfd: %s\n", strerror (errno));
766 exit(-1);
767 }
768
769 if (!foreground) {
770 pid_t cpid = fork();
771
772 if (cpid == -1) {
773 fprintf(stderr, "failed to daemonize program - %s\n", strerror (errno));
774 exit(-1);
775 } else if (cpid) {
776 write_pidfile(cpid);
777 _exit(0);
778 } else {
779 int nullfd;
780
781 if (chroot("/") != 0) fprintf(stderr, "chroot '/' failed - %s\n", strerror (errno));
782
783 if ((nullfd = open("/dev/null", O_RDWR, 0)) != -1) {
784 dup2(nullfd, 0);
785 dup2(nullfd, 1);
786 dup2(nullfd, 2);
787 if (nullfd > 2)
788 close (nullfd);
789 }
790
791 setsid();
792 }
793 } else {
794 write_pidfile(getpid());
795 }
796
797 wrote_pidfile = TRUE;
798
799 nflog_callback_register(qh, &nflog_cb, logh);
800
801 queue = g_async_queue_new_full(g_free);
802
803 log_status_message(5, "starting pvefw logger");
804
805 nlif_query(nlifh);
806
807 GIOChannel *nlif_ch = g_io_channel_unix_new(nlif_fd(nlifh));
808
809 g_io_add_watch(nlif_ch, G_IO_IN, nlif_read_cb, NULL);
810
811 int logfd = nflog_fd(logh);
812 GIOChannel *nflog_ch = g_io_channel_unix_new(logfd);
813
814 g_io_add_watch(nflog_ch, G_IO_IN, nflog_read_cb, NULL);
815
816 GIOChannel *sig_ch = g_io_channel_unix_new(sigfd);
817 if (!g_io_add_watch(sig_ch, G_IO_IN, signal_read_cb, NULL)) {
818 exit(-1);
819 }
820
821 GThread *wthread = g_thread_new("log_writer_thread", log_writer_thread, NULL);
822
823 main_loop = g_main_loop_new(NULL, TRUE);
824
825 g_main_loop_run(main_loop);
826
827 log_status_message(5, "stopping pvefw logger");
828
829 g_thread_join(wthread);
830
831 close(outfd);
832
833 nflog_close(logh);
834
835 if (wrote_pidfile)
836 unlink(PIDFILE);
837
838 exit(0);
839 }