also allow VNC and SPICE traffic inside cluster_network
[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, ...) { if (le->len < LE_MAX) le->len += snprintf(le->buf + le->len, LE_MAX - le->len, format, ##__VA_ARGS__); }
179 #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)); }
180
181 static void
182 log_status_message(guint loglevel, const char *fmt, ...)
183 {
184     va_list ap;
185     va_start(ap, fmt);
186
187     if (loglevel > 7 ) loglevel = 7; // syslog defines level 0-7
188
189     struct log_entry *le = g_new0(struct log_entry, 1);
190
191     LEPRINTF("0 %d - ", loglevel);
192
193     LEPRINTTIME(time(NULL));
194
195     le->len += vsnprintf(le->buf + le->len, LE_MAX - le->len, fmt, ap);
196
197     LEPRINTF("\n");
198
199     queue_log_entry(le);
200
201     // also log to syslog
202
203     vsyslog(loglevel, fmt, ap);
204 }
205
206 static int
207 print_tcp(struct log_entry *le, struct tcphdr *h, int payload_len)
208 {
209     LEPRINTF("PROTO=TCP ");
210
211     if (payload_len < sizeof(struct tcphdr)) {
212         LEPRINTF("LEN=%d ", payload_len);
213         LEPRINTF("INVALID=LEN ");
214         return -1;
215     }
216
217     LEPRINTF("SPT=%u DPT=%u ", ntohs(h->source), ntohs(h->dest));
218     LEPRINTF("SEQ=%u ACK=%u ", ntohl(h->seq), ntohl(h->ack_seq));
219     LEPRINTF("WINDOW=%u ", ntohs(h->window));
220
221     if (h->urg) LEPRINTF("URG ");
222     if (h->ack) LEPRINTF("ACK ");
223     if (h->psh) LEPRINTF("PSH ");
224     if (h->rst) LEPRINTF("RST ");
225     if (h->syn) LEPRINTF("SYN ");
226     if (h->fin) LEPRINTF("FIN ");
227
228     if (h->urg) LEPRINTF("URGP=%u ",ntohs(h->urg_ptr));
229
230     return 0;
231 }
232
233 static int
234 print_udp(struct log_entry *le, struct udphdr *h, int payload_len)
235 {
236     LEPRINTF("PROTO=UDP ");
237
238     if (payload_len < sizeof(struct udphdr)) {
239         LEPRINTF("LEN=%d ", payload_len);
240         LEPRINTF("INVALID=LEN ");
241         return -1;
242     }
243
244     LEPRINTF("SPT=%u DPT=%u LEN=%u", ntohs(h->source), ntohs(h->dest), ntohs(h->len));
245
246     return 0;
247 }
248
249 static int
250 print_icmp(struct log_entry *le, struct icmphdr *h, int payload_len)
251 {
252     char tmp[INET_ADDRSTRLEN];
253     u_int32_t gateway;
254
255     LEPRINTF("PROTO=ICMP ");
256
257     if (payload_len < sizeof(struct icmphdr)) {
258         LEPRINTF("LEN=%d ", payload_len);
259         LEPRINTF("INVALID=LEN ");
260         return -1;
261     }
262
263     LEPRINTF("TYPE=%u CODE=%u ", h->type, h->code);
264
265     switch (h->type) {
266     case ICMP_ECHO:
267     case ICMP_ECHOREPLY:
268         LEPRINTF("ID=%u SEQ=%u ", ntohs(h->un.echo.id), ntohs(h->un.echo.sequence));
269         break;
270     case ICMP_PARAMETERPROB:
271         LEPRINTF("PARAMETER=%u ", ntohl(h->un.gateway) >> 24);
272         break;
273     case ICMP_REDIRECT:
274         gateway = ntohl(h->un.gateway);
275         inet_ntop(AF_INET, &gateway, tmp, sizeof(tmp));
276         LEPRINTF("GATEWAY=%s ", tmp);
277         break;
278     case ICMP_DEST_UNREACH:
279         if (h->code == ICMP_FRAG_NEEDED) {
280             LEPRINTF("MTU=%u ", ntohs(h->un.frag.mtu));
281         }
282         break;
283     }
284
285     return 0;
286 }
287
288 /* Section 3.1.  SCTP Common Header Format */
289 typedef struct sctphdr {
290         __be16 source;
291         __be16 dest;
292         __be32 vtag;
293         __be32 checksum;
294 } __attribute__((packed)) sctp_sctphdr_t;
295
296 static int
297 print_sctp(struct log_entry *le, struct sctphdr *h, int payload_len)
298 {
299     LEPRINTF("PROTO=SCTP ");
300
301     if (payload_len < sizeof(struct sctphdr)) {
302         LEPRINTF("LEN=%d ", payload_len);
303         LEPRINTF("INVALID=LEN ");
304         return -1;
305     }
306
307     LEPRINTF("SPT=%u DPT=%u ", ntohs(h->source), ntohs(h->dest));
308
309     return 0;
310 }
311
312 static int
313 print_iphdr(struct log_entry *le, char * payload, int payload_len)
314 {
315     if (payload_len < sizeof(struct iphdr)) {
316        LEPRINTF("LEN=%d ", payload_len);
317        LEPRINTF("INVALID=LEN ");
318        return -1;
319     }
320
321     struct iphdr *h = (struct iphdr *)payload;
322
323     if (payload_len <= (u_int32_t)(h->ihl * 4)) {
324         LEPRINTF("INVALID=IHL ");
325         return -1;
326     }
327
328     char tmp[INET_ADDRSTRLEN];
329
330     inet_ntop(AF_INET, &h->saddr, tmp, sizeof(tmp));
331     LEPRINTF("SRC=%s ", tmp);
332     inet_ntop(AF_INET, &h->daddr, tmp, sizeof(tmp));
333     LEPRINTF("DST=%s ", tmp);
334
335     LEPRINTF("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ",
336              ntohs(h->tot_len),  h->tos & IPTOS_TOS_MASK,
337              h->tos & IPTOS_PREC_MASK, h->ttl, ntohs(h->id));
338
339     short ip_off = ntohs(h->frag_off);
340     if (ip_off & IP_OFFMASK)
341         LEPRINTF("FRAG=%u ", ip_off & IP_OFFMASK);
342
343     if (ip_off & IP_DF) LEPRINTF("DF ");
344     if (ip_off & IP_MF) LEPRINTF("MF ");
345
346     void *nexthdr = (u_int32_t *)h + h->ihl;
347     payload_len -= h->ihl * 4;
348
349     switch (h->protocol) {
350     case IPPROTO_TCP:
351         print_tcp(le, (struct tcphdr *)nexthdr, payload_len);
352         break;
353     case IPPROTO_UDP:
354         print_udp(le, (struct udphdr *)nexthdr, payload_len);
355         break;
356     case IPPROTO_ICMP:
357         print_icmp(le, (struct icmphdr *)nexthdr, payload_len);
358         break;
359     case IPPROTO_SCTP:
360         print_sctp(le, (struct sctphdr *)nexthdr, payload_len);
361         break;
362     case IPPROTO_AH:
363         LEPRINTF("PROTO=AH ");
364         break;
365     case IPPROTO_ESP:
366         LEPRINTF("PROTO=ESP ");
367         break;
368     case IPPROTO_IGMP:
369         LEPRINTF("PROTO=IGMP ");
370         break;
371      default:
372         LEPRINTF("PROTO=%u ", h->protocol);
373     }
374
375     return 0;
376 }
377
378 static int
379 print_ip6hdr(struct log_entry *le, char * payload, int payload_len)
380 {
381     LEPRINTF("IPV6 logging not implemented ");
382
383     return 0;
384 }
385
386 // ebtables -I FORWARD --nflog --nflog-group 0
387 static int
388 print_arp(struct log_entry *le, struct ether_arp *h, int payload_len)
389 {
390     if (payload_len < sizeof(struct ether_arp)) {
391         LEPRINTF("LEN=%d ", payload_len);
392         LEPRINTF("INVALID=LEN ");
393         return -1;
394     }
395
396     LEPRINTF("SRC=%u.%u.%u.%u ", h->arp_spa[0], h->arp_spa[1],
397              h->arp_spa[2], h->arp_spa[3]);
398
399     LEPRINTF("DST=%u.%u.%u.%u ", h->arp_tpa[0], h->arp_tpa[1],
400              h->arp_tpa[2], h->arp_tpa[3]);
401
402     LEPRINTF("PROTO=ARP ");
403
404     unsigned short code = ntohs(h->arp_op);
405     switch (code) {
406     case ARPOP_REQUEST:
407         LEPRINTF("REQUEST ");
408         break;
409     case ARPOP_REPLY:
410         LEPRINTF("REPLY MAC=%02x:%02x:%02x:%02x:%02x:%02x ",
411                  h->arp_sha[0], h->arp_sha[1], h->arp_sha[2],
412                  h->arp_sha[3], h->arp_sha[4], h->arp_sha[5]);
413         break;
414     case ARPOP_NAK:
415         LEPRINTF("NAK ");
416         break;
417     default:
418         LEPRINTF("CODE=%u ", code);
419     }
420
421
422     // LEPRINTF("HTYPE=%u ", ntohs(h->arp_hrd));
423
424     // LEPRINTF("PTYPE=%u ", ntohs(h->arp_pro));
425
426     return 0;
427 }
428
429
430 static int print_pkt(struct log_entry *le, struct nflog_data *ldata, u_int8_t family)
431 {
432     u_int32_t mark = nflog_get_nfmark(ldata);
433     u_int32_t indev = nflog_get_indev(ldata);
434     u_int32_t outdev = nflog_get_outdev(ldata);
435     u_int32_t physindev = nflog_get_physindev(ldata);
436     u_int32_t physoutdev = nflog_get_physoutdev(ldata);
437
438     char *prefix = nflog_get_prefix(ldata);
439     char *payload;
440     char devname[256];
441
442     guint32 vmid = 0;
443
444     guint8 log_level = 6; // info
445
446     char *chain_name = "-";
447
448     if (prefix != NULL) {
449         // Note: parse ":$vmid:$loglevel:$chain: $msg"
450         if (prefix[0] == ':') {
451             char *p = prefix + 1;
452             guint32 tmpid = 0;
453             while(*p  >= '0' && *p <= '9') { tmpid *= 10; tmpid += *p - '0'; p++; }
454
455             if ((*p == ':') &&
456                 (p[1] >= '0' && p[1] <= '7') &&
457                 (p[2] == ':')) {
458
459                 guint8 tmp_level = p[1] - '0'; // store for later use
460                 char *chain_start = p + 3; // store for later use
461                 p = chain_start;
462                 while (*p && *p != ':' && *p != ' ') p++;
463                 int len = p - chain_start;
464
465                 if (*p == ':' && p[1] == ' ' && len && (len <= MAX_CHAIN_LEN)) {
466                     // parsing successful
467
468                     *p = 0; // terminate string
469
470                     vmid = tmpid;
471                     log_level = tmp_level;
472                     chain_name = chain_start;
473                     prefix = p + 2; // the rest
474                 }
475             }
476         }
477     }
478
479     LEPRINTF("%d ", vmid);
480
481     LEPRINTF("%d ", log_level);
482
483     LEPRINTF("%s ", chain_name);
484
485     struct timeval ts;
486     nflog_get_timestamp(ldata, &ts);
487
488     LEPRINTTIME(ts.tv_sec);
489
490     if (prefix != NULL) {
491         LEPRINTF("%s", prefix);
492     }
493
494     if (indev > 0) {
495         if (nlif_index2name(nlifh, indev, devname) != -1) {
496             LEPRINTF("IN=%s ", devname);
497         } else {
498             LEPRINTF("IN=%u ", indev);
499         }
500     }
501
502     if (outdev > 0) {
503         if (nlif_index2name(nlifh, outdev, devname) != -1) {
504             LEPRINTF("OUT=%s ", devname);
505         } else {
506             LEPRINTF("OUT=%u ", outdev);
507         }
508     }
509
510     if (physindev > 0) {
511         if (nlif_index2name(nlifh, physindev, devname) != -1) {
512             LEPRINTF("PHYSIN=%s ", devname);
513         } else {
514             LEPRINTF("PHYSIN=%u ", physindev);
515         }
516     }
517
518     if (physoutdev > 0) {
519         if (nlif_index2name(nlifh, physoutdev, devname) != -1) {
520             LEPRINTF("PHYSOUT=%s ", devname);
521         } else {
522             LEPRINTF("PHYSOUT=%u ", physoutdev);
523         }
524     }
525
526     int payload_len = nflog_get_payload(ldata, &payload);
527
528     int hwhdrlen = nflog_get_msg_packet_hwhdrlen(ldata);
529     if (hwhdrlen > 0) {
530         unsigned char *hwhdr = (unsigned char *)nflog_get_msg_packet_hwhdr(ldata);
531         if (hwhdr != NULL) {
532             int i;
533             LEPRINTF("MAC=");
534             for (i = 0; i < hwhdrlen; i++) {
535                 LEPRINTF("%02x", hwhdr[i]);
536                 if (i < (hwhdrlen -1 )) LEPRINTF(":");
537             }
538             LEPRINTF(" ");
539         }
540     }
541
542     u_int16_t hw_protocol = 0;
543     struct nfulnl_msg_packet_hdr *ph = NULL;
544
545     switch (family) {
546     case AF_INET:
547         print_iphdr(le, payload, payload_len);
548         break;
549     case AF_INET6:
550         print_ip6hdr(le, payload, payload_len);
551         break;
552     case AF_BRIDGE:
553         ph = nflog_get_msg_packet_hdr(ldata);
554         if (ph) hw_protocol = ntohs(ph->hw_protocol);
555
556         switch (hw_protocol) {
557         case ETH_P_IP:
558             print_iphdr(le, payload, payload_len);
559             break;
560         case ETH_P_IPV6:
561              print_ip6hdr(le, payload, payload_len);
562             break;
563         case ETH_P_ARP:
564             print_arp(le, (struct ether_arp *)payload, payload_len);
565             break;
566         }
567         break;
568     }
569
570     if (mark) LEPRINTF("mark=%u ", mark);
571
572
573     return 0;
574
575 }
576
577 static int
578 nflog_cb(struct nflog_g_handle *gh, struct nfgenmsg *nfmsg,
579                struct nflog_data *nfa, void *data)
580 {
581     struct log_entry *le = g_new0(struct log_entry, 1);
582
583     print_pkt(le, nfa, nfmsg->nfgen_family);
584
585     LEPRINTF("\n"); // add newline
586
587     queue_log_entry(le);
588
589     return 0;
590 }
591
592 static gboolean
593 nflog_read_cb(GIOChannel *source,
594               GIOCondition condition,
595               gpointer data)
596 {
597     int rv = 0;
598     gchar buf[8192];
599
600     int fd =  g_io_channel_unix_get_fd(source);
601
602     if ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
603          nflog_handle_packet(logh, buf, rv);
604     }
605
606     return TRUE;
607 }
608
609 static gboolean
610 nlif_read_cb(GIOChannel *source,
611              GIOCondition condition,
612              gpointer data)
613 {
614     static int last_res = 0;
615     int res;
616
617     if ((res = nlif_catch(nlifh)) < 0) {
618         if (last_res == 0) { // only report once
619             log_status_message(3, "nlif_catch failed (res = %d)", res);
620         }
621         last_res = res;
622     } else {
623         last_res = 0;
624     }
625
626     return TRUE;
627 }
628
629 static gboolean
630 signal_read_cb(GIOChannel *source,
631                GIOCondition condition,
632                gpointer data)
633 {
634     int rv = 0;
635     struct signalfd_siginfo si;
636
637     int fd =  g_io_channel_unix_get_fd(source);
638
639     if ((rv = read(fd, &si, sizeof(si))) && rv >= 0) {
640         terminate_threads = TRUE;
641         log_status_message(5, "received terminate request (signal)");
642         g_main_loop_quit(main_loop);
643     }
644
645     return TRUE;
646 }
647
648 int
649 main(int argc, char *argv[])
650 {
651     int lockfd = -1;
652     int sigfd = -1;
653
654     gboolean wrote_pidfile = FALSE;
655
656     g_thread_init(NULL);
657
658     openlog("pvepw-logger", LOG_CONS|LOG_PID, LOG_DAEMON);
659
660     GOptionContext *context;
661
662     GOptionEntry entries[] = {
663         { "debug", 'd', 0, G_OPTION_ARG_NONE, &debug, "Turn on debug messages", NULL },
664         { "foreground", 'f', 0, G_OPTION_ARG_NONE, &foreground, "Do not daemonize server", NULL },
665         { NULL },
666     };
667
668     context = g_option_context_new("");
669     g_option_context_add_main_entries (context, entries, NULL);
670
671     GError *err = NULL;
672     if (!g_option_context_parse (context, &argc, &argv, &err)) {
673         fprintf(stderr, "error: %s\n", err->message);
674         fprintf(stderr, "%s", g_option_context_get_help(context, FALSE, NULL));
675         g_error_free (err);
676         exit(-1);
677     }
678
679     if (optind < argc) {
680         fprintf(stderr, "error: too many arguments\n");
681         fprintf(stderr, "%s", g_option_context_get_help(context, FALSE, NULL));
682         exit(-1);
683     }
684
685     g_option_context_free(context);
686
687     if (debug) foreground = TRUE;
688
689     if ((lockfd = open(LOCKFILE, O_RDWR|O_CREAT|O_APPEND, 0644)) == -1) {
690         fprintf(stderr, "unable to create lock '%s': %s\n", LOCKFILE, strerror (errno) );
691         exit(-1);
692     }
693
694     for (int i = 10; i >= 0; i--) {
695         if (flock(lockfd, LOCK_EX|LOCK_NB) != 0) {
696             if (!i) {
697                 fprintf(stderr, "unable to aquire lock '%s': %s\n", LOCKFILE, strerror (errno));
698                 exit(-1);
699             }
700             if (i == 10)
701                 fprintf(stderr, "unable to aquire lock '%s' - trying again.\n", LOCKFILE);
702
703             sleep(1);
704         }
705     }
706
707     if ((outfd = open(LOGFILE, O_WRONLY|O_CREAT|O_APPEND, 0644)) == -1) {
708         fprintf(stderr, "unable to open file '%s': %s\n", LOGFILE, strerror (errno));
709         exit(-1);
710     }
711
712     if ((logh = nflog_open())  == NULL) {
713         fprintf(stderr, "unable to open nflog\n");
714         exit(-1);
715     }
716
717     if (!nflog_bind_pf(logh, AF_INET) <= 0) {
718         fprintf(stderr, "nflog_bind_pf AF_INET failed\n");
719         exit(-1);
720     }
721
722 #if 0
723     if (!nflog_bind_pf(logh, AF_INET6) <= 0) {
724         fprintf(stderr, "nflog_bind_pf AF_INET6 failed\n");
725         exit(-1);
726     }
727 #endif
728
729     if (!nflog_bind_pf(logh, AF_BRIDGE) <= 0) {
730         fprintf(stderr, "nflog_bind_pf AF_BRIDGE failed\n");
731         exit(-1);
732     }
733
734     struct nflog_g_handle *qh = nflog_bind_group(logh, 0);
735     if (!qh) {
736         fprintf(stderr, "no nflog handle for group 0\n");
737         exit(-1);
738     }
739
740     if (nflog_set_mode(qh, NFULNL_COPY_PACKET, 0xffff) < 0) {
741         fprintf(stderr, "can't set packet copy mode\n");
742         exit(-1);
743     }
744
745     if ((nlifh = nlif_open()) == NULL) {
746         fprintf(stderr, "unable to open netlink interface handle\n");
747         exit(-1);
748     }
749
750     sigset_t mask;
751     sigemptyset(&mask);
752     sigaddset(&mask, SIGINT);
753     sigaddset(&mask, SIGTERM);
754     
755     sigprocmask(SIG_BLOCK, &mask, NULL);
756
757     if ((sigfd = signalfd(-1, &mask, SFD_NONBLOCK)) < 0) {
758         fprintf(stderr, "unable to open signalfd: %s\n", strerror (errno));
759         exit(-1);
760     }
761
762     if (!foreground) {
763         pid_t cpid = fork();
764
765         if (cpid == -1) {
766             fprintf(stderr, "failed to daemonize program - %s\n", strerror (errno));
767             exit(-1);
768         } else if (cpid) {
769             write_pidfile(cpid);
770             _exit(0);
771         } else {
772             int nullfd;
773
774             if (chroot("/") != 0) fprintf(stderr, "chroot '/' failed - %s\n", strerror (errno));
775
776             if ((nullfd = open("/dev/null", O_RDWR, 0)) != -1) {
777                 dup2(nullfd, 0);
778                 dup2(nullfd, 1);
779                 dup2(nullfd, 2);
780                 if (nullfd > 2)
781                     close (nullfd);
782             }
783
784             setsid();
785         }
786     } else {
787         write_pidfile(getpid());
788     }
789
790     wrote_pidfile = TRUE;
791
792     nflog_callback_register(qh, &nflog_cb, logh);
793
794     queue = g_async_queue_new_full(g_free);
795
796     log_status_message(5, "starting pvefw logger");
797
798     nlif_query(nlifh);
799
800     GIOChannel *nlif_ch = g_io_channel_unix_new(nlif_fd(nlifh));
801
802     g_io_add_watch(nlif_ch, G_IO_IN, nlif_read_cb, NULL);
803
804     int logfd = nflog_fd(logh);
805     GIOChannel *nflog_ch = g_io_channel_unix_new(logfd);
806
807     g_io_add_watch(nflog_ch, G_IO_IN, nflog_read_cb, NULL);
808
809     GIOChannel *sig_ch = g_io_channel_unix_new(sigfd);
810     if (!g_io_add_watch(sig_ch, G_IO_IN, signal_read_cb, NULL)) {
811         exit(-1);
812     }
813
814     GThread *wthread = g_thread_new("log_writer_thread", log_writer_thread, NULL);
815
816     main_loop = g_main_loop_new(NULL, TRUE);
817
818     g_main_loop_run(main_loop);
819
820     log_status_message(5, "stopping pvefw logger");
821
822     g_thread_join(wthread);
823
824     close(outfd);
825
826     nflog_close(logh);
827
828     if (wrote_pidfile)
829         unlink(PIDFILE);
830
831     exit(0);
832 }