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 Path to GeoIP city database
83 Path to GeoIP country database
91 Print help text and lists all options.
97 Written by Daniel Borkmann <daniel@netsniff-ng.org>
101 Documentation by Emmanuel Roullit <emmanuel@netsniff-ng.org>
105 Please report bugs to <bugs@netsniff-ng.org>
121 #include <libnetfilter_conntrack/libnetfilter_conntrack.h>
122 #include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
124 #include <GeoIPCity.h>
125 #include <netinet/in.h>
128 #include <sys/stat.h>
136 #include "built_in.h"
138 #include "dissector_eth.h"
140 #define INCLUDE_UDP (1 << 0)
141 #define INCLUDE_TCP (1 << 1)
143 #ifndef ATTR_TIMESTAMP_START
144 # define ATTR_TIMESTAMP_START 63
146 #ifndef ATTR_TIMESTAMP_STOP
147 # define ATTR_TIMESTAMP_STOP 64
150 #define SCROLL_MAX 1000
155 struct flow_entry
*next
;
160 uint32_t ip4_src_addr
;
161 uint32_t ip4_dst_addr
;
162 uint32_t ip6_src_addr
[4];
163 uint32_t ip6_dst_addr
[4];
168 uint64_t counter_pkts
;
169 uint64_t counter_bytes
;
170 uint64_t timestamp_start
;
171 uint64_t timestamp_stop
;
172 char country_src
[128];
174 char rev_dns_src
[256];
175 char country_dst
[128];
177 char rev_dns_dst
[256];
184 struct flow_entry
*head
;
185 struct spinlock lock
;
188 volatile sig_atomic_t sigint
= 0;
190 static int what
= INCLUDE_TCP
;
192 static struct flow_list flow_list
;
194 static GeoIP
*gi_country
= NULL
;
195 static GeoIP
*gi_city
= NULL
;
197 static char *path_city_db
= NULL
, *path_country_db
= NULL
;
199 static const char *short_options
= "vhTULK";
201 static struct option long_options
[] = {
202 {"tcp", no_argument
, 0, 'T'},
203 {"udp", no_argument
, 0, 'U'},
204 {"city-db", required_argument
, 0, 'L'},
205 {"country-db", required_argument
, 0, 'K'},
206 {"version", no_argument
, 0, 'v'},
207 {"help", no_argument
, 0, 'h'},
211 const char *const l3proto2str
[AF_MAX
] = {
216 const char *const proto2str
[IPPROTO_MAX
] = {
217 [IPPROTO_TCP
] = "tcp",
218 [IPPROTO_UDP
] = "udp",
219 [IPPROTO_UDPLITE
] = "udplite",
220 [IPPROTO_ICMP
] = "icmp",
221 [IPPROTO_ICMPV6
] = "icmpv6",
222 [IPPROTO_SCTP
] = "sctp",
223 [IPPROTO_GRE
] = "gre",
224 [IPPROTO_DCCP
] = "dccp",
225 [IPPROTO_IGMP
] = "igmp",
226 [IPPROTO_IPIP
] = "ipip",
227 [IPPROTO_EGP
] = "egp",
228 [IPPROTO_PUP
] = "pup",
229 [IPPROTO_IDP
] = "idp",
230 [IPPROTO_RSVP
] = "rsvp",
231 [IPPROTO_IPV6
] = "ip6tun",
232 [IPPROTO_ESP
] = "esp",
234 [IPPROTO_PIM
] = "pim",
235 [IPPROTO_COMP
] = "comp",
238 const char *const state2str
[TCP_CONNTRACK_MAX
] = {
239 [TCP_CONNTRACK_NONE
] = "NOSTATE",
240 [TCP_CONNTRACK_SYN_SENT
] = "SYN_SENT",
241 [TCP_CONNTRACK_SYN_RECV
] = "SYN_RECV",
242 [TCP_CONNTRACK_ESTABLISHED
] = "ESTABLISHED",
243 [TCP_CONNTRACK_FIN_WAIT
] = "FIN_WAIT",
244 [TCP_CONNTRACK_CLOSE_WAIT
] = "CLOSE_WAIT",
245 [TCP_CONNTRACK_LAST_ACK
] = "LAST_ACK",
246 [TCP_CONNTRACK_TIME_WAIT
] = "TIME_WAIT",
247 [TCP_CONNTRACK_CLOSE
] = "CLOSE",
248 [TCP_CONNTRACK_SYN_SENT2
] = "SYN_SENT2",
251 const uint8_t states
[] = {
252 TCP_CONNTRACK_SYN_SENT
,
253 TCP_CONNTRACK_SYN_RECV
,
254 TCP_CONNTRACK_ESTABLISHED
,
255 TCP_CONNTRACK_FIN_WAIT
,
256 TCP_CONNTRACK_CLOSE_WAIT
,
257 TCP_CONNTRACK_LAST_ACK
,
258 TCP_CONNTRACK_TIME_WAIT
,
260 TCP_CONNTRACK_SYN_SENT2
,
264 static void signal_handler(int number
)
276 static void help(void)
278 printf("\nflowtop %s, top-like netfilter TCP/UDP flow tracking\n",
280 printf("http://www.netsniff-ng.org\n\n");
281 printf("Usage: flowtop [options]\n");
282 printf("Options:\n");
283 printf(" -T|--tcp Show only TCP flows (default)\n");
284 printf(" -U|--udp Show only UDP flows\n");
285 printf(" --city-db <path> Specifiy path for geoip city database\n");
286 printf(" --country-db <path> Specifiy path for geoip country database\n");
287 printf(" -v|--version Print version\n");
288 printf(" -h|--help Print this help\n");
290 printf("Examples:\n");
291 printf(" flowtop\n\n");
293 printf(" If netfilter is not running, you can activate it with i.e.:\n");
294 printf(" iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT\n");
295 printf(" iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT\n");
297 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
298 printf("Copyright (C) 2011-2012 Daniel Borkmann <daniel@netsniff-ng.org>\n");
299 printf("Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel@netsniff-ng.org>\n");
300 printf("License: GNU GPL version 2\n");
301 printf("This is free software: you are free to change and redistribute it.\n");
302 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
306 static void version(void)
308 printf("\nflowtop %s, top-like netfilter TCP/UDP flow tracking\n",
310 printf("http://www.netsniff-ng.org\n\n");
311 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
312 printf("Copyright (C) 2011-2012 Daniel Borkmann <daniel@netsniff-ng.org>\n");
313 printf("Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel@netsniff-ng.org>\n");
314 printf("License: GNU GPL version 2\n");
315 printf("This is free software: you are free to change and redistribute it.\n");
316 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
320 static void screen_init(WINDOW
**screen
)
322 (*screen
) = initscr();
325 keypad(stdscr
, TRUE
);
326 nodelay(*screen
, TRUE
);
331 static inline uint16_t get_port(uint16_t src
, uint16_t dst
)
338 /* XXX: Is there a better way to determine? */
339 if (src
< dst
&& src
< 1024) {
341 } else if (dst
< src
&& dst
< 1024) {
344 tmp1
= lookup_port_tcp(src
);
345 tmp2
= lookup_port_tcp(dst
);
348 } else if (!tmp1
&& tmp2
) {
359 static void screen_update(WINDOW
*screen
, struct flow_list
*fl
, int skip_lines
)
363 struct flow_entry
*n
;
366 getmaxyx(screen
, maxy
, maxx
);
369 init_pair(1, COLOR_RED
, COLOR_BLACK
);
370 init_pair(2, COLOR_BLUE
, COLOR_BLACK
);
371 init_pair(3, COLOR_YELLOW
, COLOR_BLACK
);
372 init_pair(4, COLOR_GREEN
, COLOR_BLACK
);
378 mvwprintw(screen
, 1, 2, "Kernel netfilter TCP/UDP flow statistics, [+%d]",
381 if (rcu_dereference(fl
->head
) == NULL
)
382 mvwprintw(screen
, line
, 2, "(No active sessions! Is netfilter running?)");
385 /* Yes, that's lame :-P */
386 for (i
= 0; i
< sizeof(states
); i
++) {
387 n
= rcu_dereference(fl
->head
);
389 while (n
&& maxy
> 0) {
392 if (n
->tcp_state
!= states
[i
] ||
393 (i
!= TCP_CONNTRACK_NONE
&&
394 n
->tcp_state
== TCP_CONNTRACK_NONE
) ||
396 get_port(n
->port_src
, n
->port_dst
) == 53) {
397 n
= rcu_dereference(n
->next
);
401 if (skip_lines
> 0) {
402 n
= rcu_dereference(n
->next
);
407 snprintf(tmp
, sizeof(tmp
), "%u/%s", n
->procnum
,
408 basename(n
->cmdline
));
409 tmp
[sizeof(tmp
) - 1] = 0;
411 mvwprintw(screen
, line
, 2, "[");
412 attron(COLOR_PAIR(3));
413 printw("%s", n
->procnum
> 0 ? tmp
: "bridged(?)");
414 attroff(COLOR_PAIR(3));
415 printw("]:%s:%s[", l3proto2str
[n
->l3_proto
],
416 proto2str
[n
->l4_proto
]);
417 attron(COLOR_PAIR(3));
418 printw("%s", state2str
[n
->tcp_state
]);
419 attroff(COLOR_PAIR(3));
422 if (n
->tcp_state
!= TCP_CONNTRACK_NONE
) {
423 printw("%s -> ", lookup_port_tcp(get_port(n
->port_src
,
426 printw("%s -> ", lookup_port_udp(get_port(n
->port_src
,
430 attron(COLOR_PAIR(1));
431 printw("%s", n
->rev_dns_src
);
432 attroff(COLOR_PAIR(1));
433 printw(":%u (", ntohs(n
->port_src
));
434 attron(COLOR_PAIR(4));
435 printw("%s", (strlen(n
->country_src
) > 0 ?
436 n
->country_src
: "N/A"));
437 attroff(COLOR_PAIR(4));
438 printw(", %s) => ", (strlen(n
->city_src
) > 0 ?
439 n
->city_src
: "N/A"));
440 attron(COLOR_PAIR(2));
441 printw("%s", n
->rev_dns_dst
);
442 attroff(COLOR_PAIR(2));
443 printw(":%u (", ntohs(n
->port_dst
));
444 attron(COLOR_PAIR(4));
445 printw("%s", strlen(n
->country_dst
) > 0 ?
446 n
->country_dst
: "N/A");
447 attroff(COLOR_PAIR(4));
448 printw(", %s)", strlen(n
->city_dst
) > 0 ?
449 n
->city_dst
: "N/A");
453 n
= rcu_dereference(n
->next
);
463 static void screen_end(void)
468 static void presenter(void)
471 WINDOW
*screen
= NULL
;
473 dissector_init_ethernet(0);
474 screen_init(&screen
);
475 rcu_register_thread();
493 if (skip_lines
> SCROLL_MAX
)
494 skip_lines
= SCROLL_MAX
;
501 screen_update(screen
, &flow_list
, skip_lines
);
505 rcu_unregister_thread();
507 dissector_cleanup_ethernet();
510 static inline const char *make_n_a(const char *p
)
515 static void walk_process(char *process
, struct flow_entry
*n
)
522 if (snprintf(path
, sizeof(path
), "/proc/%s/fd", process
) == -1)
523 panic("giant process name! %s\n", process
);
529 while ((ent
= readdir(dir
))) {
532 if (snprintf(path
, sizeof(path
), "/proc/%s/fd/%s",
533 process
, ent
->d_name
) < 0)
535 if (stat(path
, &statbuf
) < 0)
537 if (S_ISSOCK(statbuf
.st_mode
) && n
->inode
== statbuf
.st_ino
) {
538 memset(n
->cmdline
, 0, sizeof(n
->cmdline
));
539 snprintf(path
, sizeof(path
), "/proc/%s/exe", process
);
540 rc
= readlink(path
, n
->cmdline
, sizeof(n
->cmdline
) - 1);
543 panic("readlink error: %s\n", strerror(errno
));
545 n
->procnum
= atoi(process
);
552 /* Derived from ifpromisc, Fred N. van Kempen, GPL v2.0 */
553 /* n->inode must be set */
554 static void walk_processes(struct flow_entry
*n
)
560 memset(n
->cmdline
, 0, sizeof(n
->cmdline
));
564 dir
= opendir("/proc");
566 panic("Cannot open /proc!\n");
568 while ((ent
= readdir(dir
)))
569 if (strspn(ent
->d_name
, "0123456789") == strlen(ent
->d_name
))
570 walk_process(ent
->d_name
, n
);
575 static int get_inode_from_local_port(int port
, const char *proto
, int ip6
)
582 memset(path
, 0, sizeof(path
));
583 snprintf(path
, sizeof(path
), "/proc/net/%s%s", proto
, ip6
? "6" : "");
584 proc
= fopen(path
, "r");
587 memset(buff
, 0, sizeof(buff
));
588 while (fgets(buff
, sizeof(buff
), proc
) != NULL
) {
589 int lport
= 0, inode
= 0;
590 buff
[sizeof(buff
) - 1] = 0;
591 if (sscanf(buff
, "%*u: %*X:%X %*X:%*X %*X %*X:%*X %*X:%*X "
592 "%*X %*u %*u %u", &lport
, &inode
) == 2) {
598 memset(buff
, 0, sizeof(buff
));
605 static void flow_entry_from_ct(struct flow_entry
*n
, struct nf_conntrack
*ct
)
607 n
->flow_id
= nfct_get_attr_u32(ct
, ATTR_ID
);
608 n
->use
= nfct_get_attr_u32(ct
, ATTR_USE
);
609 n
->status
= nfct_get_attr_u32(ct
, ATTR_STATUS
);
610 n
->l3_proto
= nfct_get_attr_u8(ct
, ATTR_ORIG_L3PROTO
);
611 n
->l4_proto
= nfct_get_attr_u8(ct
, ATTR_ORIG_L4PROTO
);
612 n
->ip4_src_addr
= nfct_get_attr_u32(ct
, ATTR_ORIG_IPV4_SRC
);
613 n
->ip4_dst_addr
= nfct_get_attr_u32(ct
, ATTR_ORIG_IPV4_DST
);
615 const uint8_t *ipv6_src
= nfct_get_attr(ct
, ATTR_ORIG_IPV6_SRC
);
617 memcpy(n
->ip6_src_addr
, ipv6_src
, sizeof(n
->ip6_src_addr
));
618 const uint8_t *ipv6_dst
= nfct_get_attr(ct
, ATTR_ORIG_IPV6_DST
);
620 memcpy(n
->ip6_dst_addr
, ipv6_dst
, sizeof(n
->ip6_dst_addr
));
622 n
->port_src
= nfct_get_attr_u16(ct
, ATTR_ORIG_PORT_SRC
);
623 n
->port_dst
= nfct_get_attr_u16(ct
, ATTR_ORIG_PORT_DST
);
624 n
->tcp_state
= nfct_get_attr_u8(ct
, ATTR_TCP_STATE
);
625 n
->tcp_flags
= nfct_get_attr_u8(ct
, ATTR_TCP_FLAGS_ORIG
);
626 n
->counter_pkts
= nfct_get_attr_u64(ct
, ATTR_ORIG_COUNTER_PACKETS
);
627 n
->counter_bytes
= nfct_get_attr_u64(ct
, ATTR_ORIG_COUNTER_BYTES
);
628 n
->timestamp_start
= nfct_get_attr_u64(ct
, ATTR_TIMESTAMP_START
);
629 n
->timestamp_stop
= nfct_get_attr_u64(ct
, ATTR_TIMESTAMP_STOP
);
632 n
->inode
= get_inode_from_local_port(ntohs(n
->port_src
),
633 proto2str
[n
->l4_proto
],
638 /* if this really runs on a router, we try it once and then let it be */
642 /* TODO: IP4 + IP6 */
643 static void flow_entry_get_extended(struct flow_entry
*n
)
645 struct sockaddr_in sa
;
646 struct hostent
*hent
;
647 GeoIPRecord
*gir_src
, *gir_dst
;
651 if (ntohs(n
->port_src
) == 53 || ntohs(n
->port_dst
) == 53)
654 memset(&sa
, 0, sizeof(sa
));
655 sa
.sin_family
= PF_INET
; //XXX: IPv4
656 sa
.sin_addr
.s_addr
= n
->ip4_src_addr
;
657 getnameinfo((struct sockaddr
*) &sa
, sizeof(sa
), n
->rev_dns_src
,
658 sizeof(n
->rev_dns_src
), NULL
, 0, NI_NUMERICHOST
);
660 hent
= gethostbyaddr(&sa
.sin_addr
, sizeof(sa
.sin_addr
), PF_INET
);
662 memset(n
->rev_dns_src
, 0, sizeof(n
->rev_dns_src
));
663 memcpy(n
->rev_dns_src
, hent
->h_name
,
664 min(sizeof(n
->rev_dns_src
), strlen(hent
->h_name
)));
667 gir_src
= GeoIP_record_by_ipnum(gi_city
, ntohl(n
->ip4_src_addr
));
669 const char *country
=
670 make_n_a(GeoIP_country_name_by_ipnum(gi_country
,
671 ntohl(n
->ip4_src_addr
)));
672 const char *city
= make_n_a(gir_src
->city
);
673 memcpy(n
->country_src
, country
,
674 min(sizeof(n
->country_src
), strlen(country
)));
675 memcpy(n
->city_src
, city
,
676 min(sizeof(n
->city_src
), strlen(city
)));
679 memset(&sa
, 0, sizeof(sa
));
680 sa
.sin_family
= PF_INET
; //XXX: IPv4
681 sa
.sin_addr
.s_addr
= n
->ip4_dst_addr
;
682 getnameinfo((struct sockaddr
*) &sa
, sizeof(sa
), n
->rev_dns_dst
,
683 sizeof(n
->rev_dns_dst
), NULL
, 0, NI_NUMERICHOST
);
685 hent
= gethostbyaddr(&sa
.sin_addr
, sizeof(sa
.sin_addr
), PF_INET
);
687 memset(n
->rev_dns_dst
, 0, sizeof(n
->rev_dns_dst
));
688 memcpy(n
->rev_dns_dst
, hent
->h_name
,
689 min(sizeof(n
->rev_dns_dst
), strlen(hent
->h_name
)));
692 gir_dst
= GeoIP_record_by_ipnum(gi_city
, ntohl(n
->ip4_dst_addr
));
694 const char *country
=
695 make_n_a(GeoIP_country_name_by_ipnum(gi_country
,
696 ntohl(n
->ip4_dst_addr
)));
697 const char *city
= make_n_a(gir_dst
->city
);
698 memcpy(n
->country_dst
, country
,
699 min(sizeof(n
->country_dst
), strlen(country
)));
700 memcpy(n
->city_dst
, city
,
701 min(sizeof(n
->city_dst
), strlen(city
)));
705 static void flow_list_init(struct flow_list
*fl
)
708 spinlock_init(&fl
->lock
);
711 static struct flow_entry
*__flow_list_find_by_id(struct flow_list
*fl
, uint32_t id
)
713 struct flow_entry
*n
= rcu_dereference(fl
->head
);
715 if (n
->flow_id
== id
)
717 n
= rcu_dereference(n
->next
);
722 static struct flow_entry
*__flow_list_find_prev_by_id(struct flow_list
*fl
, uint32_t id
)
724 struct flow_entry
*n
= rcu_dereference(fl
->head
);
725 if (n
->flow_id
== id
)
727 while (rcu_dereference(n
->next
) != NULL
) {
728 if (rcu_dereference(n
->next
)->flow_id
== id
)
730 n
= rcu_dereference(n
->next
);
735 static void flow_list_new_entry(struct flow_list
*fl
, struct nf_conntrack
*ct
)
737 struct flow_entry
*n
= xzmalloc(sizeof(*n
));
739 rcu_assign_pointer(n
->next
, fl
->head
);
740 rcu_assign_pointer(fl
->head
, n
);
741 flow_entry_from_ct(n
, ct
);
742 flow_entry_get_extended(n
);
745 static void flow_list_update_entry(struct flow_list
*fl
, struct nf_conntrack
*ct
)
748 uint32_t id
= nfct_get_attr_u32(ct
, ATTR_ID
);
749 struct flow_entry
*n
;
750 n
= __flow_list_find_by_id(fl
, id
);
752 n
= xzmalloc(sizeof(*n
));
754 rcu_assign_pointer(n
->next
, fl
->head
);
755 rcu_assign_pointer(fl
->head
, n
);
758 flow_entry_from_ct(n
, ct
);
760 flow_entry_get_extended(n
);
763 static void flow_list_destroy_entry(struct flow_list
*fl
, struct nf_conntrack
*ct
)
765 uint32_t id
= nfct_get_attr_u32(ct
, ATTR_ID
);
766 struct flow_entry
*n1
, *n2
;
768 n1
= __flow_list_find_by_id(fl
, id
);
770 n2
= __flow_list_find_prev_by_id(fl
, id
);
772 rcu_assign_pointer(n2
->next
, n1
->next
);
773 rcu_assign_pointer(n1
->next
, NULL
);
777 rcu_assign_pointer(fl
->head
, NULL
);
782 static void flow_list_destroy(struct flow_list
*fl
)
784 struct flow_entry
*n
;
786 while (fl
->head
!= NULL
) {
787 n
= rcu_dereference(fl
->head
->next
);
788 rcu_assign_pointer(fl
->head
->next
, NULL
);
790 rcu_assign_pointer(fl
->head
, n
);
794 spinlock_destroy(&fl
->lock
);
797 static int collector_cb(enum nf_conntrack_msg_type type
,
798 struct nf_conntrack
*ct
,
806 spinlock_lock(&flow_list
.lock
);
809 flow_list_new_entry(&flow_list
, ct
);
812 flow_list_update_entry(&flow_list
, ct
);
815 flow_list_destroy_entry(&flow_list
, ct
);
820 spinlock_unlock(&flow_list
.lock
);
822 return NFCT_CB_CONTINUE
;
825 static int dummy_cb(enum nf_conntrack_msg_type type
, struct nf_conntrack
*ct
,
831 static void *collector(void *null
)
834 u_int32_t family
= AF_INET
;
835 struct nfct_handle
*handle
;
836 struct nfct_filter
*filter
;
838 handle
= nfct_open(CONNTRACK
, NFCT_ALL_CT_GROUPS
);
840 panic("Cannot create a nfct handle!\n");
843 nfct_callback_register(handle
, NFCT_T_ALL
, dummy_cb
, NULL
);
844 nfct_query(handle
, NFCT_Q_DUMP
, &family
);
847 handle
= nfct_open(CONNTRACK
, NFCT_ALL_CT_GROUPS
);
849 panic("Cannot create a nfct handle!\n");
851 nfct_query(handle
, NFCT_Q_FLUSH
, &family
);
853 filter
= nfct_filter_create();
855 panic("Cannot create a nfct filter!\n");
856 if (what
& INCLUDE_UDP
)
857 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_UDP
);
858 if (what
& INCLUDE_TCP
)
859 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_TCP
);
861 struct nfct_filter_ipv4 filter_ipv4
= {
862 .addr
= ntohl(INADDR_LOOPBACK
),
866 nfct_filter_set_logic(filter
, NFCT_FILTER_SRC_IPV4
,
867 NFCT_FILTER_LOGIC_NEGATIVE
);
868 nfct_filter_add_attr(filter
, NFCT_FILTER_SRC_IPV4
, &filter_ipv4
);
870 struct nfct_filter_ipv6 filter_ipv6
= {
871 .addr
= { 0x0, 0x0, 0x0, 0x1 },
872 .mask
= { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff },
875 nfct_filter_set_logic(filter
, NFCT_FILTER_SRC_IPV6
,
876 NFCT_FILTER_LOGIC_NEGATIVE
);
877 nfct_filter_add_attr(filter
, NFCT_FILTER_SRC_IPV6
, &filter_ipv6
);
879 ret
= nfct_filter_attach(nfct_fd(handle
), filter
);
881 panic("Cannot attach filter to handle!\n");
883 nfct_filter_destroy(filter
);
886 gi_country
= GeoIP_open(path_country_db
, GEOIP_MMAP_CACHE
);
888 gi_country
= GeoIP_open_type(GEOIP_COUNTRY_EDITION
,
892 gi_city
= GeoIP_open(path_city_db
, GEOIP_MMAP_CACHE
);
894 gi_city
= GeoIP_open_type(GEOIP_CITY_EDITION_REV1
,
896 if (!gi_country
|| !gi_city
)
897 panic("Cannot open GeoIP database!\n");
899 GeoIP_set_charset(gi_country
, GEOIP_CHARSET_UTF8
);
900 GeoIP_set_charset(gi_city
, GEOIP_CHARSET_UTF8
);
902 flow_list_init(&flow_list
);
904 rcu_register_thread();
906 nfct_callback_register(handle
, NFCT_T_ALL
, collector_cb
, NULL
);
911 rcu_unregister_thread();
913 flow_list_destroy(&flow_list
);
915 GeoIP_delete(gi_city
);
916 GeoIP_delete(gi_country
);
923 xfree(path_country_db
);
928 int main(int argc
, char **argv
)
931 int ret
, c
, opt_index
, what_cmd
= 0;
933 check_for_root_maybe_die();
935 while ((c
= getopt_long(argc
, argv
, short_options
, long_options
,
936 &opt_index
)) != EOF
) {
939 what_cmd
|= INCLUDE_TCP
;
942 what_cmd
|= INCLUDE_UDP
;
945 path_city_db
= xstrdup(optarg
);
948 path_country_db
= xstrdup(optarg
);
960 panic("Option -%c requires an argument!\n",
964 whine("Unknown option character "
965 "`0x%X\'!\n", optopt
);
978 register_signal(SIGINT
, signal_handler
);
979 register_signal(SIGHUP
, signal_handler
);
981 ret
= pthread_create(&tid
, NULL
, collector
, NULL
);
983 panic("Cannot create phthread!\n");