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"
143 #include "pkt_buff.h"
145 #define INCLUDE_UDP (1 << 0)
146 #define INCLUDE_TCP (1 << 1)
148 #ifndef ATTR_TIMESTAMP_START
149 # define ATTR_TIMESTAMP_START 63
151 #ifndef ATTR_TIMESTAMP_STOP
152 # define ATTR_TIMESTAMP_STOP 64
155 #define SCROLL_MAX 1000
160 struct flow_entry
*next
;
165 uint32_t ip4_src_addr
;
166 uint32_t ip4_dst_addr
;
167 uint32_t ip6_src_addr
[4];
168 uint32_t ip6_dst_addr
[4];
173 uint64_t counter_pkts
;
174 uint64_t counter_bytes
;
175 uint64_t timestamp_start
;
176 uint64_t timestamp_stop
;
177 char country_src
[128];
179 char rev_dns_src
[256];
180 char country_dst
[128];
182 char rev_dns_dst
[256];
189 struct flow_entry
*head
;
190 struct spinlock lock
;
193 volatile sig_atomic_t sigint
= 0;
195 static int what
= INCLUDE_TCP
;
197 static int show_src
= 0;
199 static struct flow_list flow_list
;
201 static GeoIP
*gi_country
= NULL
;
202 static GeoIP
*gi_city
= NULL
;
204 static char *path_city_db
= NULL
, *path_country_db
= NULL
;
206 static const char *short_options
= "vhTULKs";
208 static struct option long_options
[] = {
209 {"tcp", no_argument
, 0, 'T'},
210 {"udp", no_argument
, 0, 'U'},
211 {"show-src", no_argument
, 0, 's'},
212 {"city-db", required_argument
, 0, 'L'},
213 {"country-db", required_argument
, 0, 'K'},
214 {"version", no_argument
, 0, 'v'},
215 {"help", no_argument
, 0, 'h'},
219 const char *const l3proto2str
[AF_MAX
] = {
224 const char *const proto2str
[IPPROTO_MAX
] = {
225 [IPPROTO_TCP
] = "tcp",
226 [IPPROTO_UDP
] = "udp",
227 [IPPROTO_UDPLITE
] = "udplite",
228 [IPPROTO_ICMP
] = "icmp",
229 [IPPROTO_ICMPV6
] = "icmpv6",
230 [IPPROTO_SCTP
] = "sctp",
231 [IPPROTO_GRE
] = "gre",
232 [IPPROTO_DCCP
] = "dccp",
233 [IPPROTO_IGMP
] = "igmp",
234 [IPPROTO_IPIP
] = "ipip",
235 [IPPROTO_EGP
] = "egp",
236 [IPPROTO_PUP
] = "pup",
237 [IPPROTO_IDP
] = "idp",
238 [IPPROTO_RSVP
] = "rsvp",
239 [IPPROTO_IPV6
] = "ip6tun",
240 [IPPROTO_ESP
] = "esp",
242 [IPPROTO_PIM
] = "pim",
243 [IPPROTO_COMP
] = "comp",
246 const char *const state2str
[TCP_CONNTRACK_MAX
] = {
247 [TCP_CONNTRACK_NONE
] = "NOSTATE",
248 [TCP_CONNTRACK_SYN_SENT
] = "SYN_SENT",
249 [TCP_CONNTRACK_SYN_RECV
] = "SYN_RECV",
250 [TCP_CONNTRACK_ESTABLISHED
] = "ESTABLISHED",
251 [TCP_CONNTRACK_FIN_WAIT
] = "FIN_WAIT",
252 [TCP_CONNTRACK_CLOSE_WAIT
] = "CLOSE_WAIT",
253 [TCP_CONNTRACK_LAST_ACK
] = "LAST_ACK",
254 [TCP_CONNTRACK_TIME_WAIT
] = "TIME_WAIT",
255 [TCP_CONNTRACK_CLOSE
] = "CLOSE",
256 [TCP_CONNTRACK_SYN_SENT2
] = "SYN_SENT2",
259 const uint8_t states
[] = {
260 TCP_CONNTRACK_SYN_SENT
,
261 TCP_CONNTRACK_SYN_RECV
,
262 TCP_CONNTRACK_ESTABLISHED
,
263 TCP_CONNTRACK_FIN_WAIT
,
264 TCP_CONNTRACK_CLOSE_WAIT
,
265 TCP_CONNTRACK_LAST_ACK
,
266 TCP_CONNTRACK_TIME_WAIT
,
268 TCP_CONNTRACK_SYN_SENT2
,
272 static void signal_handler(int number
)
284 static void help(void)
286 printf("\nflowtop %s, top-like netfilter TCP/UDP flow tracking\n",
288 printf("http://www.netsniff-ng.org\n\n");
289 printf("Usage: flowtop [options]\n");
290 printf("Options:\n");
291 printf(" -T|--tcp Show only TCP flows (default)\n");
292 printf(" -U|--udp Show only UDP flows\n");
293 printf(" -s|--show-src Also show source, not only dest\n");
294 printf(" --city-db <path> Specifiy path for geoip city database\n");
295 printf(" --country-db <path> Specifiy path for geoip country database\n");
296 printf(" -v|--version Print version\n");
297 printf(" -h|--help Print this help\n");
299 printf("Examples:\n");
300 printf(" flowtop\n");
301 printf(" flowtop -s\n\n");
303 printf(" If netfilter is not running, you can activate it with i.e.:\n");
304 printf(" iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT\n");
305 printf(" iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT\n");
307 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
308 printf("Copyright (C) 2011-2012 Daniel Borkmann <daniel@netsniff-ng.org>\n");
309 printf("Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel@netsniff-ng.org>\n");
310 printf("License: GNU GPL version 2\n");
311 printf("This is free software: you are free to change and redistribute it.\n");
312 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
316 static void version(void)
318 printf("\nflowtop %s, top-like netfilter TCP/UDP flow tracking\n",
320 printf("http://www.netsniff-ng.org\n\n");
321 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
322 printf("Copyright (C) 2011-2012 Daniel Borkmann <daniel@netsniff-ng.org>\n");
323 printf("Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel@netsniff-ng.org>\n");
324 printf("License: GNU GPL version 2\n");
325 printf("This is free software: you are free to change and redistribute it.\n");
326 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
330 static void screen_init(WINDOW
**screen
)
332 (*screen
) = initscr();
335 keypad(stdscr
, TRUE
);
336 nodelay(*screen
, TRUE
);
341 static inline uint16_t get_port(uint16_t src
, uint16_t dst
)
348 /* XXX: Is there a better way to determine? */
349 if (src
< dst
&& src
< 1024) {
351 } else if (dst
< src
&& dst
< 1024) {
354 tmp1
= lookup_port_tcp(src
);
355 tmp2
= lookup_port_tcp(dst
);
358 } else if (!tmp1
&& tmp2
) {
369 static void screen_update(WINDOW
*screen
, struct flow_list
*fl
, int skip_lines
)
373 struct flow_entry
*n
;
376 getmaxyx(screen
, maxy
, maxx
);
379 init_pair(1, COLOR_RED
, COLOR_BLACK
);
380 init_pair(2, COLOR_BLUE
, COLOR_BLACK
);
381 init_pair(3, COLOR_YELLOW
, COLOR_BLACK
);
382 init_pair(4, COLOR_GREEN
, COLOR_BLACK
);
388 mvwprintw(screen
, 1, 2, "Kernel netfilter TCP/UDP flow statistics, [+%d]",
391 if (rcu_dereference(fl
->head
) == NULL
)
392 mvwprintw(screen
, line
, 2, "(No active sessions! Is netfilter running?)");
395 /* Yes, that's lame :-P */
396 for (i
= 0; i
< sizeof(states
); i
++) {
397 n
= rcu_dereference(fl
->head
);
399 while (n
&& maxy
> 0) {
402 if (n
->tcp_state
!= states
[i
] ||
403 (i
!= TCP_CONNTRACK_NONE
&&
404 n
->tcp_state
== TCP_CONNTRACK_NONE
) ||
406 get_port(n
->port_src
, n
->port_dst
) == 53) {
407 n
= rcu_dereference(n
->next
);
411 if (skip_lines
> 0) {
412 n
= rcu_dereference(n
->next
);
417 snprintf(tmp
, sizeof(tmp
), "%u/%s", n
->procnum
,
418 basename(n
->cmdline
));
419 tmp
[sizeof(tmp
) - 1] = 0;
421 mvwprintw(screen
, line
, 2, "[");
422 attron(COLOR_PAIR(3));
423 printw("%s", n
->procnum
> 0 ? tmp
: "bridged(?)");
424 attroff(COLOR_PAIR(3));
425 printw("]:%s:%s[", l3proto2str
[n
->l3_proto
],
426 proto2str
[n
->l4_proto
]);
427 attron(COLOR_PAIR(3));
428 printw("%s", state2str
[n
->tcp_state
]);
429 attroff(COLOR_PAIR(3));
432 if (n
->tcp_state
!= TCP_CONNTRACK_NONE
) {
433 printw("%s -> ", lookup_port_tcp(get_port(n
->port_src
,
436 printw("%s -> ", lookup_port_udp(get_port(n
->port_src
,
441 attron(COLOR_PAIR(1));
442 mvwprintw(screen
, ++line
, 8, "src: %s", n
->rev_dns_src
);
443 attroff(COLOR_PAIR(1));
444 printw(":%u (", ntohs(n
->port_src
));
445 attron(COLOR_PAIR(4));
446 printw("%s", (strlen(n
->country_src
) > 0 ?
447 n
->country_src
: "N/A"));
448 attroff(COLOR_PAIR(4));
449 printw(", %s) => ", (strlen(n
->city_src
) > 0 ?
450 n
->city_src
: "N/A"));
452 attron(COLOR_PAIR(2));
453 mvwprintw(screen
, ++line
, 8, "dst: %s", n
->rev_dns_dst
);
454 attroff(COLOR_PAIR(2));
455 printw(":%u (", ntohs(n
->port_dst
));
456 attron(COLOR_PAIR(4));
457 printw("%s", strlen(n
->country_dst
) > 0 ?
458 n
->country_dst
: "N/A");
459 attroff(COLOR_PAIR(4));
460 printw(", %s)", strlen(n
->city_dst
) > 0 ?
461 n
->city_dst
: "N/A");
465 n
= rcu_dereference(n
->next
);
475 static void screen_end(void)
480 static void presenter(void)
483 WINDOW
*screen
= NULL
;
485 dissector_init_ethernet(0);
486 screen_init(&screen
);
487 rcu_register_thread();
505 if (skip_lines
> SCROLL_MAX
)
506 skip_lines
= SCROLL_MAX
;
513 screen_update(screen
, &flow_list
, skip_lines
);
517 rcu_unregister_thread();
519 dissector_cleanup_ethernet();
522 static inline const char *make_n_a(const char *p
)
527 static void walk_process(char *process
, struct flow_entry
*n
)
534 if (snprintf(path
, sizeof(path
), "/proc/%s/fd", process
) == -1)
535 panic("giant process name! %s\n", process
);
541 while ((ent
= readdir(dir
))) {
544 if (snprintf(path
, sizeof(path
), "/proc/%s/fd/%s",
545 process
, ent
->d_name
) < 0)
547 if (stat(path
, &statbuf
) < 0)
549 if (S_ISSOCK(statbuf
.st_mode
) && n
->inode
== statbuf
.st_ino
) {
550 memset(n
->cmdline
, 0, sizeof(n
->cmdline
));
551 snprintf(path
, sizeof(path
), "/proc/%s/exe", process
);
552 rc
= readlink(path
, n
->cmdline
, sizeof(n
->cmdline
) - 1);
555 panic("readlink error: %s\n", strerror(errno
));
557 n
->procnum
= atoi(process
);
564 /* Derived from ifpromisc, Fred N. van Kempen, GPL v2.0 */
565 /* n->inode must be set */
566 static void walk_processes(struct flow_entry
*n
)
572 memset(n
->cmdline
, 0, sizeof(n
->cmdline
));
576 dir
= opendir("/proc");
578 panic("Cannot open /proc!\n");
580 while ((ent
= readdir(dir
)))
581 if (strspn(ent
->d_name
, "0123456789") == strlen(ent
->d_name
))
582 walk_process(ent
->d_name
, n
);
587 static int get_inode_from_local_port(int port
, const char *proto
, int ip6
)
594 memset(path
, 0, sizeof(path
));
595 snprintf(path
, sizeof(path
), "/proc/net/%s%s", proto
, ip6
? "6" : "");
596 proc
= fopen(path
, "r");
599 memset(buff
, 0, sizeof(buff
));
600 while (fgets(buff
, sizeof(buff
), proc
) != NULL
) {
601 int lport
= 0, inode
= 0;
602 buff
[sizeof(buff
) - 1] = 0;
603 if (sscanf(buff
, "%*u: %*X:%X %*X:%*X %*X %*X:%*X %*X:%*X "
604 "%*X %*u %*u %u", &lport
, &inode
) == 2) {
610 memset(buff
, 0, sizeof(buff
));
617 static void flow_entry_from_ct(struct flow_entry
*n
, struct nf_conntrack
*ct
)
619 n
->flow_id
= nfct_get_attr_u32(ct
, ATTR_ID
);
620 n
->use
= nfct_get_attr_u32(ct
, ATTR_USE
);
621 n
->status
= nfct_get_attr_u32(ct
, ATTR_STATUS
);
622 n
->l3_proto
= nfct_get_attr_u8(ct
, ATTR_ORIG_L3PROTO
);
623 n
->l4_proto
= nfct_get_attr_u8(ct
, ATTR_ORIG_L4PROTO
);
624 n
->ip4_src_addr
= nfct_get_attr_u32(ct
, ATTR_ORIG_IPV4_SRC
);
625 n
->ip4_dst_addr
= nfct_get_attr_u32(ct
, ATTR_ORIG_IPV4_DST
);
627 const uint8_t *ipv6_src
= nfct_get_attr(ct
, ATTR_ORIG_IPV6_SRC
);
629 memcpy(n
->ip6_src_addr
, ipv6_src
, sizeof(n
->ip6_src_addr
));
630 const uint8_t *ipv6_dst
= nfct_get_attr(ct
, ATTR_ORIG_IPV6_DST
);
632 memcpy(n
->ip6_dst_addr
, ipv6_dst
, sizeof(n
->ip6_dst_addr
));
634 n
->port_src
= nfct_get_attr_u16(ct
, ATTR_ORIG_PORT_SRC
);
635 n
->port_dst
= nfct_get_attr_u16(ct
, ATTR_ORIG_PORT_DST
);
636 n
->tcp_state
= nfct_get_attr_u8(ct
, ATTR_TCP_STATE
);
637 n
->tcp_flags
= nfct_get_attr_u8(ct
, ATTR_TCP_FLAGS_ORIG
);
638 n
->counter_pkts
= nfct_get_attr_u64(ct
, ATTR_ORIG_COUNTER_PACKETS
);
639 n
->counter_bytes
= nfct_get_attr_u64(ct
, ATTR_ORIG_COUNTER_BYTES
);
640 n
->timestamp_start
= nfct_get_attr_u64(ct
, ATTR_TIMESTAMP_START
);
641 n
->timestamp_stop
= nfct_get_attr_u64(ct
, ATTR_TIMESTAMP_STOP
);
644 n
->inode
= get_inode_from_local_port(ntohs(n
->port_src
),
645 proto2str
[n
->l4_proto
],
650 /* if this really runs on a router, we try it once and then let it be */
654 /* TODO: IP4 + IP6 */
655 static void flow_entry_get_extended(struct flow_entry
*n
)
657 struct sockaddr_in sa
;
658 struct hostent
*hent
;
659 GeoIPRecord
*gir_src
, *gir_dst
;
663 if (ntohs(n
->port_src
) == 53 || ntohs(n
->port_dst
) == 53)
666 memset(&sa
, 0, sizeof(sa
));
667 sa
.sin_family
= PF_INET
; //XXX: IPv4
668 sa
.sin_addr
.s_addr
= n
->ip4_src_addr
;
669 getnameinfo((struct sockaddr
*) &sa
, sizeof(sa
), n
->rev_dns_src
,
670 sizeof(n
->rev_dns_src
), NULL
, 0, NI_NUMERICHOST
);
672 hent
= gethostbyaddr(&sa
.sin_addr
, sizeof(sa
.sin_addr
), PF_INET
);
674 memset(n
->rev_dns_src
, 0, sizeof(n
->rev_dns_src
));
675 memcpy(n
->rev_dns_src
, hent
->h_name
,
676 min(sizeof(n
->rev_dns_src
), strlen(hent
->h_name
)));
679 gir_src
= GeoIP_record_by_ipnum(gi_city
, ntohl(n
->ip4_src_addr
));
681 const char *country
=
682 make_n_a(GeoIP_country_name_by_ipnum(gi_country
,
683 ntohl(n
->ip4_src_addr
)));
684 const char *city
= make_n_a(gir_src
->city
);
685 memcpy(n
->country_src
, country
,
686 min(sizeof(n
->country_src
), strlen(country
)));
687 memcpy(n
->city_src
, city
,
688 min(sizeof(n
->city_src
), strlen(city
)));
691 memset(&sa
, 0, sizeof(sa
));
692 sa
.sin_family
= PF_INET
; //XXX: IPv4
693 sa
.sin_addr
.s_addr
= n
->ip4_dst_addr
;
694 getnameinfo((struct sockaddr
*) &sa
, sizeof(sa
), n
->rev_dns_dst
,
695 sizeof(n
->rev_dns_dst
), NULL
, 0, NI_NUMERICHOST
);
697 hent
= gethostbyaddr(&sa
.sin_addr
, sizeof(sa
.sin_addr
), PF_INET
);
699 memset(n
->rev_dns_dst
, 0, sizeof(n
->rev_dns_dst
));
700 memcpy(n
->rev_dns_dst
, hent
->h_name
,
701 min(sizeof(n
->rev_dns_dst
), strlen(hent
->h_name
)));
704 gir_dst
= GeoIP_record_by_ipnum(gi_city
, ntohl(n
->ip4_dst_addr
));
706 const char *country
=
707 make_n_a(GeoIP_country_name_by_ipnum(gi_country
,
708 ntohl(n
->ip4_dst_addr
)));
709 const char *city
= make_n_a(gir_dst
->city
);
710 memcpy(n
->country_dst
, country
,
711 min(sizeof(n
->country_dst
), strlen(country
)));
712 memcpy(n
->city_dst
, city
,
713 min(sizeof(n
->city_dst
), strlen(city
)));
717 static void flow_list_init(struct flow_list
*fl
)
720 spinlock_init(&fl
->lock
);
723 static struct flow_entry
*__flow_list_find_by_id(struct flow_list
*fl
, uint32_t id
)
725 struct flow_entry
*n
= rcu_dereference(fl
->head
);
727 if (n
->flow_id
== id
)
729 n
= rcu_dereference(n
->next
);
734 static struct flow_entry
*__flow_list_find_prev_by_id(struct flow_list
*fl
, uint32_t id
)
736 struct flow_entry
*n
= rcu_dereference(fl
->head
);
737 if (n
->flow_id
== id
)
739 while (rcu_dereference(n
->next
) != NULL
) {
740 if (rcu_dereference(n
->next
)->flow_id
== id
)
742 n
= rcu_dereference(n
->next
);
747 static void flow_list_new_entry(struct flow_list
*fl
, struct nf_conntrack
*ct
)
749 struct flow_entry
*n
= xzmalloc(sizeof(*n
));
751 rcu_assign_pointer(n
->next
, fl
->head
);
752 rcu_assign_pointer(fl
->head
, n
);
753 flow_entry_from_ct(n
, ct
);
754 flow_entry_get_extended(n
);
757 static void flow_list_update_entry(struct flow_list
*fl
, struct nf_conntrack
*ct
)
760 uint32_t id
= nfct_get_attr_u32(ct
, ATTR_ID
);
761 struct flow_entry
*n
;
762 n
= __flow_list_find_by_id(fl
, id
);
764 n
= xzmalloc(sizeof(*n
));
766 rcu_assign_pointer(n
->next
, fl
->head
);
767 rcu_assign_pointer(fl
->head
, n
);
770 flow_entry_from_ct(n
, ct
);
772 flow_entry_get_extended(n
);
775 static void flow_list_destroy_entry(struct flow_list
*fl
, struct nf_conntrack
*ct
)
777 uint32_t id
= nfct_get_attr_u32(ct
, ATTR_ID
);
778 struct flow_entry
*n1
, *n2
;
780 n1
= __flow_list_find_by_id(fl
, id
);
782 n2
= __flow_list_find_prev_by_id(fl
, id
);
784 rcu_assign_pointer(n2
->next
, n1
->next
);
785 rcu_assign_pointer(n1
->next
, NULL
);
789 rcu_assign_pointer(fl
->head
, NULL
);
794 static void flow_list_destroy(struct flow_list
*fl
)
796 struct flow_entry
*n
;
798 while (fl
->head
!= NULL
) {
799 n
= rcu_dereference(fl
->head
->next
);
800 rcu_assign_pointer(fl
->head
->next
, NULL
);
802 rcu_assign_pointer(fl
->head
, n
);
806 spinlock_destroy(&fl
->lock
);
809 static int collector_cb(enum nf_conntrack_msg_type type
,
810 struct nf_conntrack
*ct
,
818 spinlock_lock(&flow_list
.lock
);
821 flow_list_new_entry(&flow_list
, ct
);
824 flow_list_update_entry(&flow_list
, ct
);
827 flow_list_destroy_entry(&flow_list
, ct
);
832 spinlock_unlock(&flow_list
.lock
);
834 return NFCT_CB_CONTINUE
;
837 static int dummy_cb(enum nf_conntrack_msg_type type
, struct nf_conntrack
*ct
,
843 static void *collector(void *null
)
846 u_int32_t family
= AF_INET
;
847 struct nfct_handle
*handle
;
848 struct nfct_filter
*filter
;
850 handle
= nfct_open(CONNTRACK
, NFCT_ALL_CT_GROUPS
);
852 panic("Cannot create a nfct handle!\n");
855 nfct_callback_register(handle
, NFCT_T_ALL
, dummy_cb
, NULL
);
856 nfct_query(handle
, NFCT_Q_DUMP
, &family
);
859 handle
= nfct_open(CONNTRACK
, NFCT_ALL_CT_GROUPS
);
861 panic("Cannot create a nfct handle!\n");
863 nfct_query(handle
, NFCT_Q_FLUSH
, &family
);
865 filter
= nfct_filter_create();
867 panic("Cannot create a nfct filter!\n");
868 if (what
& INCLUDE_UDP
)
869 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_UDP
);
870 if (what
& INCLUDE_TCP
)
871 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_TCP
);
873 struct nfct_filter_ipv4 filter_ipv4
= {
874 .addr
= ntohl(INADDR_LOOPBACK
),
878 nfct_filter_set_logic(filter
, NFCT_FILTER_SRC_IPV4
,
879 NFCT_FILTER_LOGIC_NEGATIVE
);
880 nfct_filter_add_attr(filter
, NFCT_FILTER_SRC_IPV4
, &filter_ipv4
);
882 struct nfct_filter_ipv6 filter_ipv6
= {
883 .addr
= { 0x0, 0x0, 0x0, 0x1 },
884 .mask
= { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff },
887 nfct_filter_set_logic(filter
, NFCT_FILTER_SRC_IPV6
,
888 NFCT_FILTER_LOGIC_NEGATIVE
);
889 nfct_filter_add_attr(filter
, NFCT_FILTER_SRC_IPV6
, &filter_ipv6
);
891 ret
= nfct_filter_attach(nfct_fd(handle
), filter
);
893 panic("Cannot attach filter to handle!\n");
895 nfct_filter_destroy(filter
);
898 gi_country
= GeoIP_open(path_country_db
, GEOIP_MMAP_CACHE
);
900 gi_country
= GeoIP_open_type(GEOIP_COUNTRY_EDITION
,
904 gi_city
= GeoIP_open(path_city_db
, GEOIP_MMAP_CACHE
);
906 gi_city
= GeoIP_open_type(GEOIP_CITY_EDITION_REV1
,
908 if (!gi_country
|| !gi_city
)
909 panic("Cannot open GeoIP database!\n");
911 GeoIP_set_charset(gi_country
, GEOIP_CHARSET_UTF8
);
912 GeoIP_set_charset(gi_city
, GEOIP_CHARSET_UTF8
);
914 flow_list_init(&flow_list
);
916 rcu_register_thread();
918 nfct_callback_register(handle
, NFCT_T_ALL
, collector_cb
, NULL
);
923 rcu_unregister_thread();
925 flow_list_destroy(&flow_list
);
927 GeoIP_delete(gi_city
);
928 GeoIP_delete(gi_country
);
935 xfree(path_country_db
);
940 int main(int argc
, char **argv
)
943 int ret
, c
, opt_index
, what_cmd
= 0;
945 check_for_root_maybe_die();
947 while ((c
= getopt_long(argc
, argv
, short_options
, long_options
,
948 &opt_index
)) != EOF
) {
951 what_cmd
|= INCLUDE_TCP
;
954 what_cmd
|= INCLUDE_UDP
;
960 path_city_db
= xstrdup(optarg
);
963 path_country_db
= xstrdup(optarg
);
975 panic("Option -%c requires an argument!\n",
979 whine("Unknown option character "
980 "`0x%X\'!\n", optopt
);
993 register_signal(SIGINT
, signal_handler
);
994 register_signal(SIGHUP
, signal_handler
);
996 ret
= pthread_create(&tid
, NULL
, collector
, NULL
);
998 panic("Cannot create phthread!\n");