pcap: also support byte swapped pcap types
[netsniff-ng.git] / flowtop.c
blob14846a78071fb7c94d02ca5791583a083b3901c8
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2011 - 2012 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'.
18 #define _LGPL_SOURCE
19 #include <stdio.h>
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <signal.h>
23 #include <getopt.h>
24 #include <pthread.h>
25 #include <signal.h>
26 #include <netdb.h>
27 #include <ctype.h>
28 #include <libnetfilter_conntrack/libnetfilter_conntrack.h>
29 #include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
30 #include <libnetfilter_conntrack/libnetfilter_conntrack_dccp.h>
31 #include <libnetfilter_conntrack/libnetfilter_conntrack_sctp.h>
32 #include <GeoIP.h>
33 #include <GeoIPCity.h>
34 #include <netinet/in.h>
35 #include <curses.h>
36 #include <dirent.h>
37 #include <sys/stat.h>
38 #include <sys/fsuid.h>
39 #include <urcu.h>
40 #include <libgen.h>
42 #include "die.h"
43 #include "xmalloc.h"
44 #include "xio.h"
45 #include "xutils.h"
46 #include "built_in.h"
47 #include "locking.h"
48 #include "dissector_eth.h"
49 #include "pkt_buff.h"
51 struct geo_ip_db {
52 GeoIP *gi4, *gi6;
53 char *path4, *path6;
56 struct flow_entry {
57 uint32_t flow_id, use, status;
58 uint8_t l3_proto, l4_proto;
59 uint32_t ip4_src_addr, ip4_dst_addr;
60 uint32_t ip6_src_addr[4], ip6_dst_addr[4];
61 uint16_t port_src, port_dst;
62 uint8_t tcp_state, tcp_flags, sctp_state, dccp_state;
63 uint64_t counter_pkts, counter_bytes;
64 uint64_t timestamp_start, timestamp_stop;
65 char country_src[128], country_dst[128];
66 char city_src[128], city_dst[128];
67 char rev_dns_src[256], rev_dns_dst[256];
68 char cmdline[256];
69 struct flow_entry *next;
70 int procnum, inode;
73 struct flow_list {
74 struct flow_entry *head;
75 struct spinlock lock;
78 #ifndef ATTR_TIMESTAMP_START
79 # define ATTR_TIMESTAMP_START 63
80 #endif
81 #ifndef ATTR_TIMESTAMP_STOP
82 # define ATTR_TIMESTAMP_STOP 64
83 #endif
85 #define SCROLL_MAX 1000
87 #define INCLUDE_IPV4 (1 << 0)
88 #define INCLUDE_IPV6 (1 << 1)
89 #define INCLUDE_UDP (1 << 2)
90 #define INCLUDE_TCP (1 << 3)
91 #define INCLUDE_DCCP (1 << 4)
92 #define INCLUDE_ICMP (1 << 5)
93 #define INCLUDE_SCTP (1 << 6)
95 volatile sig_atomic_t sigint = 0;
97 static int what = INCLUDE_IPV4 | INCLUDE_IPV6 | INCLUDE_TCP, show_src = 0;
99 struct geo_ip_db geo_country, geo_city;
101 static struct flow_list flow_list;
103 static const char *short_options = "vhTULKsOPDIS46";
104 static const struct option long_options[] = {
105 {"ipv4", no_argument, NULL, '4'},
106 {"ipv6", no_argument, NULL, '6'},
107 {"tcp", no_argument, NULL, 'T'},
108 {"udp", no_argument, NULL, 'U'},
109 {"dccp", no_argument, NULL, 'D'},
110 {"icmp", no_argument, NULL, 'I'},
111 {"sctp", no_argument, NULL, 'S'},
112 {"show-src", no_argument, NULL, 's'},
113 {"city-db4", required_argument, NULL, 'L'},
114 {"country-db4", required_argument, NULL, 'K'},
115 {"city-db6", required_argument, NULL, 'O'},
116 {"country-db6", required_argument, NULL, 'P'},
117 {"version", no_argument, NULL, 'v'},
118 {"help", no_argument, NULL, 'h'},
119 {NULL, 0, NULL, 0}
122 static const char *const l3proto2str[AF_MAX] = {
123 [AF_INET] = "ipv4",
124 [AF_INET6] = "ipv6",
127 static const char *const l4proto2str[IPPROTO_MAX] = {
128 [IPPROTO_TCP] = "tcp",
129 [IPPROTO_UDP] = "udp",
130 [IPPROTO_UDPLITE] = "udplite",
131 [IPPROTO_ICMP] = "icmp",
132 [IPPROTO_ICMPV6] = "icmpv6",
133 [IPPROTO_SCTP] = "sctp",
134 [IPPROTO_GRE] = "gre",
135 [IPPROTO_DCCP] = "dccp",
136 [IPPROTO_IGMP] = "igmp",
137 [IPPROTO_IPIP] = "ipip",
138 [IPPROTO_EGP] = "egp",
139 [IPPROTO_PUP] = "pup",
140 [IPPROTO_IDP] = "idp",
141 [IPPROTO_RSVP] = "rsvp",
142 [IPPROTO_IPV6] = "ip6tun",
143 [IPPROTO_ESP] = "esp",
144 [IPPROTO_AH] = "ah",
145 [IPPROTO_PIM] = "pim",
146 [IPPROTO_COMP] = "comp",
149 static const char *const tcp_state2str[TCP_CONNTRACK_MAX] = {
150 [TCP_CONNTRACK_NONE] = "NOSTATE",
151 [TCP_CONNTRACK_SYN_SENT] = "SYN_SENT",
152 [TCP_CONNTRACK_SYN_RECV] = "SYN_RECV",
153 [TCP_CONNTRACK_ESTABLISHED] = "ESTABLISHED",
154 [TCP_CONNTRACK_FIN_WAIT] = "FIN_WAIT",
155 [TCP_CONNTRACK_CLOSE_WAIT] = "CLOSE_WAIT",
156 [TCP_CONNTRACK_LAST_ACK] = "LAST_ACK",
157 [TCP_CONNTRACK_TIME_WAIT] = "TIME_WAIT",
158 [TCP_CONNTRACK_CLOSE] = "CLOSE",
159 [TCP_CONNTRACK_SYN_SENT2] = "SYN_SENT2",
162 static const uint8_t tcp_states[] = {
163 TCP_CONNTRACK_SYN_SENT,
164 TCP_CONNTRACK_SYN_RECV,
165 TCP_CONNTRACK_ESTABLISHED,
166 TCP_CONNTRACK_FIN_WAIT,
167 TCP_CONNTRACK_CLOSE_WAIT,
168 TCP_CONNTRACK_LAST_ACK,
169 TCP_CONNTRACK_TIME_WAIT,
170 TCP_CONNTRACK_CLOSE,
171 TCP_CONNTRACK_SYN_SENT2,
172 TCP_CONNTRACK_NONE,
175 static const char *const dccp_state2str[DCCP_CONNTRACK_MAX] = {
176 [DCCP_CONNTRACK_NONE] = "NOSTATE",
177 [DCCP_CONNTRACK_REQUEST] = "REQUEST",
178 [DCCP_CONNTRACK_RESPOND] = "RESPOND",
179 [DCCP_CONNTRACK_PARTOPEN] = "PARTOPEN",
180 [DCCP_CONNTRACK_OPEN] = "OPEN",
181 [DCCP_CONNTRACK_CLOSEREQ] = "CLOSEREQ",
182 [DCCP_CONNTRACK_CLOSING] = "CLOSING",
183 [DCCP_CONNTRACK_TIMEWAIT] = "TIMEWAIT",
184 [DCCP_CONNTRACK_IGNORE] = "IGNORE",
185 [DCCP_CONNTRACK_INVALID] = "INVALID",
188 static const uint8_t dccp_states[] = {
189 DCCP_CONNTRACK_NONE,
190 DCCP_CONNTRACK_REQUEST,
191 DCCP_CONNTRACK_RESPOND,
192 DCCP_CONNTRACK_PARTOPEN,
193 DCCP_CONNTRACK_OPEN,
194 DCCP_CONNTRACK_CLOSEREQ,
195 DCCP_CONNTRACK_CLOSING,
196 DCCP_CONNTRACK_TIMEWAIT,
197 DCCP_CONNTRACK_IGNORE,
198 DCCP_CONNTRACK_INVALID,
201 static const char *const sctp_state2str[SCTP_CONNTRACK_MAX] = {
202 [SCTP_CONNTRACK_NONE] = "NOSTATE",
203 [SCTP_CONNTRACK_CLOSED] = "CLOSED",
204 [SCTP_CONNTRACK_COOKIE_WAIT] = "COOKIE_WAIT",
205 [SCTP_CONNTRACK_COOKIE_ECHOED] = "COOKIE_ECHOED",
206 [SCTP_CONNTRACK_ESTABLISHED] = "ESTABLISHED",
207 [SCTP_CONNTRACK_SHUTDOWN_SENT] = "SHUTDOWN_SENT",
208 [SCTP_CONNTRACK_SHUTDOWN_RECD] = "SHUTDOWN_RECD",
209 [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT] = "SHUTDOWN_ACK_SENT",
212 static const uint8_t sctp_states[] = {
213 SCTP_CONNTRACK_NONE,
214 SCTP_CONNTRACK_CLOSED,
215 SCTP_CONNTRACK_COOKIE_WAIT,
216 SCTP_CONNTRACK_COOKIE_ECHOED,
217 SCTP_CONNTRACK_ESTABLISHED,
218 SCTP_CONNTRACK_SHUTDOWN_SENT,
219 SCTP_CONNTRACK_SHUTDOWN_RECD,
220 SCTP_CONNTRACK_SHUTDOWN_ACK_SENT,
223 static const struct nfct_filter_ipv4 filter_ipv4 = {
224 .addr = __constant_htonl(INADDR_LOOPBACK),
225 .mask = 0xffffffff,
228 static const struct nfct_filter_ipv6 filter_ipv6 = {
229 .addr = { 0x0, 0x0, 0x0, 0x1 },
230 .mask = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff },
233 static void signal_handler(int number)
235 switch (number) {
236 case SIGINT:
237 sigint = 1;
238 break;
239 case SIGHUP:
240 default:
241 break;
245 static void flow_entry_from_ct(struct flow_entry *n, struct nf_conntrack *ct);
246 static void flow_entry_get_extended(struct flow_entry *n);
248 static void help(void)
250 printf("\nflowtop %s, top-like netfilter TCP/UDP flow tracking\n",
251 VERSION_STRING);
252 puts("http://www.netsniff-ng.org\n\n"
253 "Usage: flowtop [options]\n"
254 "Options:\n"
255 " -4|--ipv4 Show only IPv4 flows (default)\n"
256 " -6|--ipv6 Show only IPv6 flows (default)\n"
257 " -T|--tcp Show only TCP flows (default)\n"
258 " -U|--udp Show only UDP flows\n"
259 " -D|--dccp Show only DCCP flows\n"
260 " -I|--icmp Show only ICMP/ICMPv6 flows\n"
261 " -S|--sctp Show only SCTP flows\n"
262 " -s|--show-src Also show source, not only dest\n"
263 " --city-db4 <path> Specifiy path for geoip4 city database\n"
264 " --country-db4 <path> Specifiy path for geoip4 country database\n"
265 " --city-db6 <path> Specifiy path for geoip6 city database\n"
266 " --country-db6 <path> Specifiy path for geoip6 country database\n"
267 " -v|--version Print version\n"
268 " -h|--help Print this help\n\n"
269 "Examples:\n"
270 " flowtop\n"
271 " flowtop -46UTDISs\n\n"
272 "Note:\n"
273 " If netfilter is not running, you can activate it with e.g.:\n"
274 " iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT\n"
275 " iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT\n\n"
276 "Please report bugs to <bugs@netsniff-ng.org>\n"
277 "Copyright (C) 2011-2012 Daniel Borkmann <daniel@netsniff-ng.org>\n"
278 "Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel@netsniff-ng.org>\n"
279 "License: GNU GPL version 2.0\n"
280 "This is free software: you are free to change and redistribute it.\n"
281 "There is NO WARRANTY, to the extent permitted by law.\n");
282 die();
285 static void version(void)
287 printf("\nflowtop %s, top-like netfilter TCP/UDP flow tracking\n",
288 VERSION_STRING);
289 puts("http://www.netsniff-ng.org\n\n"
290 "Please report bugs to <bugs@netsniff-ng.org>\n"
291 "Copyright (C) 2011-2012 Daniel Borkmann <daniel@netsniff-ng.org>\n"
292 "Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel@netsniff-ng.org>\n"
293 "License: GNU GPL version 2.0\n"
294 "This is free software: you are free to change and redistribute it.\n"
295 "There is NO WARRANTY, to the extent permitted by law.\n");
296 die();
299 static inline struct flow_entry *flow_entry_xalloc(void)
301 return xzmalloc(sizeof(struct flow_entry));
304 static inline void flow_entry_xfree(struct flow_entry *n)
306 xfree(n);
309 static inline void flow_list_init(struct flow_list *fl)
311 fl->head = NULL;
312 spinlock_init(&fl->lock);
315 static void flow_list_new_entry(struct flow_list *fl, struct nf_conntrack *ct)
317 struct flow_entry *n = flow_entry_xalloc();
319 flow_entry_from_ct(n, ct);
320 flow_entry_get_extended(n);
322 rcu_assign_pointer(n->next, fl->head);
323 rcu_assign_pointer(fl->head, n);
326 static struct flow_entry *flow_list_find_id(struct flow_list *fl,
327 uint32_t id)
329 struct flow_entry *n = rcu_dereference(fl->head);
331 while (n != NULL) {
332 if (n->flow_id == id)
333 return n;
335 n = rcu_dereference(n->next);
338 return NULL;
341 static struct flow_entry *flow_list_find_prev_id(struct flow_list *fl,
342 uint32_t id)
344 struct flow_entry *n = rcu_dereference(fl->head), *tmp;
346 if (n->flow_id == id)
347 return NULL;
349 while ((tmp = rcu_dereference(n->next)) != NULL) {
350 if (tmp->flow_id == id)
351 return n;
353 n = tmp;
356 return NULL;
359 static void flow_list_update_entry(struct flow_list *fl,
360 struct nf_conntrack *ct)
362 int do_ext = 0;
363 struct flow_entry *n;
365 n = flow_list_find_id(fl, nfct_get_attr_u32(ct, ATTR_ID));
366 if (n == NULL) {
367 n = flow_entry_xalloc();
368 do_ext = 1;
371 flow_entry_from_ct(n, ct);
372 if (do_ext) {
373 flow_entry_get_extended(n);
375 rcu_assign_pointer(n->next, fl->head);
376 rcu_assign_pointer(fl->head, n);
380 static void flow_list_destroy_entry(struct flow_list *fl,
381 struct nf_conntrack *ct)
383 struct flow_entry *n1, *n2;
384 uint32_t id = nfct_get_attr_u32(ct, ATTR_ID);
386 n1 = flow_list_find_id(fl, id);
387 if (n1) {
388 n2 = flow_list_find_prev_id(fl, id);
389 if (n2) {
390 rcu_assign_pointer(n2->next, n1->next);
391 rcu_assign_pointer(n1->next, NULL);
393 flow_entry_xfree(n1);
394 } else {
395 flow_entry_xfree(fl->head);
397 rcu_assign_pointer(fl->head, NULL);
402 static void flow_list_destroy(struct flow_list *fl)
404 struct flow_entry *n;
406 while (fl->head != NULL) {
407 n = rcu_dereference(fl->head->next);
408 rcu_assign_pointer(fl->head->next, NULL);
410 flow_entry_xfree(fl->head);
411 rcu_assign_pointer(fl->head, n);
414 synchronize_rcu();
415 spinlock_destroy(&fl->lock);
418 static int walk_process(char *process, struct flow_entry *n)
420 int ret;
421 DIR *dir;
422 struct dirent *ent;
423 char path[1024];
425 if (snprintf(path, sizeof(path), "/proc/%s/fd", process) == -1)
426 panic("giant process name! %s\n", process);
428 dir = opendir(path);
429 if (!dir)
430 return 0;
432 while ((ent = readdir(dir))) {
433 struct stat statbuf;
435 if (snprintf(path, sizeof(path), "/proc/%s/fd/%s",
436 process, ent->d_name) < 0)
437 continue;
439 if (stat(path, &statbuf) < 0)
440 continue;
442 if (S_ISSOCK(statbuf.st_mode) && n->inode == statbuf.st_ino) {
443 memset(n->cmdline, 0, sizeof(n->cmdline));
445 snprintf(path, sizeof(path), "/proc/%s/exe", process);
447 ret = readlink(path, n->cmdline,
448 sizeof(n->cmdline) - 1);
449 if (ret < 0)
450 panic("readlink error: %s\n", strerror(errno));
452 n->procnum = atoi(process);
453 return 1;
457 closedir(dir);
458 return 0;
461 static void walk_processes(struct flow_entry *n)
463 int ret;
464 DIR *dir;
465 struct dirent *ent;
467 /* n->inode must be set */
468 if (n->inode <= 0) {
469 memset(n->cmdline, 0, sizeof(n->cmdline));
470 return;
473 dir = opendir("/proc");
474 if (!dir)
475 panic("Cannot open /proc!\n");
477 while ((ent = readdir(dir))) {
478 if (strspn(ent->d_name, "0123456789") == strlen(ent->d_name)) {
479 ret = walk_process(ent->d_name, n);
480 if (ret > 0)
481 break;
485 closedir(dir);
488 static int get_port_inode(uint16_t port, int proto, int is_ip6)
490 int ret = -ENOENT;
491 char path[128], buff[1024];
492 FILE *proc;
494 memset(path, 0, sizeof(path));
495 snprintf(path, sizeof(path), "/proc/net/%s%s",
496 l4proto2str[proto], is_ip6 ? "6" : "");
498 proc = fopen(path, "r");
499 if (!proc)
500 return -EIO;
502 memset(buff, 0, sizeof(buff));
504 while (fgets(buff, sizeof(buff), proc) != NULL) {
505 int inode = 0;
506 unsigned int lport = 0;
508 buff[sizeof(buff) - 1] = 0;
509 if (sscanf(buff, "%*u: %*X:%X %*X:%*X %*X %*X:%*X %*X:%*X "
510 "%*X %*u %*u %u", &lport, &inode) == 2) {
511 if ((uint16_t) lport == port) {
512 ret = inode;
513 break;
517 memset(buff, 0, sizeof(buff));
520 fclose(proc);
521 return ret;
524 #define CP_NFCT(elem, attr, x) \
525 do { n->elem = nfct_get_attr_u##x(ct,(attr)); } while (0)
526 #define CP_NFCT_BUFF(elem, attr) do { \
527 const uint8_t *buff = nfct_get_attr(ct,(attr)); \
528 if (buff != NULL) \
529 memcpy(n->elem, buff, sizeof(n->elem)); \
530 } while (0)
532 static void flow_entry_from_ct(struct flow_entry *n, struct nf_conntrack *ct)
534 CP_NFCT(l3_proto, ATTR_ORIG_L3PROTO, 8);
535 CP_NFCT(l4_proto, ATTR_ORIG_L4PROTO, 8);
537 CP_NFCT(ip4_src_addr, ATTR_ORIG_IPV4_SRC, 32);
538 CP_NFCT(ip4_dst_addr, ATTR_ORIG_IPV4_DST, 32);
540 CP_NFCT(port_src, ATTR_ORIG_PORT_SRC, 16);
541 CP_NFCT(port_dst, ATTR_ORIG_PORT_DST, 16);
543 CP_NFCT(status, ATTR_STATUS, 32);
545 CP_NFCT(tcp_state, ATTR_TCP_STATE, 8);
546 CP_NFCT(tcp_flags, ATTR_TCP_FLAGS_ORIG, 8);
547 CP_NFCT(sctp_state, ATTR_SCTP_STATE, 8);
548 CP_NFCT(dccp_state, ATTR_DCCP_STATE, 8);
550 CP_NFCT(counter_pkts, ATTR_ORIG_COUNTER_PACKETS, 64);
551 CP_NFCT(counter_bytes, ATTR_ORIG_COUNTER_BYTES, 64);
553 CP_NFCT(timestamp_start, ATTR_TIMESTAMP_START, 64);
554 CP_NFCT(timestamp_stop, ATTR_TIMESTAMP_STOP, 64);
556 CP_NFCT(flow_id, ATTR_ID, 32);
557 CP_NFCT(use, ATTR_USE, 32);
559 CP_NFCT_BUFF(ip6_src_addr, ATTR_ORIG_IPV6_SRC);
560 CP_NFCT_BUFF(ip6_dst_addr, ATTR_ORIG_IPV6_DST);
562 n->port_src = ntohs(n->port_src);
563 n->port_dst = ntohs(n->port_dst);
565 n->ip4_src_addr = ntohl(n->ip4_src_addr);
566 n->ip4_dst_addr = ntohl(n->ip4_dst_addr);
569 enum flow_entry_direction {
570 flow_entry_src,
571 flow_entry_dst,
574 static inline int flow_entry_get_extended_is_dns(struct flow_entry *n)
576 /* We don't want to analyze / display DNS itself, since we
577 * use it to resolve reverse dns.
579 return n->port_src == 53 || n->port_dst == 53;
582 #define SELFLD(dir,src_member,dst_member) \
583 (((dir) == flow_entry_src) ? n->src_member : n->dst_member)
585 static struct sockaddr_in *
586 flow_entry_get_sain4_obj(struct flow_entry *n, enum flow_entry_direction dir,
587 struct sockaddr_in *sa)
589 memset(sa, 0, sizeof(*sa));
590 sa->sin_family = PF_INET;
591 sa->sin_addr.s_addr = htonl(SELFLD(dir, ip4_src_addr, ip4_dst_addr));
593 return sa;
596 static struct sockaddr_in6 *
597 flow_entry_get_sain6_obj(struct flow_entry *n, enum flow_entry_direction dir,
598 struct sockaddr_in6 *sa)
600 memset(sa, 0, sizeof(*sa));
601 sa->sin6_family = PF_INET6;
603 memcpy(&sa->sin6_addr, SELFLD(dir, ip6_src_addr, ip6_dst_addr),
604 sizeof(SELFLD(dir, ip6_src_addr, ip6_dst_addr)));
606 return sa;
609 static void
610 flow_entry_geo_city_lookup_generic(struct flow_entry *n,
611 enum flow_entry_direction dir)
613 GeoIPRecord *gir = NULL;
614 struct sockaddr_in sa4;
615 struct sockaddr_in6 sa6;
616 const char *city = NULL;
618 switch (n->l3_proto) {
619 default:
620 bug();
622 case AF_INET:
623 flow_entry_get_sain4_obj(n, dir, &sa4);
624 gir = GeoIP_record_by_ipnum(geo_city.gi4,
625 ntohl(sa4.sin_addr.s_addr));
626 break;
628 case AF_INET6:
629 flow_entry_get_sain6_obj(n, dir, &sa6);
630 gir = GeoIP_record_by_ipnum_v6(geo_city.gi6, sa6.sin6_addr);
631 break;
634 if (gir != NULL)
635 city = gir->city;
637 bug_on(sizeof(n->city_src) != sizeof(n->city_dst));
639 if (city) {
640 memcpy(SELFLD(dir, city_src, city_dst), city,
641 min(sizeof(n->city_src), strlen(city)));
642 } else {
643 memset(SELFLD(dir, city_src, city_dst), 0,
644 sizeof(n->city_src));
648 static void
649 flow_entry_geo_country_lookup_generic(struct flow_entry *n,
650 enum flow_entry_direction dir)
652 struct sockaddr_in sa4;
653 struct sockaddr_in6 sa6;
654 inline const char *make_na(const char *p) { return p ? : "N/A"; }
655 const char *country = NULL;
657 switch (n->l3_proto) {
658 default:
659 bug();
661 case AF_INET:
662 flow_entry_get_sain4_obj(n, dir, &sa4);
663 country = GeoIP_country_name_by_ipnum(geo_country.gi4,
664 ntohl(sa4.sin_addr.s_addr));
665 break;
667 case AF_INET6:
668 flow_entry_get_sain6_obj(n, dir, &sa6);
669 country = GeoIP_country_name_by_ipnum_v6(geo_country.gi6,
670 sa6.sin6_addr);
671 break;
674 country = make_na(country);
676 bug_on(sizeof(n->country_src) != sizeof(n->country_dst));
677 memcpy(SELFLD(dir, country_src, country_dst), country,
678 min(sizeof(n->country_src), strlen(country)));
681 static void flow_entry_get_extended_geo(struct flow_entry *n,
682 enum flow_entry_direction dir)
684 flow_entry_geo_city_lookup_generic(n, dir);
685 flow_entry_geo_country_lookup_generic(n, dir);
688 static void flow_entry_get_extended_revdns(struct flow_entry *n,
689 enum flow_entry_direction dir)
691 size_t sa_len;
692 struct sockaddr_in sa4;
693 struct sockaddr_in6 sa6;
694 struct sockaddr *sa;
695 struct hostent *hent;
697 switch (n->l3_proto) {
698 default:
699 bug();
701 case AF_INET:
702 flow_entry_get_sain4_obj(n, dir, &sa4);
703 sa = (struct sockaddr *) &sa4;
704 sa_len = sizeof(sa4);
705 hent = gethostbyaddr(&sa4.sin_addr, sizeof(sa4.sin_addr),
706 AF_INET);
707 break;
709 case AF_INET6:
710 flow_entry_get_sain6_obj(n, dir, &sa6);
711 sa = (struct sockaddr *) &sa6;
712 sa_len = sizeof(sa6);
713 hent = gethostbyaddr(&sa6.sin6_addr, sizeof(sa6.sin6_addr),
714 AF_INET6);
715 break;
718 bug_on(sizeof(n->rev_dns_src) != sizeof(n->rev_dns_dst));
719 getnameinfo(sa, sa_len, SELFLD(dir, rev_dns_src, rev_dns_dst),
720 sizeof(n->rev_dns_src), NULL, 0, NI_NUMERICHOST);
722 if (hent) {
723 memset(n->rev_dns_dst, 0, sizeof(n->rev_dns_dst));
724 memcpy(SELFLD(dir, rev_dns_src, rev_dns_dst),
725 hent->h_name, min(sizeof(n->rev_dns_src),
726 strlen(hent->h_name)));
730 static void flow_entry_get_extended(struct flow_entry *n)
732 if (n->flow_id == 0 || flow_entry_get_extended_is_dns(n))
733 return;
735 flow_entry_get_extended_revdns(n, flow_entry_src);
736 flow_entry_get_extended_geo(n, flow_entry_src);
738 flow_entry_get_extended_revdns(n, flow_entry_dst);
739 flow_entry_get_extended_geo(n, flow_entry_dst);
741 /* Lookup application */
742 n->inode = get_port_inode(n->port_src, n->l4_proto,
743 n->l3_proto == AF_INET6);
744 if (n->inode > 0)
745 walk_processes(n);
748 static uint16_t presenter_get_port(uint16_t src, uint16_t dst, int tcp)
750 if (src < dst && src < 1024) {
751 return src;
752 } else if (dst < src && dst < 1024) {
753 return dst;
754 } else {
755 const char *tmp1, *tmp2;
756 if (tcp) {
757 tmp1 = lookup_port_tcp(src);
758 tmp2 = lookup_port_tcp(dst);
759 } else {
760 tmp1 = lookup_port_udp(src);
761 tmp2 = lookup_port_udp(dst);
763 if (tmp1 && !tmp2) {
764 return src;
765 } else if (!tmp1 && tmp2) {
766 return dst;
767 } else {
768 if (src < dst)
769 return src;
770 else
771 return dst;
776 static void presenter_screen_init(WINDOW **screen)
778 (*screen) = initscr();
779 noecho();
780 cbreak();
781 keypad(stdscr, TRUE);
782 nodelay(*screen, TRUE);
783 refresh();
784 wrefresh(*screen);
787 static void presenter_screen_do_line(WINDOW *screen, struct flow_entry *n,
788 unsigned int *line)
790 char tmp[128], *pname = NULL;
791 uint16_t port;
793 mvwprintw(screen, *line, 2, "");
795 /* PID, application name */
796 if (n->procnum > 0) {
797 slprintf(tmp, sizeof(tmp), "%s(%u)", basename(n->cmdline),
798 n->procnum);
800 printw("[");
801 attron(COLOR_PAIR(3));
802 printw("%s", tmp);
803 attroff(COLOR_PAIR(3));
804 printw("]:");
807 /* L3 protocol, L4 protocol, states */
808 printw("%s:%s", l3proto2str[n->l3_proto], l4proto2str[n->l4_proto]);
809 printw("[");
810 attron(COLOR_PAIR(3));
811 switch (n->l4_proto) {
812 case IPPROTO_TCP:
813 printw("%s", tcp_state2str[n->tcp_state]);
814 break;
815 case IPPROTO_SCTP:
816 printw("%s", sctp_state2str[n->sctp_state]);
817 break;
818 case IPPROTO_DCCP:
819 printw("%s", dccp_state2str[n->dccp_state]);
820 break;
821 case IPPROTO_UDP:
822 case IPPROTO_UDPLITE:
823 case IPPROTO_ICMP:
824 case IPPROTO_ICMPV6:
825 printw("NOSTATE");
826 break;
828 attroff(COLOR_PAIR(3));
829 printw("]");
831 /* Guess application port */
832 switch (n->l4_proto) {
833 case IPPROTO_TCP:
834 port = presenter_get_port(n->port_src, n->port_dst, 1);
835 pname = lookup_port_tcp(port);
836 break;
837 case IPPROTO_UDP:
838 case IPPROTO_UDPLITE:
839 port = presenter_get_port(n->port_src, n->port_dst, 0);
840 pname = lookup_port_udp(port);
841 break;
843 if (pname) {
844 attron(A_BOLD);
845 printw(":%s", pname);
846 attroff(A_BOLD);
848 printw(" ->");
850 /* Number packets, bytes */
851 if (n->counter_pkts > 0 && n->counter_bytes > 0)
852 printw(" (%llu pkts, %llu bytes) ->",
853 n->counter_pkts, n->counter_bytes);
855 /* Show source information: reverse DNS, port, country, city */
856 if (show_src) {
857 attron(COLOR_PAIR(1));
858 mvwprintw(screen, ++(*line), 8, "src: %s", n->rev_dns_src);
859 attroff(COLOR_PAIR(1));
861 printw(":%u (", n->port_src);
863 attron(COLOR_PAIR(4));
864 printw("%s", n->country_src);
865 attroff(COLOR_PAIR(4));
867 if (n->city_src[0])
868 printw(", %s", n->city_src);
869 printw(") => ");
872 /* Show dest information: reverse DNS, port, country, city */
873 attron(COLOR_PAIR(2));
874 mvwprintw(screen, ++(*line), 8, "dst: %s", n->rev_dns_dst);
875 attroff(COLOR_PAIR(2));
877 printw(":%u (", n->port_dst);
879 attron(COLOR_PAIR(4));
880 printw("%s", n->country_dst);
881 attroff(COLOR_PAIR(4));
883 if (n->city_dst[0])
884 printw(", %s", n->city_dst);
885 printw(")");
888 static inline int presenter_flow_wrong_state(struct flow_entry *n, int state)
890 int ret = 1;
892 switch (n->l4_proto) {
893 case IPPROTO_TCP:
894 if (n->tcp_state == state)
895 ret = 0;
896 break;
897 case IPPROTO_SCTP:
898 if (n->sctp_state == state)
899 ret = 0;
900 break;
901 case IPPROTO_DCCP:
902 if (n->dccp_state == state)
903 ret = 0;
904 break;
905 case IPPROTO_UDP:
906 case IPPROTO_UDPLITE:
907 case IPPROTO_ICMP:
908 case IPPROTO_ICMPV6:
909 ret = 0;
910 break;
913 return ret;
916 static void presenter_screen_update(WINDOW *screen, struct flow_list *fl,
917 int skip_lines)
919 int i, j, maxy;
920 unsigned int line = 3;
921 struct flow_entry *n;
922 uint8_t protocols[] = {
923 IPPROTO_TCP,
924 IPPROTO_DCCP,
925 IPPROTO_SCTP,
926 IPPROTO_UDP,
927 IPPROTO_UDPLITE,
928 IPPROTO_ICMP,
929 IPPROTO_ICMPV6,
931 size_t protocol_state_size[] = {
932 [IPPROTO_TCP] = array_size(tcp_states),
933 [IPPROTO_DCCP] = array_size(dccp_states),
934 [IPPROTO_SCTP] = array_size(sctp_states),
935 [IPPROTO_UDP] = 1,
936 [IPPROTO_UDPLITE] = 1,
937 [IPPROTO_ICMP] = 1,
938 [IPPROTO_ICMPV6] = 1,
941 curs_set(0);
943 maxy = getmaxy(screen);
944 maxy -= 6;
946 start_color();
947 init_pair(1, COLOR_RED, COLOR_BLACK);
948 init_pair(2, COLOR_BLUE, COLOR_BLACK);
949 init_pair(3, COLOR_YELLOW, COLOR_BLACK);
950 init_pair(4, COLOR_GREEN, COLOR_BLACK);
952 wclear(screen);
953 clear();
955 mvwprintw(screen, 1, 2, "Kernel netfilter TCP/UDP "
956 "flow statistics, [+%d]", skip_lines);
958 rcu_read_lock();
960 if (rcu_dereference(fl->head) == NULL)
961 mvwprintw(screen, line, 2, "(No active sessions! "
962 "Is netfilter running?)");
964 for (i = 0; i < array_size(protocols); i++) {
965 for (j = 0; j < protocol_state_size[protocols[i]]; j++) {
966 n = rcu_dereference(fl->head);
967 while (n && maxy > 0) {
968 int skip_entry = 0;
970 if (n->l4_proto != protocols[i])
971 skip_entry = 1;
972 if (presenter_flow_wrong_state(n, j))
973 skip_entry = 1;
974 if (presenter_get_port(n->port_src,
975 n->port_dst, 0) == 53)
976 skip_entry = 1;
977 if (skip_entry) {
978 n = rcu_dereference(n->next);
979 continue;
981 if (skip_lines > 0) {
982 n = rcu_dereference(n->next);
983 skip_lines--;
984 continue;
987 presenter_screen_do_line(screen, n, &line);
989 line++;
990 maxy -= (2 + 1 * show_src);
991 n = rcu_dereference(n->next);
996 rcu_read_unlock();
998 wrefresh(screen);
999 refresh();
1002 static inline void presenter_screen_end(void)
1004 endwin();
1007 static void presenter(void)
1009 int skip_lines = 0;
1010 WINDOW *screen = NULL;
1012 dissector_init_ethernet(0);
1013 presenter_screen_init(&screen);
1015 rcu_register_thread();
1016 while (!sigint) {
1017 switch (getch()) {
1018 case 'q':
1019 sigint = 1;
1020 break;
1021 case KEY_UP:
1022 case 'u':
1023 case 'k':
1024 skip_lines--;
1025 if (skip_lines < 0)
1026 skip_lines = 0;
1027 break;
1028 case KEY_DOWN:
1029 case 'd':
1030 case 'j':
1031 skip_lines++;
1032 if (skip_lines > SCROLL_MAX)
1033 skip_lines = SCROLL_MAX;
1034 break;
1035 default:
1036 fflush(stdin);
1037 break;
1040 presenter_screen_update(screen, &flow_list, skip_lines);
1041 usleep(100000);
1043 rcu_unregister_thread();
1045 presenter_screen_end();
1046 dissector_cleanup_ethernet();
1049 static int collector_cb(enum nf_conntrack_msg_type type,
1050 struct nf_conntrack *ct, void *data)
1052 if (sigint)
1053 return NFCT_CB_STOP;
1055 synchronize_rcu();
1056 spinlock_lock(&flow_list.lock);
1058 switch (type) {
1059 case NFCT_T_NEW:
1060 flow_list_new_entry(&flow_list, ct);
1061 break;
1062 case NFCT_T_UPDATE:
1063 flow_list_update_entry(&flow_list, ct);
1064 break;
1065 case NFCT_T_DESTROY:
1066 flow_list_destroy_entry(&flow_list, ct);
1067 break;
1068 default:
1069 break;
1072 spinlock_unlock(&flow_list.lock);
1074 return NFCT_CB_CONTINUE;
1077 static inline GeoIP *collector_geoip_open(const char *path, int type)
1079 if (path != NULL)
1080 return GeoIP_open(path, GEOIP_MMAP_CACHE);
1081 else
1082 return GeoIP_open_type(type, GEOIP_MMAP_CACHE);
1085 static void collector_load_geoip(void)
1087 geo_country.gi4 = collector_geoip_open(geo_country.path4,
1088 GEOIP_COUNTRY_EDITION);
1089 if (geo_country.gi4 == NULL)
1090 panic("Cannot open GeoIP4 country database!\n");
1092 geo_country.gi6 = collector_geoip_open(geo_country.path6,
1093 GEOIP_COUNTRY_EDITION_V6);
1094 if (geo_country.gi6 == NULL)
1095 panic("Cannot open GeoIP6 country database!\n");
1097 geo_city.gi4 = collector_geoip_open(geo_city.path4,
1098 GEOIP_CITY_EDITION_REV1);
1099 if (geo_city.gi4 == NULL)
1100 panic("Cannot open GeoIP4 city database!\n");
1102 geo_city.gi6 = collector_geoip_open(geo_city.path6,
1103 GEOIP_CITY_EDITION_REV1_V6);
1104 if (geo_city.gi6 == NULL)
1105 panic("Cannot open GeoIP6 city database!\n");
1107 GeoIP_set_charset(geo_country.gi4, GEOIP_CHARSET_UTF8);
1108 GeoIP_set_charset(geo_country.gi6, GEOIP_CHARSET_UTF8);
1110 GeoIP_set_charset(geo_city.gi4, GEOIP_CHARSET_UTF8);
1111 GeoIP_set_charset(geo_city.gi6, GEOIP_CHARSET_UTF8);
1114 static void collector_destroy_geoip(void)
1116 GeoIP_delete(geo_country.gi4);
1117 GeoIP_delete(geo_country.gi6);
1119 GeoIP_delete(geo_city.gi4);
1120 GeoIP_delete(geo_city.gi6);
1123 static inline void collector_flush(struct nfct_handle *handle, uint8_t family)
1125 nfct_query(handle, NFCT_Q_FLUSH, &family);
1128 static void *collector(void *null)
1130 int ret;
1131 struct nfct_handle *handle;
1132 struct nfct_filter *filter;
1134 handle = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_NEW |
1135 NF_NETLINK_CONNTRACK_UPDATE |
1136 NF_NETLINK_CONNTRACK_DESTROY);
1137 if (!handle)
1138 panic("Cannot create a nfct handle!\n");
1140 collector_flush(handle, AF_INET);
1141 collector_flush(handle, AF_INET6);
1143 filter = nfct_filter_create();
1144 if (!filter)
1145 panic("Cannot create a nfct filter!\n");
1147 ret = nfct_filter_attach(nfct_fd(handle), filter);
1148 if (ret < 0)
1149 panic("Cannot attach filter to handle!\n");
1151 if (what & INCLUDE_UDP) {
1152 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_UDP);
1153 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_UDPLITE);
1155 if (what & INCLUDE_TCP)
1156 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_TCP);
1157 if (what & INCLUDE_DCCP)
1158 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_DCCP);
1159 if (what & INCLUDE_SCTP)
1160 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_SCTP);
1161 if (what & INCLUDE_ICMP && what & INCLUDE_IPV4)
1162 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_ICMP);
1163 if (what & INCLUDE_ICMP && what & INCLUDE_IPV6)
1164 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_ICMPV6);
1165 if (what & INCLUDE_IPV4) {
1166 nfct_filter_set_logic(filter, NFCT_FILTER_SRC_IPV4,
1167 NFCT_FILTER_LOGIC_NEGATIVE);
1168 nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
1170 if (what & INCLUDE_IPV6) {
1171 nfct_filter_set_logic(filter, NFCT_FILTER_SRC_IPV6,
1172 NFCT_FILTER_LOGIC_NEGATIVE);
1173 nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV6, &filter_ipv6);
1176 ret = nfct_filter_attach(nfct_fd(handle), filter);
1177 if (ret < 0)
1178 panic("Cannot attach filter to handle!\n");
1180 nfct_callback_register(handle, NFCT_T_ALL, collector_cb, NULL);
1182 nfct_filter_destroy(filter);
1184 collector_load_geoip();
1186 flow_list_init(&flow_list);
1188 rcu_register_thread();
1190 while (!sigint && ret >= 0)
1191 ret = nfct_catch(handle);
1193 rcu_unregister_thread();
1195 flow_list_destroy(&flow_list);
1197 collector_destroy_geoip();
1199 nfct_close(handle);
1201 pthread_exit(0);
1204 int main(int argc, char **argv)
1206 pthread_t tid;
1207 int ret, c, opt_index, what_cmd = 0;
1209 setfsuid(getuid());
1210 setfsgid(getgid());
1212 memset(&geo_country, 0, sizeof(geo_country));
1213 memset(&geo_city, 0, sizeof(geo_city));
1215 while ((c = getopt_long(argc, argv, short_options, long_options,
1216 &opt_index)) != EOF) {
1217 switch (c) {
1218 case '4':
1219 what_cmd |= INCLUDE_IPV4;
1220 break;
1221 case '6':
1222 what_cmd |= INCLUDE_IPV6;
1223 break;
1224 case 'T':
1225 what_cmd |= INCLUDE_TCP;
1226 break;
1227 case 'U':
1228 what_cmd |= INCLUDE_UDP;
1229 break;
1230 case 'D':
1231 what_cmd |= INCLUDE_DCCP;
1232 break;
1233 case 'I':
1234 what_cmd |= INCLUDE_ICMP;
1235 break;
1236 case 'S':
1237 what_cmd |= INCLUDE_SCTP;
1238 break;
1239 case 's':
1240 show_src = 1;
1241 break;
1242 case 'L':
1243 geo_city.path4 = xstrdup(optarg);
1244 break;
1245 case 'K':
1246 geo_country.path4 = xstrdup(optarg);
1247 break;
1248 case 'O':
1249 geo_city.path6 = xstrdup(optarg);
1250 break;
1251 case 'P':
1252 geo_country.path6 = xstrdup(optarg);
1253 break;
1254 case 'h':
1255 help();
1256 break;
1257 case 'v':
1258 version();
1259 break;
1260 case '?':
1261 switch (optopt) {
1262 case 'L':
1263 case 'K':
1264 case 'O':
1265 case 'P':
1266 panic("Option -%c requires an argument!\n",
1267 optopt);
1268 default:
1269 if (isprint(optopt))
1270 whine("Unknown option character "
1271 "`0x%X\'!\n", optopt);
1272 die();
1274 default:
1275 break;
1279 if (what_cmd > 0)
1280 what = what_cmd;
1282 rcu_init();
1284 register_signal(SIGINT, signal_handler);
1285 register_signal(SIGHUP, signal_handler);
1287 ret = pthread_create(&tid, NULL, collector, NULL);
1288 if (ret < 0)
1289 panic("Cannot create phthread!\n");
1291 presenter();
1293 free(geo_country.path4);
1294 free(geo_country.path6);
1296 free(geo_city.path4);
1297 free(geo_city.path6);
1299 return 0;