2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2011 Daniel Borkmann.
5 * Copyright 2011 Emmanuel Roullit.
6 * Subject to the GPL, version 2.
8 * A tiny tool to provide top-like netfilter connection tracking information.
10 * The Dark Lord has Nine. But we have One, mightier than they: the White
11 * Rider. He has passed through the fire and the abyss, and they shall
12 * fear him. We will go where he leads.
14 * -- The Lord of the Rings, Aragorn,
15 * Chapter 'The White Rider'.
19 * Debian: apt-get install libnetfilter-conntrack3 libnetfilter-conntrack-dev
20 * liburcu0 liburcu-dev
22 * Start conntrack (if not yet running):
23 * iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT
24 * iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT
31 flowtop - provide top-like netfilter connection tracking information
35 flowtop [--city-db <path>][--country-db <path>]
36 [-T|--tcp][-U|--udp][-v|--version][-h|--help]
40 flowtop is a tiny tool to print human-readable
41 netfilter connection tracking information.
55 =item flowtop --city-db /usr/share/GeoIP/GeoIPCity.dat
57 Use the specified GeoIP city database
59 =item flowtop --country-db /usr/share/GeoIP/GeoIP.dat
61 Use the specified GeoIP country database
71 Only show TCP flows (default)
79 Also include flow source in top output
83 Path to GeoIP city database
87 Path to GeoIP country database
95 Print help text and lists all options.
101 Written by Daniel Borkmann <daniel@netsniff-ng.org>
105 Documentation by Emmanuel Roullit <emmanuel@netsniff-ng.org>
109 Please report bugs to <bugs@netsniff-ng.org>
125 #include <libnetfilter_conntrack/libnetfilter_conntrack.h>
126 #include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
128 #include <GeoIPCity.h>
129 #include <netinet/in.h>
132 #include <sys/stat.h>
140 #include "built_in.h"
142 #include "dissector_eth.h"
144 #define INCLUDE_UDP (1 << 0)
145 #define INCLUDE_TCP (1 << 1)
147 #ifndef ATTR_TIMESTAMP_START
148 # define ATTR_TIMESTAMP_START 63
150 #ifndef ATTR_TIMESTAMP_STOP
151 # define ATTR_TIMESTAMP_STOP 64
154 #define SCROLL_MAX 1000
159 struct flow_entry
*next
;
164 uint32_t ip4_src_addr
;
165 uint32_t ip4_dst_addr
;
166 uint32_t ip6_src_addr
[4];
167 uint32_t ip6_dst_addr
[4];
172 uint64_t counter_pkts
;
173 uint64_t counter_bytes
;
174 uint64_t timestamp_start
;
175 uint64_t timestamp_stop
;
176 char country_src
[128];
178 char rev_dns_src
[256];
179 char country_dst
[128];
181 char rev_dns_dst
[256];
188 struct flow_entry
*head
;
189 struct spinlock lock
;
192 volatile sig_atomic_t sigint
= 0;
194 static int what
= INCLUDE_TCP
;
196 static int show_src
= 0;
198 static struct flow_list flow_list
;
200 static GeoIP
*gi_country
= NULL
;
201 static GeoIP
*gi_city
= NULL
;
203 static char *path_city_db
= NULL
, *path_country_db
= NULL
;
205 static const char *short_options
= "vhTULKs";
207 static struct option long_options
[] = {
208 {"tcp", no_argument
, 0, 'T'},
209 {"udp", no_argument
, 0, 'U'},
210 {"show-src", no_argument
, 0, 's'},
211 {"city-db", required_argument
, 0, 'L'},
212 {"country-db", required_argument
, 0, 'K'},
213 {"version", no_argument
, 0, 'v'},
214 {"help", no_argument
, 0, 'h'},
218 const char *const l3proto2str
[AF_MAX
] = {
223 const char *const proto2str
[IPPROTO_MAX
] = {
224 [IPPROTO_TCP
] = "tcp",
225 [IPPROTO_UDP
] = "udp",
226 [IPPROTO_UDPLITE
] = "udplite",
227 [IPPROTO_ICMP
] = "icmp",
228 [IPPROTO_ICMPV6
] = "icmpv6",
229 [IPPROTO_SCTP
] = "sctp",
230 [IPPROTO_GRE
] = "gre",
231 [IPPROTO_DCCP
] = "dccp",
232 [IPPROTO_IGMP
] = "igmp",
233 [IPPROTO_IPIP
] = "ipip",
234 [IPPROTO_EGP
] = "egp",
235 [IPPROTO_PUP
] = "pup",
236 [IPPROTO_IDP
] = "idp",
237 [IPPROTO_RSVP
] = "rsvp",
238 [IPPROTO_IPV6
] = "ip6tun",
239 [IPPROTO_ESP
] = "esp",
241 [IPPROTO_PIM
] = "pim",
242 [IPPROTO_COMP
] = "comp",
245 const char *const state2str
[TCP_CONNTRACK_MAX
] = {
246 [TCP_CONNTRACK_NONE
] = "NOSTATE",
247 [TCP_CONNTRACK_SYN_SENT
] = "SYN_SENT",
248 [TCP_CONNTRACK_SYN_RECV
] = "SYN_RECV",
249 [TCP_CONNTRACK_ESTABLISHED
] = "ESTABLISHED",
250 [TCP_CONNTRACK_FIN_WAIT
] = "FIN_WAIT",
251 [TCP_CONNTRACK_CLOSE_WAIT
] = "CLOSE_WAIT",
252 [TCP_CONNTRACK_LAST_ACK
] = "LAST_ACK",
253 [TCP_CONNTRACK_TIME_WAIT
] = "TIME_WAIT",
254 [TCP_CONNTRACK_CLOSE
] = "CLOSE",
255 [TCP_CONNTRACK_SYN_SENT2
] = "SYN_SENT2",
258 const uint8_t states
[] = {
259 TCP_CONNTRACK_SYN_SENT
,
260 TCP_CONNTRACK_SYN_RECV
,
261 TCP_CONNTRACK_ESTABLISHED
,
262 TCP_CONNTRACK_FIN_WAIT
,
263 TCP_CONNTRACK_CLOSE_WAIT
,
264 TCP_CONNTRACK_LAST_ACK
,
265 TCP_CONNTRACK_TIME_WAIT
,
267 TCP_CONNTRACK_SYN_SENT2
,
271 static void signal_handler(int number
)
283 static void help(void)
285 printf("\nflowtop %s, top-like netfilter TCP/UDP flow tracking\n",
287 printf("http://www.netsniff-ng.org\n\n");
288 printf("Usage: flowtop [options]\n");
289 printf("Options:\n");
290 printf(" -T|--tcp Show only TCP flows (default)\n");
291 printf(" -U|--udp Show only UDP flows\n");
292 printf(" -s|--show-src Also show source, not only dest\n");
293 printf(" --city-db <path> Specifiy path for geoip city database\n");
294 printf(" --country-db <path> Specifiy path for geoip country database\n");
295 printf(" -v|--version Print version\n");
296 printf(" -h|--help Print this help\n");
298 printf("Examples:\n");
299 printf(" flowtop\n");
300 printf(" flowtop -s\n\n");
302 printf(" If netfilter is not running, you can activate it with i.e.:\n");
303 printf(" iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT\n");
304 printf(" iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT\n");
306 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
307 printf("Copyright (C) 2011-2012 Daniel Borkmann <daniel@netsniff-ng.org>\n");
308 printf("Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel@netsniff-ng.org>\n");
309 printf("License: GNU GPL version 2\n");
310 printf("This is free software: you are free to change and redistribute it.\n");
311 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
315 static void version(void)
317 printf("\nflowtop %s, top-like netfilter TCP/UDP flow tracking\n",
319 printf("http://www.netsniff-ng.org\n\n");
320 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
321 printf("Copyright (C) 2011-2012 Daniel Borkmann <daniel@netsniff-ng.org>\n");
322 printf("Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel@netsniff-ng.org>\n");
323 printf("License: GNU GPL version 2\n");
324 printf("This is free software: you are free to change and redistribute it.\n");
325 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
329 static void screen_init(WINDOW
**screen
)
331 (*screen
) = initscr();
334 keypad(stdscr
, TRUE
);
335 nodelay(*screen
, TRUE
);
340 static inline uint16_t get_port(uint16_t src
, uint16_t dst
)
347 /* XXX: Is there a better way to determine? */
348 if (src
< dst
&& src
< 1024) {
350 } else if (dst
< src
&& dst
< 1024) {
353 tmp1
= lookup_port_tcp(src
);
354 tmp2
= lookup_port_tcp(dst
);
357 } else if (!tmp1
&& tmp2
) {
368 static void screen_update(WINDOW
*screen
, struct flow_list
*fl
, int skip_lines
)
372 struct flow_entry
*n
;
375 getmaxyx(screen
, maxy
, maxx
);
378 init_pair(1, COLOR_RED
, COLOR_BLACK
);
379 init_pair(2, COLOR_BLUE
, COLOR_BLACK
);
380 init_pair(3, COLOR_YELLOW
, COLOR_BLACK
);
381 init_pair(4, COLOR_GREEN
, COLOR_BLACK
);
387 mvwprintw(screen
, 1, 2, "Kernel netfilter TCP/UDP flow statistics, [+%d]",
390 if (rcu_dereference(fl
->head
) == NULL
)
391 mvwprintw(screen
, line
, 2, "(No active sessions! Is netfilter running?)");
394 /* Yes, that's lame :-P */
395 for (i
= 0; i
< sizeof(states
); i
++) {
396 n
= rcu_dereference(fl
->head
);
398 while (n
&& maxy
> 0) {
401 if (n
->tcp_state
!= states
[i
] ||
402 (i
!= TCP_CONNTRACK_NONE
&&
403 n
->tcp_state
== TCP_CONNTRACK_NONE
) ||
405 get_port(n
->port_src
, n
->port_dst
) == 53) {
406 n
= rcu_dereference(n
->next
);
410 if (skip_lines
> 0) {
411 n
= rcu_dereference(n
->next
);
416 snprintf(tmp
, sizeof(tmp
), "%u/%s", n
->procnum
,
417 basename(n
->cmdline
));
418 tmp
[sizeof(tmp
) - 1] = 0;
420 mvwprintw(screen
, line
, 2, "[");
421 attron(COLOR_PAIR(3));
422 printw("%s", n
->procnum
> 0 ? tmp
: "bridged(?)");
423 attroff(COLOR_PAIR(3));
424 printw("]:%s:%s[", l3proto2str
[n
->l3_proto
],
425 proto2str
[n
->l4_proto
]);
426 attron(COLOR_PAIR(3));
427 printw("%s", state2str
[n
->tcp_state
]);
428 attroff(COLOR_PAIR(3));
431 if (n
->tcp_state
!= TCP_CONNTRACK_NONE
) {
432 printw("%s -> ", lookup_port_tcp(get_port(n
->port_src
,
435 printw("%s -> ", lookup_port_udp(get_port(n
->port_src
,
440 attron(COLOR_PAIR(1));
441 mvwprintw(screen
, ++line
, 8, "src: %s", n
->rev_dns_src
);
442 attroff(COLOR_PAIR(1));
443 printw(":%u (", ntohs(n
->port_src
));
444 attron(COLOR_PAIR(4));
445 printw("%s", (strlen(n
->country_src
) > 0 ?
446 n
->country_src
: "N/A"));
447 attroff(COLOR_PAIR(4));
448 printw(", %s) => ", (strlen(n
->city_src
) > 0 ?
449 n
->city_src
: "N/A"));
451 attron(COLOR_PAIR(2));
452 mvwprintw(screen
, ++line
, 8, "dst: %s", n
->rev_dns_dst
);
453 attroff(COLOR_PAIR(2));
454 printw(":%u (", ntohs(n
->port_dst
));
455 attron(COLOR_PAIR(4));
456 printw("%s", strlen(n
->country_dst
) > 0 ?
457 n
->country_dst
: "N/A");
458 attroff(COLOR_PAIR(4));
459 printw(", %s)", strlen(n
->city_dst
) > 0 ?
460 n
->city_dst
: "N/A");
464 n
= rcu_dereference(n
->next
);
474 static void screen_end(void)
479 static void presenter(void)
482 WINDOW
*screen
= NULL
;
484 dissector_init_ethernet(0);
485 screen_init(&screen
);
486 rcu_register_thread();
504 if (skip_lines
> SCROLL_MAX
)
505 skip_lines
= SCROLL_MAX
;
512 screen_update(screen
, &flow_list
, skip_lines
);
516 rcu_unregister_thread();
518 dissector_cleanup_ethernet();
521 static inline const char *make_n_a(const char *p
)
526 static void walk_process(char *process
, struct flow_entry
*n
)
533 if (snprintf(path
, sizeof(path
), "/proc/%s/fd", process
) == -1)
534 panic("giant process name! %s\n", process
);
540 while ((ent
= readdir(dir
))) {
543 if (snprintf(path
, sizeof(path
), "/proc/%s/fd/%s",
544 process
, ent
->d_name
) < 0)
546 if (stat(path
, &statbuf
) < 0)
548 if (S_ISSOCK(statbuf
.st_mode
) && n
->inode
== statbuf
.st_ino
) {
549 memset(n
->cmdline
, 0, sizeof(n
->cmdline
));
550 snprintf(path
, sizeof(path
), "/proc/%s/exe", process
);
551 rc
= readlink(path
, n
->cmdline
, sizeof(n
->cmdline
) - 1);
554 panic("readlink error: %s\n", strerror(errno
));
556 n
->procnum
= atoi(process
);
563 /* Derived from ifpromisc, Fred N. van Kempen, GPL v2.0 */
564 /* n->inode must be set */
565 static void walk_processes(struct flow_entry
*n
)
571 memset(n
->cmdline
, 0, sizeof(n
->cmdline
));
575 dir
= opendir("/proc");
577 panic("Cannot open /proc!\n");
579 while ((ent
= readdir(dir
)))
580 if (strspn(ent
->d_name
, "0123456789") == strlen(ent
->d_name
))
581 walk_process(ent
->d_name
, n
);
586 static int get_inode_from_local_port(int port
, const char *proto
, int ip6
)
593 memset(path
, 0, sizeof(path
));
594 snprintf(path
, sizeof(path
), "/proc/net/%s%s", proto
, ip6
? "6" : "");
595 proc
= fopen(path
, "r");
598 memset(buff
, 0, sizeof(buff
));
599 while (fgets(buff
, sizeof(buff
), proc
) != NULL
) {
600 int lport
= 0, inode
= 0;
601 buff
[sizeof(buff
) - 1] = 0;
602 if (sscanf(buff
, "%*u: %*X:%X %*X:%*X %*X %*X:%*X %*X:%*X "
603 "%*X %*u %*u %u", &lport
, &inode
) == 2) {
609 memset(buff
, 0, sizeof(buff
));
616 static void flow_entry_from_ct(struct flow_entry
*n
, struct nf_conntrack
*ct
)
618 n
->flow_id
= nfct_get_attr_u32(ct
, ATTR_ID
);
619 n
->use
= nfct_get_attr_u32(ct
, ATTR_USE
);
620 n
->status
= nfct_get_attr_u32(ct
, ATTR_STATUS
);
621 n
->l3_proto
= nfct_get_attr_u8(ct
, ATTR_ORIG_L3PROTO
);
622 n
->l4_proto
= nfct_get_attr_u8(ct
, ATTR_ORIG_L4PROTO
);
623 n
->ip4_src_addr
= nfct_get_attr_u32(ct
, ATTR_ORIG_IPV4_SRC
);
624 n
->ip4_dst_addr
= nfct_get_attr_u32(ct
, ATTR_ORIG_IPV4_DST
);
626 const uint8_t *ipv6_src
= nfct_get_attr(ct
, ATTR_ORIG_IPV6_SRC
);
628 memcpy(n
->ip6_src_addr
, ipv6_src
, sizeof(n
->ip6_src_addr
));
629 const uint8_t *ipv6_dst
= nfct_get_attr(ct
, ATTR_ORIG_IPV6_DST
);
631 memcpy(n
->ip6_dst_addr
, ipv6_dst
, sizeof(n
->ip6_dst_addr
));
633 n
->port_src
= nfct_get_attr_u16(ct
, ATTR_ORIG_PORT_SRC
);
634 n
->port_dst
= nfct_get_attr_u16(ct
, ATTR_ORIG_PORT_DST
);
635 n
->tcp_state
= nfct_get_attr_u8(ct
, ATTR_TCP_STATE
);
636 n
->tcp_flags
= nfct_get_attr_u8(ct
, ATTR_TCP_FLAGS_ORIG
);
637 n
->counter_pkts
= nfct_get_attr_u64(ct
, ATTR_ORIG_COUNTER_PACKETS
);
638 n
->counter_bytes
= nfct_get_attr_u64(ct
, ATTR_ORIG_COUNTER_BYTES
);
639 n
->timestamp_start
= nfct_get_attr_u64(ct
, ATTR_TIMESTAMP_START
);
640 n
->timestamp_stop
= nfct_get_attr_u64(ct
, ATTR_TIMESTAMP_STOP
);
643 n
->inode
= get_inode_from_local_port(ntohs(n
->port_src
),
644 proto2str
[n
->l4_proto
],
649 /* if this really runs on a router, we try it once and then let it be */
653 /* TODO: IP4 + IP6 */
654 static void flow_entry_get_extended(struct flow_entry
*n
)
656 struct sockaddr_in sa
;
657 struct hostent
*hent
;
658 GeoIPRecord
*gir_src
, *gir_dst
;
662 if (ntohs(n
->port_src
) == 53 || ntohs(n
->port_dst
) == 53)
665 memset(&sa
, 0, sizeof(sa
));
666 sa
.sin_family
= PF_INET
; //XXX: IPv4
667 sa
.sin_addr
.s_addr
= n
->ip4_src_addr
;
668 getnameinfo((struct sockaddr
*) &sa
, sizeof(sa
), n
->rev_dns_src
,
669 sizeof(n
->rev_dns_src
), NULL
, 0, NI_NUMERICHOST
);
671 hent
= gethostbyaddr(&sa
.sin_addr
, sizeof(sa
.sin_addr
), PF_INET
);
673 memset(n
->rev_dns_src
, 0, sizeof(n
->rev_dns_src
));
674 memcpy(n
->rev_dns_src
, hent
->h_name
,
675 min(sizeof(n
->rev_dns_src
), strlen(hent
->h_name
)));
678 gir_src
= GeoIP_record_by_ipnum(gi_city
, ntohl(n
->ip4_src_addr
));
680 const char *country
=
681 make_n_a(GeoIP_country_name_by_ipnum(gi_country
,
682 ntohl(n
->ip4_src_addr
)));
683 const char *city
= make_n_a(gir_src
->city
);
684 memcpy(n
->country_src
, country
,
685 min(sizeof(n
->country_src
), strlen(country
)));
686 memcpy(n
->city_src
, city
,
687 min(sizeof(n
->city_src
), strlen(city
)));
690 memset(&sa
, 0, sizeof(sa
));
691 sa
.sin_family
= PF_INET
; //XXX: IPv4
692 sa
.sin_addr
.s_addr
= n
->ip4_dst_addr
;
693 getnameinfo((struct sockaddr
*) &sa
, sizeof(sa
), n
->rev_dns_dst
,
694 sizeof(n
->rev_dns_dst
), NULL
, 0, NI_NUMERICHOST
);
696 hent
= gethostbyaddr(&sa
.sin_addr
, sizeof(sa
.sin_addr
), PF_INET
);
698 memset(n
->rev_dns_dst
, 0, sizeof(n
->rev_dns_dst
));
699 memcpy(n
->rev_dns_dst
, hent
->h_name
,
700 min(sizeof(n
->rev_dns_dst
), strlen(hent
->h_name
)));
703 gir_dst
= GeoIP_record_by_ipnum(gi_city
, ntohl(n
->ip4_dst_addr
));
705 const char *country
=
706 make_n_a(GeoIP_country_name_by_ipnum(gi_country
,
707 ntohl(n
->ip4_dst_addr
)));
708 const char *city
= make_n_a(gir_dst
->city
);
709 memcpy(n
->country_dst
, country
,
710 min(sizeof(n
->country_dst
), strlen(country
)));
711 memcpy(n
->city_dst
, city
,
712 min(sizeof(n
->city_dst
), strlen(city
)));
716 static void flow_list_init(struct flow_list
*fl
)
719 spinlock_init(&fl
->lock
);
722 static struct flow_entry
*__flow_list_find_by_id(struct flow_list
*fl
, uint32_t id
)
724 struct flow_entry
*n
= rcu_dereference(fl
->head
);
726 if (n
->flow_id
== id
)
728 n
= rcu_dereference(n
->next
);
733 static struct flow_entry
*__flow_list_find_prev_by_id(struct flow_list
*fl
, uint32_t id
)
735 struct flow_entry
*n
= rcu_dereference(fl
->head
);
736 if (n
->flow_id
== id
)
738 while (rcu_dereference(n
->next
) != NULL
) {
739 if (rcu_dereference(n
->next
)->flow_id
== id
)
741 n
= rcu_dereference(n
->next
);
746 static void flow_list_new_entry(struct flow_list
*fl
, struct nf_conntrack
*ct
)
748 struct flow_entry
*n
= xzmalloc(sizeof(*n
));
750 rcu_assign_pointer(n
->next
, fl
->head
);
751 rcu_assign_pointer(fl
->head
, n
);
752 flow_entry_from_ct(n
, ct
);
753 flow_entry_get_extended(n
);
756 static void flow_list_update_entry(struct flow_list
*fl
, struct nf_conntrack
*ct
)
759 uint32_t id
= nfct_get_attr_u32(ct
, ATTR_ID
);
760 struct flow_entry
*n
;
761 n
= __flow_list_find_by_id(fl
, id
);
763 n
= xzmalloc(sizeof(*n
));
765 rcu_assign_pointer(n
->next
, fl
->head
);
766 rcu_assign_pointer(fl
->head
, n
);
769 flow_entry_from_ct(n
, ct
);
771 flow_entry_get_extended(n
);
774 static void flow_list_destroy_entry(struct flow_list
*fl
, struct nf_conntrack
*ct
)
776 uint32_t id
= nfct_get_attr_u32(ct
, ATTR_ID
);
777 struct flow_entry
*n1
, *n2
;
779 n1
= __flow_list_find_by_id(fl
, id
);
781 n2
= __flow_list_find_prev_by_id(fl
, id
);
783 rcu_assign_pointer(n2
->next
, n1
->next
);
784 rcu_assign_pointer(n1
->next
, NULL
);
788 rcu_assign_pointer(fl
->head
, NULL
);
793 static void flow_list_destroy(struct flow_list
*fl
)
795 struct flow_entry
*n
;
797 while (fl
->head
!= NULL
) {
798 n
= rcu_dereference(fl
->head
->next
);
799 rcu_assign_pointer(fl
->head
->next
, NULL
);
801 rcu_assign_pointer(fl
->head
, n
);
805 spinlock_destroy(&fl
->lock
);
808 static int collector_cb(enum nf_conntrack_msg_type type
,
809 struct nf_conntrack
*ct
,
817 spinlock_lock(&flow_list
.lock
);
820 flow_list_new_entry(&flow_list
, ct
);
823 flow_list_update_entry(&flow_list
, ct
);
826 flow_list_destroy_entry(&flow_list
, ct
);
831 spinlock_unlock(&flow_list
.lock
);
833 return NFCT_CB_CONTINUE
;
836 static int dummy_cb(enum nf_conntrack_msg_type type
, struct nf_conntrack
*ct
,
842 static void *collector(void *null
)
845 u_int32_t family
= AF_INET
;
846 struct nfct_handle
*handle
;
847 struct nfct_filter
*filter
;
849 handle
= nfct_open(CONNTRACK
, NFCT_ALL_CT_GROUPS
);
851 panic("Cannot create a nfct handle!\n");
854 nfct_callback_register(handle
, NFCT_T_ALL
, dummy_cb
, NULL
);
855 nfct_query(handle
, NFCT_Q_DUMP
, &family
);
858 handle
= nfct_open(CONNTRACK
, NFCT_ALL_CT_GROUPS
);
860 panic("Cannot create a nfct handle!\n");
862 nfct_query(handle
, NFCT_Q_FLUSH
, &family
);
864 filter
= nfct_filter_create();
866 panic("Cannot create a nfct filter!\n");
867 if (what
& INCLUDE_UDP
)
868 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_UDP
);
869 if (what
& INCLUDE_TCP
)
870 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_TCP
);
872 struct nfct_filter_ipv4 filter_ipv4
= {
873 .addr
= ntohl(INADDR_LOOPBACK
),
877 nfct_filter_set_logic(filter
, NFCT_FILTER_SRC_IPV4
,
878 NFCT_FILTER_LOGIC_NEGATIVE
);
879 nfct_filter_add_attr(filter
, NFCT_FILTER_SRC_IPV4
, &filter_ipv4
);
881 struct nfct_filter_ipv6 filter_ipv6
= {
882 .addr
= { 0x0, 0x0, 0x0, 0x1 },
883 .mask
= { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff },
886 nfct_filter_set_logic(filter
, NFCT_FILTER_SRC_IPV6
,
887 NFCT_FILTER_LOGIC_NEGATIVE
);
888 nfct_filter_add_attr(filter
, NFCT_FILTER_SRC_IPV6
, &filter_ipv6
);
890 ret
= nfct_filter_attach(nfct_fd(handle
), filter
);
892 panic("Cannot attach filter to handle!\n");
894 nfct_filter_destroy(filter
);
897 gi_country
= GeoIP_open(path_country_db
, GEOIP_MMAP_CACHE
);
899 gi_country
= GeoIP_open_type(GEOIP_COUNTRY_EDITION
,
903 gi_city
= GeoIP_open(path_city_db
, GEOIP_MMAP_CACHE
);
905 gi_city
= GeoIP_open_type(GEOIP_CITY_EDITION_REV1
,
907 if (!gi_country
|| !gi_city
)
908 panic("Cannot open GeoIP database!\n");
910 GeoIP_set_charset(gi_country
, GEOIP_CHARSET_UTF8
);
911 GeoIP_set_charset(gi_city
, GEOIP_CHARSET_UTF8
);
913 flow_list_init(&flow_list
);
915 rcu_register_thread();
917 nfct_callback_register(handle
, NFCT_T_ALL
, collector_cb
, NULL
);
922 rcu_unregister_thread();
924 flow_list_destroy(&flow_list
);
926 GeoIP_delete(gi_city
);
927 GeoIP_delete(gi_country
);
934 xfree(path_country_db
);
939 int main(int argc
, char **argv
)
942 int ret
, c
, opt_index
, what_cmd
= 0;
944 check_for_root_maybe_die();
946 while ((c
= getopt_long(argc
, argv
, short_options
, long_options
,
947 &opt_index
)) != EOF
) {
950 what_cmd
|= INCLUDE_TCP
;
953 what_cmd
|= INCLUDE_UDP
;
959 path_city_db
= xstrdup(optarg
);
962 path_country_db
= xstrdup(optarg
);
974 panic("Option -%c requires an argument!\n",
978 whine("Unknown option character "
979 "`0x%X\'!\n", optopt
);
992 register_signal(SIGINT
, signal_handler
);
993 register_signal(SIGHUP
, signal_handler
);
995 ret
= pthread_create(&tid
, NULL
, collector
, NULL
);
997 panic("Cannot create phthread!\n");