]> mj.ucw.cz Git - netgrind.git/blob - netgrind/netgrind.c
Cleanup.
[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     appl = &appl_http;
46   f->appl = appl;
47   appl->open(f, when);
48 }
49
50 struct appl_hooks appl_mux = {
51   .open = mux_open,
52   .input = sink_input,
53   .close = sink_close
54 };
55
56 /*** PCAP INTERFACE ***/
57
58 static void (*link_handler)(struct pkt *);
59 static struct pkt_stats stat_pcap_incomplete, stat_pcap_in;
60
61 static uns in_count, start_sec;
62 static u64 last_timestamp;
63
64 static int link_setup_handler(int dlt)
65 {
66   switch (dlt)
67     {
68     case DLT_EN10MB:    link_handler = link_eth_got_packet; return 1;
69     default:            return 0;
70     }
71 }
72
73 static void got_pcap_packet(u_char *userdata UNUSED, const struct pcap_pkthdr *hdr, const u_char *pkt)
74 {
75   stat_pcap_in.packets++;
76   stat_pcap_in.bytes += hdr->len;
77   if (hdr->caplen != hdr->len)
78     {
79       stat_pcap_incomplete.packets++;
80       stat_pcap_incomplete.bytes += hdr->len - hdr->caplen;
81       return;
82     }
83   if (!(in_count % 1024))
84     {
85       if (!in_count)
86         start_sec = hdr->ts.tv_sec;
87       fprintf(stderr, "%d packets, %d seconds, %d conns (%d open)\r",
88               in_count, (int)hdr->ts.tv_sec - start_sec,
89               cnt_tcp_flows, tcp_num_flows);
90       fflush(stderr);
91     }
92   in_count++;
93   struct pkt *p = pkt_new(0, hdr->len);
94   memcpy(pkt_append(p, hdr->len), pkt, hdr->len);
95   p->timestamp = (u64)hdr->ts.tv_sec * 1000000 + hdr->ts.tv_usec;
96   last_timestamp = p->timestamp;
97   link_handler(p);
98 }
99
100 /*** MAIN ***/
101
102 static void usage(void)
103 {
104   fprintf(stderr, "Usage: netgrind [<switches>] <capture-files>\n\
105 \n\
106 -a              TCP: Record arrival times instead of processing times\n\
107 -c <count>      Stop after processing <count> packets\n\
108 -d <dir>        Dump connections to a given directory\n\
109 -D <dir>        Dump connections with more details\n\
110 -f <filter>     Apply filter expression\n\
111 -s              Dump connection summary\n\
112 -t              Calculate statistics only\n\
113 -w              TCP: Wait for ACK before processing packets\n\
114 ");
115   exit(1);
116 }
117
118 int main(int argc, char **argv)
119 {
120   char errbuf[PCAP_ERRBUF_SIZE];
121   pcap_t *pcap;
122   int c, dlt;
123   int max_packets = -1;
124   byte *filter = NULL;
125   struct bpf_program filter_prog;
126
127   tcp_default_appl = &appl_mux;
128   while ((c = getopt(argc, argv, "ac:d:D:f:stw")) >= 0)
129     switch (c)
130       {
131       case 'a':
132         tcp_arrival_times = 1;
133         break;
134       case 'c':
135         max_packets = atol(optarg);
136         break;
137       case 'd':
138         tcp_default_appl = &appl_save;
139         save_dir = optarg;
140         break;
141       case 'D':
142         tcp_default_appl = &appl_asave;
143         save_dir = optarg;
144         break;
145       case 'f':
146         filter = optarg;
147         break;
148       case 'w':
149         tcp_wait_for_ack = 1;
150         break;
151       case 's':
152         tcp_default_appl = &appl_summary;
153         break;
154       case 't':
155         tcp_default_appl = &appl_sink;
156         break;
157       default:
158         usage();
159       }
160   if (optind == argc)
161     usage();
162
163   tcp_init();
164
165   while (optind < argc)
166     {
167       fprintf(stderr, "Processing %s...\n", argv[optind]);
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           pcap_freecode(&filter_prog);
179         }
180       if (pcap_loop(pcap, max_packets, got_pcap_packet, NULL) < 0)
181         die("Capture failed: %s", pcap_geterr(pcap));
182       pcap_close(pcap);
183       optind++;
184     }
185   tcp_cleanup(last_timestamp);
186   printf("# Netgrind statistics:\n");
187   printf("# Pcap: %Ld(%Ld) in, %Ld(%Ld) incomplete\n",
188          stat_pcap_in.packets, stat_pcap_in.bytes,
189          stat_pcap_incomplete.packets, stat_pcap_incomplete.bytes);
190   printf("# Link: %Ld(%Ld) in, %Ld(%Ld) dwarves, %Ld(%Ld) strangers, %Ld(%Ld) ARPs\n",
191          stat_link_in.packets, stat_link_in.bytes,
192          stat_link_dwarf.packets, stat_link_dwarf.bytes,
193          stat_link_unknown.packets, stat_link_unknown.bytes,
194          stat_link_arp.packets, stat_link_arp.bytes);
195   printf("# IP: %Ld(%Ld) in, %Ld(%Ld) invalid, %Ld(%Ld) boring, %Ld(%Ld) fragmented, %Ld(%Ld) bad checksum\n",
196          stat_ip_in.packets, stat_ip_in.bytes,
197          stat_ip_invalid.packets, stat_ip_invalid.bytes,
198          stat_ip_uninteresting.packets, stat_ip_uninteresting.bytes,
199          stat_ip_fragmented.packets, stat_ip_fragmented.bytes,
200          stat_ip_badsum.packets, stat_ip_badsum.bytes);
201   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",
202          stat_tcp_in.packets, stat_tcp_in.bytes,
203          stat_tcp_invalid.packets, stat_tcp_invalid.bytes,
204          stat_tcp_badsum.packets, stat_tcp_badsum.bytes,
205          stat_tcp_unmatched.packets, stat_tcp_unmatched.bytes,
206          stat_tcp_on_closed.packets, stat_tcp_on_closed.bytes,
207          stat_tcp_bad_state.packets, stat_tcp_bad_state.bytes);
208   printf("# Flows: %d total: %d closed, %d reset, %d timed out, %d overlap end, %d corrupted\n",
209          cnt_tcp_flows, cnt_tcp_causes[CAUSE_CLOSE], cnt_tcp_causes[CAUSE_RESET],
210          cnt_tcp_causes[CAUSE_TIMEOUT], cnt_tcp_causes[CAUSE_DOOMSDAY], cnt_tcp_causes[CAUSE_CORRUPT]);
211   return 0;
212 }