]> mj.ucw.cz Git - netgrind.git/blob - netgrind/netgrind.c
Better statistics.
[netgrind.git] / netgrind / netgrind.c
1 /*
2  *      Netgrind -- The Network Traffic Analyser
3  *
4  *      (c) 2003 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU General Public License.
8  */
9
10 #include "lib/lib.h"
11 #include "netgrind/pkt.h"
12 #include "netgrind/netgrind.h"
13
14 #include <stdio.h>
15 #include <stdarg.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <getopt.h>
19 #include <netinet/in.h>
20
21 #include <pcap.h>
22
23 void die(byte *msg, ...)
24 {
25   va_list args;
26
27   va_start(args, msg);
28   fputs("netgrind: ", stderr);
29   vfprintf(stderr, msg, args);
30   fputs("\n", stderr);
31   exit(1);
32 }
33
34 /*** MANUAL MULTIPLEXER ***/
35
36 static void mux_open(struct flow *f, u64 when)
37 {
38   u32 saddr = ntohl(f->saddr);
39   u32 daddr = ntohl(f->daddr);
40   uns sport = ntohs(f->sport);
41   uns dport = ntohs(f->dport);
42   struct appl_hooks *appl = &appl_sink;
43
44   if (dport == 80 || dport == 8080 || dport == 8081 || dport == 3128)
45     {
46       appl = &appl_asave;
47       save_dir = "flows";
48     }
49   f->appl = appl;
50   appl->open(f, when);
51 }
52
53 struct appl_hooks appl_mux = {
54   .open = mux_open,
55   .input = sink_input,
56   .close = sink_close
57 };
58
59 /*** PCAP INTERFACE ***/
60
61 static void (*link_handler)(struct pkt *);
62 static struct pkt_stats stat_pcap_incomplete, stat_pcap_in;
63
64 static uns in_count, start_sec;
65 static u64 last_timestamp;
66
67 static int link_setup_handler(int dlt)
68 {
69   switch (dlt)
70     {
71     case DLT_EN10MB:    link_handler = link_eth_got_packet; return 1;
72     default:            return 0;
73     }
74 }
75
76 static void got_pcap_packet(u_char *userdata UNUSED, const struct pcap_pkthdr *hdr, const u_char *pkt)
77 {
78   stat_pcap_in.packets++;
79   stat_pcap_in.bytes += hdr->len;
80   if (hdr->caplen != hdr->len)
81     {
82       stat_pcap_incomplete.packets++;
83       stat_pcap_incomplete.bytes += hdr->len - hdr->caplen;
84       return;
85     }
86   if (!(in_count % 1024))
87     {
88       if (!in_count)
89         start_sec = hdr->ts.tv_sec;
90       fprintf(stderr, "%d packets, %d seconds, %d conns (%d open)\r",
91               in_count, (int)hdr->ts.tv_sec - start_sec,
92               cnt_tcp_flows, tcp_num_flows);
93       fflush(stderr);
94     }
95   in_count++;
96   struct pkt *p = pkt_new(0, hdr->len);
97   memcpy(pkt_append(p, hdr->len), pkt, hdr->len);
98   p->timestamp = (u64)hdr->ts.tv_sec * 1000000 + hdr->ts.tv_usec;
99   last_timestamp = p->timestamp;
100   link_handler(p);
101 }
102
103 /*** MAIN ***/
104
105 static void usage(void)
106 {
107   fprintf(stderr, "Usage: netgrind [<switches>] <capture-file>\n\
108 \n\
109 -a              TCP: Record arrival times instead of processing times\n\
110 -c <count>      Stop after processing <count> packets\n\
111 -d <dir>        Dump connections to a given directory\n\
112 -D <dir>        Dump connections with more details\n\
113 -f <filter>     Apply filter expression\n\
114 -s              Dump connection summary\n\
115 -t              Calculate statistics only\n\
116 -w              TCP: Wait for ACK before processing packets\n\
117 ");
118   exit(1);
119 }
120
121 int main(int argc, char **argv)
122 {
123   char errbuf[PCAP_ERRBUF_SIZE];
124   pcap_t *pcap;
125   int c, dlt;
126   int max_packets = -1;
127   byte *filter = NULL;
128   struct bpf_program filter_prog;
129
130   tcp_default_appl = &appl_mux;
131   while ((c = getopt(argc, argv, "ac:d:D:f:stw")) >= 0)
132     switch (c)
133       {
134       case 'a':
135         tcp_arrival_times = 1;
136         break;
137       case 'c':
138         max_packets = atol(optarg);
139         break;
140       case 'd':
141         tcp_default_appl = &appl_save;
142         save_dir = optarg;
143         break;
144       case 'D':
145         tcp_default_appl = &appl_asave;
146         save_dir = optarg;
147         break;
148       case 'f':
149         filter = optarg;
150         break;
151       case 'w':
152         tcp_wait_for_ack = 1;
153         break;
154       case 's':
155         tcp_default_appl = &appl_summary;
156         break;
157       case 't':
158         tcp_default_appl = &appl_sink;
159         break;
160       default:
161         usage();
162       }
163   if (optind != argc - 1)
164     usage();
165
166   tcp_init();
167
168   if (!(pcap = pcap_open_offline(argv[optind], errbuf)))
169     die("Unable to open %s", errbuf);
170   dlt = pcap_datalink(pcap);
171   if (!link_setup_handler(dlt))
172     die("Don't know how to handle data link type %d", dlt);
173   if (filter)
174     {
175       if (pcap_compile(pcap, &filter_prog, filter, 1, 0) < 0)
176         die("Error compiling filter: %s", pcap_geterr(pcap));
177       pcap_setfilter(pcap, &filter_prog);
178     }
179   if (pcap_loop(pcap, max_packets, got_pcap_packet, NULL) < 0)
180     die("Capture failed: %s", pcap_geterr(pcap));
181   tcp_cleanup(last_timestamp);
182   printf("# Netgrind statistics:\n");
183   printf("# Pcap: %Ld(%Ld) in, %Ld(%Ld) incomplete\n",
184          stat_pcap_in.packets, stat_pcap_in.bytes,
185          stat_pcap_incomplete.packets, stat_pcap_incomplete.bytes);
186   printf("# Link: %Ld(%Ld) in, %Ld(%Ld) dwarves, %Ld(%Ld) strangers, %Ld(%Ld) ARPs\n",
187          stat_link_in.packets, stat_link_in.bytes,
188          stat_link_dwarf.packets, stat_link_dwarf.bytes,
189          stat_link_unknown.packets, stat_link_unknown.bytes,
190          stat_link_arp.packets, stat_link_arp.bytes);
191   printf("# IP: %Ld(%Ld) in, %Ld(%Ld) invalid, %Ld(%Ld) boring, %Ld(%Ld) fragmented, %Ld(%Ld) bad checksum\n",
192          stat_ip_in.packets, stat_ip_in.bytes,
193          stat_ip_invalid.packets, stat_ip_invalid.bytes,
194          stat_ip_uninteresting.packets, stat_ip_uninteresting.bytes,
195          stat_ip_fragmented.packets, stat_ip_fragmented.bytes,
196          stat_ip_badsum.packets, stat_ip_badsum.bytes);
197   printf("# TCP: %Ld(%Ld) in, %Ld(%Ld) invalid, %Ld(%Ld) bad checksum, %Ld(%Ld) unmatched, %Ld(%Ld) on closed connections, %Ld(%Ld) in unexpected state\n",
198          stat_tcp_in.packets, stat_tcp_in.bytes,
199          stat_tcp_invalid.packets, stat_tcp_invalid.bytes,
200          stat_tcp_badsum.packets, stat_tcp_badsum.bytes,
201          stat_tcp_unmatched.packets, stat_tcp_unmatched.bytes,
202          stat_tcp_on_closed.packets, stat_tcp_on_closed.bytes,
203          stat_tcp_bad_state.packets, stat_tcp_bad_state.bytes);
204   printf("# Flows: %d total: %d closed, %d reset, %d timed out, %d overlap end, %d corrupted\n",
205          cnt_tcp_flows, cnt_tcp_causes[CAUSE_CLOSE], cnt_tcp_causes[CAUSE_RESET],
206          cnt_tcp_causes[CAUSE_TIMEOUT], cnt_tcp_causes[CAUSE_DOOMSDAY], cnt_tcp_causes[CAUSE_CORRUPT]);
207   pcap_close(pcap);
208   return 0;
209 }