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