2 * Netgrind -- The Network Traffic Analyser
4 * (c) 2003 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.
14 #include "netgrind/netgrind.h"
15 #include "netgrind/pkt.h"
21 #include <net/ethernet.h>
22 #include <netinet/in.h>
23 #include <netinet/ip.h>
24 #include <netinet/tcp.h>
28 void die(byte *msg, ...)
33 fputs("netgrind: ", stderr);
34 vfprintf(stderr, msg, args);
39 /*** CHECKSUMMING ***/
41 static uns tcpip_calc_checksum(void *data, uns len, uns csum)
47 csum += (x[0] << 8) | x[1];
48 if (csum & 0xffff0000)
59 if (csum & 0xffff0000)
68 static inline uns tcpip_verify_checksum(uns csum)
70 return (csum == 0xffff);
73 /*** FLOW ANALYSIS ***/
85 void (*open)(struct flow *f);
86 void (*input)(struct flow *f, int dir, struct pkt *p);
87 void (*close)(struct flow *f, int cause);
90 static void sink_open(struct flow *f)
94 static void sink_close(struct flow *f, int cause)
98 static void sink_input(struct flow *f, int dir, struct pkt *p)
102 struct appl_hooks appl_sink = {
110 static struct pkt_stats stat_tcp_in, stat_tcp_invalid, stat_tcp_badsum, stat_tcp_unmatched,
118 FLOW_SYN_SENT, /* sent SYN, waiting for SYN ACK */
119 FLOW_SYN_SENT_ACK, /* sent SYN ACK, waiting for first ACK */
120 FLOW_ESTABLISHED, /* established state including waiting for ACK of SYN ACK */
121 FLOW_FIN_SENT, /* sent FIN, waiting for its ACK */
122 FLOW_CLOSED /* closed, ignoring further packets */
127 struct flow *hash_next;
128 u32 saddr, daddr, sport, dport;
131 struct appl_hooks *appl;
136 static uns num_flows, max_flows;
137 static struct flow **flow_hash;
138 static struct flow **flow_heap;
140 static uns flow_calc_hash(u32 saddr, u32 daddr, u32 sport, u32 dport)
142 saddr = (saddr >> 16) | (saddr << 16);
143 daddr = (daddr >> 8) | (daddr << 24);
146 return (saddr + daddr + sport + dport) % max_flows;
149 #define FLOW_HEAP_LESS(a,b) (a->timeout < b->timeout)
150 #define FLOW_HEAP_SWAP(h,a,b,t) do { t=h[a]; h[a]=h[b]; h[b]=t; h[a]->heap_pos=a; h[b]->heap_pos=b; } while(0)
152 static void flow_rehash(void)
154 uns omax = max_flows;
155 struct flow **ohash = flow_hash;
160 max_flows = nextprime(2*max_flows);
163 DBG("Rehashing to %d buckets\n", max_flows);
164 flow_hash = xmalloc_zero(sizeof(struct flow *) * max_flows);
165 flow_heap = xmalloc_zero(sizeof(struct flow *) * (max_flows+1));
167 for (uns i=0; i<omax; i++)
169 struct flow *f = ohash[i];
172 struct flow *n = f->hash_next;
173 uns h = flow_calc_hash(f->saddr, f->daddr, f->sport, f->dport);
174 f->hash_next = flow_hash[h];
176 flow_heap[++num_flows] = f;
177 f->heap_pos = num_flows;
183 HEAP_INIT(struct flow *, flow_heap, num_flows, FLOW_HEAP_LESS, FLOW_HEAP_SWAP);
186 static struct flow *flow_lookup(u32 saddr, u32 daddr, u32 sport, u32 dport)
188 uns h = flow_calc_hash(saddr, daddr, sport, dport);
189 for (struct flow *f = flow_hash[h]; f; f=f->hash_next)
190 if (f->saddr == saddr && f->daddr == daddr &&
191 f->sport == sport && f->dport == dport)
196 static struct flow *flow_create(u32 saddr, u32 daddr, u32 sport, u32 dport)
198 if (num_flows >= max_flows)
200 uns h = flow_calc_hash(saddr, daddr, sport, dport);
201 struct flow *f = xmalloc_zero(sizeof(struct flow));
207 f->hash_next = flow_hash[h];
209 flow_heap[++num_flows] = f;
210 f->heap_pos = num_flows;
214 static void flow_set_timeout(struct flow *f, u32 when)
217 HEAP_CHANGE(struct flow *, flow_heap, num_flows, FLOW_HEAP_LESS, FLOW_HEAP_SWAP, f->heap_pos);
220 static uns flow_now(struct pkt *p)
222 return p->timestamp >> 20;
225 static void tcp_time_step(uns now)
227 while (num_flows && flow_heap[1]->timeout <= now)
229 struct flow *f = flow_heap[1];
230 HEAP_DELMIN(struct flow *, flow_heap, num_flows, FLOW_HEAP_LESS, FLOW_HEAP_SWAP);
231 DBG("TIMEOUT for flow %p(%d/%d)\n", f, f->pipe[0].state, f->pipe[1].state);
232 if (f->pipe[0].state != FLOW_CLOSED || f->pipe[1].state != FLOW_CLOSED)
233 f->appl->close(f, (now == ~0U) ? CAUSE_DOOMSDAY : CAUSE_TIMEOUT);
234 uns h = flow_calc_hash(f->saddr, f->daddr, f->sport, f->dport);
235 struct flow **gg = &flow_hash[h];
244 gg = &(*gg)->hash_next;
250 static void tcp_got_packet(struct iphdr *iph, struct pkt *p)
260 uns now = flow_now(p);
264 pkt_account(&stat_tcp_in, p);
265 if (!(tcph = pkt_peek(p, sizeof(*tcph))))
267 uns hdrlen = 4*tcph->doff;
268 if (hdrlen < sizeof(*tcph) || hdrlen > pkt_len(p))
270 fakehdr.src = iph->saddr;
271 fakehdr.dst = iph->daddr;
273 fakehdr.proto = IPPROTO_TCP;
274 fakehdr.len = htons(pkt_len(p));
275 uns sum = tcpip_calc_checksum(&fakehdr, sizeof(fakehdr), 0);
276 sum = tcpip_calc_checksum(p->data, pkt_len(p), sum);
277 if (!tcpip_verify_checksum(sum))
279 pkt_account(&stat_tcp_badsum, p);
282 /* XXX: Check TCP options? */
285 u32 seq = ntohl(tcph->seq);
286 u32 ack = ntohl(tcph->ack_seq);
287 DBG("TCP %08x %08x %04x %04x seq=%u+%u ack=%u%s%s%s%s%s%s\n",
288 ntohl(iph->saddr), ntohl(iph->daddr), ntohs(tcph->source), ntohs(tcph->dest), seq, pkt_len(p), ack,
289 (tcph->fin ? " FIN" : ""),
290 (tcph->syn ? " SYN" : ""),
291 (tcph->rst ? " RST" : ""),
292 (tcph->psh ? " PSH" : ""),
293 (tcph->ack ? " ACK" : ""),
294 (tcph->urg ? " URG" : ""));
298 if (f = flow_lookup(iph->saddr, iph->daddr, tcph->source, tcph->dest))
303 else if (f = flow_lookup(iph->daddr, iph->saddr, tcph->dest, tcph->source))
310 /* Flow not found, if it's a SYN packet, go create it */
311 if (tcph->syn && !tcph->ack && !tcph->rst && !tcph->fin)
313 f = flow_create(iph->saddr, iph->daddr, tcph->source, tcph->dest);
314 f->appl = &appl_sink;
318 list_init(&a->queue);
319 a->last_acked_seq = seq;
320 a->state = FLOW_SYN_SENT;
321 list_init(&b->queue);
322 b->state = FLOW_IDLE;
323 DBG("\t%p NEW\n", f);
326 DBG("\tUnmatched\n");
327 pkt_account(&stat_tcp_unmatched, p);
331 DBG("\t%p(%d/%d) ", f, a->state, b->state);
332 if (a->state == FLOW_CLOSED && b->state == FLOW_CLOSED)
335 pkt_account(&stat_tcp_on_closed, p);
342 f->appl->close(f, CAUSE_RESET);
343 a->state = b->state = FLOW_CLOSED;
344 flow_set_timeout(f, now + 300); /* FIXME */
348 flow_set_timeout(f, now + 600); /* FIXME */
352 if (tcph->fin || pkt_len(p))
356 if (b->state == FLOW_SYN_SENT && b->last_acked_seq+1 == ack)
359 b->last_acked_seq = ack;
360 a->state = FLOW_SYN_SENT_ACK;
361 a->last_acked_seq = seq;
364 else if (b->state == FLOW_ESTABLISHED)
370 goto dup; /* otherwise SYN on already existing connection gets ignored */
375 if (b->state == FLOW_SYN_SENT_ACK && b->last_acked_seq+1)
377 a->state = b->state = FLOW_ESTABLISHED;
378 b->last_acked_seq = ack+1;
381 if (b->state == FLOW_FIN_SENT && b->last_acked_seq+1 == ack)
383 b->state = FLOW_CLOSED;
384 if (a->state == FLOW_CLOSED)
386 DBG("CLOSED BOTH WAYS\n");
387 f->appl->close(f, CAUSE_CLOSE);
388 flow_set_timeout(f, now + 300); /* FIXME */
392 DBG("CLOSED ONE-WAY, ");
394 else if (b->state == FLOW_ESTABLISHED || b->state == FLOW_FIN_SENT)
396 else if (b->state == FLOW_CLOSED)
404 if (a->state == FLOW_ESTABLISHED)
406 a->state = FLOW_FIN_SENT;
407 a->last_acked_seq = seq;
408 DBG("FIN SENT, waiting for FIN ACK, ");
410 else if (a->state == FLOW_FIN_SENT)
422 if (b->state == FLOW_ESTABLISHED || b->state == FLOW_FIN_SENT || b->state == FLOW_CLOSED)
425 // list_add_tail(&b->queue, &p->n); /* FIXME */
427 f->appl->input(f, (a == &f->pipe[1]), p);
448 pkt_account(&stat_tcp_invalid, p);
454 static struct pkt_stats stat_ip_in, stat_ip_invalid, stat_ip_uninteresting, stat_ip_fragmented, stat_ip_badsum;
456 static void ip_got_packet(struct pkt *p)
460 pkt_account(&stat_ip_in, p);
461 if (!(iph = pkt_peek(p, sizeof(*iph))))
465 if (iph->version != 4)
467 uns hdrlen = 4*iph->ihl;
468 if (pkt_len(p) < hdrlen)
470 if (!tcpip_verify_checksum(tcpip_calc_checksum(p->data, hdrlen, 0)))
472 pkt_account(&stat_ip_badsum, p);
475 uns len = ntohs(iph->tot_len);
476 if (len < hdrlen || len > pkt_len(p))
478 pkt_unappend(p, pkt_len(p) - len);
481 if (iph->protocol != IPPROTO_TCP)
483 pkt_account(&stat_ip_uninteresting, p);
486 /* XXX: Fragmentation not supported yet, but well-behaved TCP stacks don't use it anyway */
487 if (ntohs(iph->frag_off) & 0x3fff)
489 pkt_account(&stat_ip_fragmented, p);
492 tcp_got_packet(iph, p);
496 pkt_account(&stat_ip_invalid, p);
503 static struct pkt_stats stat_link_dwarf, stat_link_in, stat_link_unknown, stat_link_arp;
505 static void link_eth_got_packet(struct pkt *p)
507 struct ether_header *eth;
510 pkt_account(&stat_link_in, p);
511 if (!(eth = pkt_pop(p, sizeof(*eth))))
513 pkt_account(&stat_link_dwarf, p);
516 etype = ntohs(eth->ether_type);
523 pkt_account(&stat_link_arp, p);
527 // printf("Unknown ethertype: %04x\n", etype);
528 pkt_account(&stat_link_unknown, p);
533 /*** PCAP INTERFACE ***/
535 static void (*link_handler)(struct pkt *);
536 static struct pkt_stats stat_pcap_incomplete;
538 static int link_setup_handler(int dlt)
542 case DLT_EN10MB: link_handler = link_eth_got_packet; return 1;
547 static void got_pcap_packet(u_char *userdata UNUSED, const struct pcap_pkthdr *hdr, const u_char *pkt)
549 if (hdr->caplen != hdr->len)
551 stat_pcap_incomplete.packets++;
552 stat_pcap_incomplete.bytes += hdr->len - hdr->caplen;
555 struct pkt *p = pkt_new(0, hdr->len);
556 memcpy(pkt_append(p, hdr->len), pkt, hdr->len);
557 p->timestamp = (u64)hdr->ts.tv_sec * 1000000 + hdr->ts.tv_usec;
561 int main(int argc, char **argv)
563 char errbuf[PCAP_ERRBUF_SIZE];
568 die("Usage: netgrind <capture-file>");
572 if (!(pcap = pcap_open_offline(argv[1], errbuf)))
573 die("Unable to open %s: %s", argv[1], errbuf);
574 dlt = pcap_datalink(pcap);
575 if (!link_setup_handler(dlt))
576 die("Don't know how to handle data link type %d", dlt);
577 if (pcap_loop(pcap, -1, got_pcap_packet, NULL) < 0)
578 die("Capture failed: %s", pcap_geterr(pcap));
581 struct pcap_stat stats;
582 if (pcap_stats(pcap, &stats))
583 die("pcap_stats: %s", pcap_geterr(pcap));
584 printf("libpcap stats: %d packets received, %d dropped\n", stats.ps_recv, stats.ps_drop);
586 printf("Pcap: %Ld(%Ld) incomplete\n",
587 stat_pcap_incomplete.packets, stat_pcap_incomplete.bytes);
588 printf("Link: %Ld(%Ld) in, %Ld(%Ld) dwarves, %Ld(%Ld) strangers, %Ld(%Ld) ARPs\n",
589 stat_link_in.packets, stat_link_in.bytes,
590 stat_link_dwarf.packets, stat_link_dwarf.bytes,
591 stat_link_unknown.packets, stat_link_unknown.bytes,
592 stat_link_arp.packets, stat_link_arp.bytes);
593 printf("IP: %Ld(%Ld) in, %Ld(%Ld) invalid, %Ld(%Ld) boring, %Ld(%Ld) fragmented, %Ld(%Ld) bad checksum\n",
594 stat_ip_in.packets, stat_ip_in.bytes,
595 stat_ip_invalid.packets, stat_ip_invalid.bytes,
596 stat_ip_uninteresting.packets, stat_ip_uninteresting.bytes,
597 stat_ip_fragmented.packets, stat_ip_fragmented.bytes,
598 stat_ip_badsum.packets, stat_ip_badsum.bytes);
599 printf("TCP: %Ld(%Ld) in, %Ld(%Ld) invalid, %Ld(%Ld) bad checksum\n",
600 stat_tcp_in.packets, stat_tcp_in.bytes,
601 stat_tcp_invalid.packets, stat_tcp_invalid.bytes,
602 stat_tcp_badsum.packets, stat_tcp_badsum.bytes);