2 * Netgrind -- The Network Traffic Analyser
4 * (c) 2003--2013 Martin Mares <mj@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU General Public License.
11 #include "netgrind/pkt.h"
12 #include "netgrind/netgrind.h"
21 #include <netinet/in.h>
25 void die(byte *msg, ...)
30 fputs("netgrind: ", stderr);
31 vfprintf(stderr, msg, args);
36 static volatile int stop_signal;
38 static void sigint_handler(int arg UNUSED)
43 /*** MANUAL MULTIPLEXER ***/
45 static void mux_open(struct flow *f, u64 when)
47 u32 saddr = ntohl(f->saddr);
48 u32 daddr = ntohl(f->daddr);
49 uns sport = ntohs(f->sport);
50 uns dport = ntohs(f->dport);
51 struct appl_hooks *appl = &appl_sink;
53 if (dport == 80 || dport == 8080 || dport == 8081 || dport == 3128)
59 struct appl_hooks appl_mux = {
65 /*** PCAP INTERFACE ***/
67 static void (*link_handler)(struct pkt *);
68 static struct pkt_stats stat_pcap_incomplete, stat_pcap_in;
70 static uns in_count, start_sec;
71 static u64 last_timestamp;
72 static jmp_buf stop_jump;
74 static int link_setup_handler(int dlt)
78 case DLT_EN10MB: link_handler = link_eth_got_packet; return 1;
83 static void got_pcap_packet(u_char *userdata UNUSED, const struct pcap_pkthdr *hdr, const u_char *pkt)
86 longjmp(stop_jump, 1);
87 histogram_step((uns) hdr->ts.tv_sec);
88 stat_pcap_in.packets++;
89 stat_pcap_in.bytes += hdr->len;
90 if (hdr->caplen != hdr->len)
92 stat_pcap_incomplete.packets++;
93 stat_pcap_incomplete.bytes += hdr->len - hdr->caplen;
96 if (!(in_count % 1024))
99 start_sec = hdr->ts.tv_sec;
100 fprintf(stderr, "%d packets, %d seconds, %d conns (%d open)\r",
101 in_count, (int)hdr->ts.tv_sec - start_sec,
102 cnt_tcp_flows, tcp_num_flows);
106 struct pkt *p = pkt_new(0, hdr->len);
107 memcpy(pkt_append(p, hdr->len), pkt, hdr->len);
108 p->timestamp = (u64)hdr->ts.tv_sec * 1000000 + hdr->ts.tv_usec;
109 last_timestamp = p->timestamp;
115 static void usage(void)
117 fprintf(stderr, "Usage: netgrind [<switches>] <capture-files>\n\
119 -a TCP: Record arrival times instead of processing times\n\
120 -b Accept broken checksums\n\
121 -c <count> Stop after processing <count> packets\n\
122 -d <dir> Dump connections to a given directory\n\
123 -D <dir> Dump connections with more details\n\
124 -f <filter> Apply filter expression\n\
125 -h <file> Write packet histogram to <file>\n\
126 -s Dump connection summary\n\
127 -t Calculate statistics only\n\
128 -w TCP: Wait for ACK before processing packets\n\
129 -x <dir> Dump HTTP transactions to a given directory\n\
134 static int max_packets = -1;
135 static byte *filter = NULL;
137 int main(int argc, char **argv)
139 char errbuf[PCAP_ERRBUF_SIZE];
142 struct bpf_program filter_prog;
143 byte *histogram = NULL;
145 tcp_default_appl = &appl_mux;
146 while ((c = getopt(argc, argv, "abc:d:D:f:h:stwx:")) >= 0)
150 tcp_arrival_times = 1;
153 accept_broken_checksums = 1;
156 max_packets = atol(optarg);
159 tcp_default_appl = &appl_save;
163 tcp_default_appl = &appl_asave;
173 tcp_wait_for_ack = 1;
176 tcp_default_appl = &appl_summary;
179 tcp_default_appl = &appl_sink;
182 http_log_dir = optarg;
193 histogram_init(histogram);
194 histogram_add_stat("PcapIn", &stat_pcap_in);
195 histogram_add_stat("PcapIncomp", &stat_pcap_incomplete);
196 histogram_add_stat("LinkIn", &stat_link_in);
197 histogram_add_stat("LinkDwarf", &stat_link_dwarf);
198 histogram_add_stat("LinkUnkn", &stat_link_unknown);
199 histogram_add_stat("LinkArp", &stat_link_arp);
200 histogram_add_stat("IPIn", &stat_ip_in);
201 histogram_add_stat("IPBad", &stat_ip_invalid);
202 histogram_add_stat("IPUnint", &stat_ip_uninteresting);
203 histogram_add_stat("IPFrag", &stat_ip_fragmented);
204 histogram_add_stat("IPBadSum", &stat_ip_badsum);
205 histogram_add_stat("TCPIn", &stat_tcp_in);
206 histogram_add_stat("TCPBad", &stat_tcp_invalid);
207 histogram_add_stat("TCPBadSum", &stat_tcp_badsum);
208 histogram_add_stat("TCPUnmatch", &stat_tcp_unmatched);
209 histogram_add_stat("TCPOnClosed", &stat_tcp_on_closed);
210 histogram_add_stat("TCPBadState", &stat_tcp_bad_state);
211 histogram_add_int("FlowsTotal", &cnt_tcp_flows);
212 histogram_add_int("FlowsClosed", &cnt_tcp_causes[CAUSE_CLOSE]);
213 histogram_add_int("FlowsReset", &cnt_tcp_causes[CAUSE_RESET]);
214 histogram_add_int("FlowsTimeout", &cnt_tcp_causes[CAUSE_TIMEOUT]);
215 histogram_add_int("FlowsDoomsday", &cnt_tcp_causes[CAUSE_DOOMSDAY]);
216 histogram_add_int("FlowsBad", &cnt_tcp_causes[CAUSE_CORRUPT]);
218 signal(SIGINT, sigint_handler);
220 while (optind < argc)
222 fprintf(stderr, "Processing %s...\n", argv[optind]);
223 if (!(pcap = pcap_open_offline(argv[optind], errbuf)))
224 die("Unable to open %s", errbuf);
225 dlt = pcap_datalink(pcap);
226 if (!link_setup_handler(dlt))
227 die("Don't know how to handle data link type %d", dlt);
230 if (pcap_compile(pcap, &filter_prog, filter, 1, 0) < 0)
231 die("Error compiling filter: %s", pcap_geterr(pcap));
232 pcap_setfilter(pcap, &filter_prog);
233 pcap_freecode(&filter_prog);
235 if (!setjmp(stop_jump))
237 if (pcap_loop(pcap, max_packets, got_pcap_packet, NULL) < 0)
239 fprintf(stderr, "Capture failed: %s\n", pcap_geterr(pcap));
245 fprintf(stderr, "Interrupted\n");
251 tcp_cleanup(last_timestamp);
254 printf("# Netgrind statistics:\n");
255 printf("# Pcap: %Ld(%Ld) in, %Ld(%Ld) incomplete\n",
256 stat_pcap_in.packets, stat_pcap_in.bytes,
257 stat_pcap_incomplete.packets, stat_pcap_incomplete.bytes);
258 printf("# Link: %Ld(%Ld) in, %Ld(%Ld) dwarves, %Ld(%Ld) strangers, %Ld(%Ld) ARPs\n",
259 stat_link_in.packets, stat_link_in.bytes,
260 stat_link_dwarf.packets, stat_link_dwarf.bytes,
261 stat_link_unknown.packets, stat_link_unknown.bytes,
262 stat_link_arp.packets, stat_link_arp.bytes);
263 printf("# IP: %Ld(%Ld) in, %Ld(%Ld) invalid, %Ld(%Ld) boring, %Ld(%Ld) fragmented, %Ld(%Ld) bad checksum\n",
264 stat_ip_in.packets, stat_ip_in.bytes,
265 stat_ip_invalid.packets, stat_ip_invalid.bytes,
266 stat_ip_uninteresting.packets, stat_ip_uninteresting.bytes,
267 stat_ip_fragmented.packets, stat_ip_fragmented.bytes,
268 stat_ip_badsum.packets, stat_ip_badsum.bytes);
269 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",
270 stat_tcp_in.packets, stat_tcp_in.bytes,
271 stat_tcp_invalid.packets, stat_tcp_invalid.bytes,
272 stat_tcp_badsum.packets, stat_tcp_badsum.bytes,
273 stat_tcp_unmatched.packets, stat_tcp_unmatched.bytes,
274 stat_tcp_on_closed.packets, stat_tcp_on_closed.bytes,
275 stat_tcp_bad_state.packets, stat_tcp_bad_state.bytes);
276 printf("# Flows: %d total: %d closed, %d reset, %d timed out, %d overlap end, %d corrupted\n",
277 cnt_tcp_flows, cnt_tcp_causes[CAUSE_CLOSE], cnt_tcp_causes[CAUSE_RESET],
278 cnt_tcp_causes[CAUSE_TIMEOUT], cnt_tcp_causes[CAUSE_DOOMSDAY], cnt_tcp_causes[CAUSE_CORRUPT]);