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.
11 #include "netgrind/netgrind.h"
12 #include "netgrind/pkt.h"
18 #include <net/ethernet.h>
19 #include <netinet/in.h>
20 #include <netinet/ip.h>
21 #include <netinet/tcp.h>
25 void die(byte *msg, ...)
30 fputs("netgrind: ", stderr);
31 vfprintf(stderr, msg, args);
36 /*** CHECKSUMMING ***/
38 static uns tcpip_calc_checksum(void *data, uns len, uns csum)
44 csum += (x[0] << 8) | x[1];
45 if (csum & 0xffff0000)
56 if (csum & 0xffff0000)
65 static inline uns tcpip_verify_checksum(uns csum)
67 return (csum == 0xffff);
72 static struct pkt_stats stat_tcp_in, stat_tcp_invalid;
74 static void tcp_got_packet(struct iphdr *iph, struct pkt *p)
85 pkt_account(&stat_tcp_in, p);
86 if (!(tcph = pkt_peek(p, sizeof(*tcph))))
88 uns hdrlen = 4*tcph->doff;
89 if (hdrlen < sizeof(*tcph) || hdrlen > pkt_len(p))
91 fakehdr.src = iph->saddr;
92 fakehdr.dst = iph->daddr;
94 fakehdr.proto = IPPROTO_TCP;
95 fakehdr.len = htons(pkt_len(p));
96 uns sum = tcpip_calc_checksum(&fakehdr, sizeof(fakehdr), 0);
97 sum = tcpip_calc_checksum(p->data, pkt_len(p), sum);
98 if (!tcpip_verify_checksum(sum))
101 /* Here we should do something with the packet */
106 pkt_account(&stat_tcp_invalid, p);
112 static struct pkt_stats stat_ip_in, stat_ip_invalid, stat_ip_uninteresting, stat_ip_fragmented;
114 static void ip_got_packet(struct pkt *p)
118 pkt_account(&stat_ip_in, p);
119 if (!(iph = pkt_peek(p, sizeof(*iph))))
123 if (iph->version != 4)
125 uns hdrlen = 4*iph->ihl;
126 if (pkt_len(p) < hdrlen)
128 if (!tcpip_verify_checksum(tcpip_calc_checksum(p->data, hdrlen, 0)))
130 uns len = ntohs(iph->tot_len);
131 if (len < hdrlen || len > pkt_len(p))
133 pkt_unappend(p, pkt_len(p) - len);
136 if (iph->protocol != IPPROTO_TCP)
138 pkt_account(&stat_ip_uninteresting, p);
141 /* XXX: Fragmentation not supported yet, but well-behaved TCP stacks don't use it anyway */
142 if (ntohs(iph->frag_off) & 0x3fff)
144 pkt_account(&stat_ip_fragmented, p);
147 tcp_got_packet(iph, p);
151 pkt_account(&stat_ip_invalid, p);
158 static struct pkt_stats stat_link_dwarf, stat_link_in, stat_link_unknown, stat_link_arp;
160 static void link_eth_got_packet(struct pkt *p)
162 struct ether_header *eth;
165 pkt_account(&stat_link_in, p);
166 if (!(eth = pkt_pop(p, sizeof(*eth))))
168 pkt_account(&stat_link_dwarf, p);
171 etype = ntohs(eth->ether_type);
178 pkt_account(&stat_link_arp, p);
182 // printf("Unknown ethertype: %04x\n", etype);
183 pkt_account(&stat_link_unknown, p);
188 /*** PCAP INTERFACE ***/
190 static void (*link_handler)(struct pkt *);
191 static struct pkt_stats stat_pcap_incomplete;
193 static int link_setup_handler(int dlt)
197 case DLT_EN10MB: link_handler = link_eth_got_packet; return 1;
202 static void got_pcap_packet(u_char *userdata UNUSED, const struct pcap_pkthdr *hdr, const u_char *pkt)
204 if (hdr->caplen != hdr->len)
206 stat_pcap_incomplete.packets++;
207 stat_pcap_incomplete.bytes += hdr->len - hdr->caplen;
210 struct pkt *p = pkt_new(0, hdr->len);
211 memcpy(pkt_append(p, hdr->len), pkt, hdr->len);
215 int main(int argc, char **argv)
217 char errbuf[PCAP_ERRBUF_SIZE];
222 die("Usage: netgrind <capture-file>");
224 if (!(pcap = pcap_open_offline(argv[1], errbuf)))
225 die("Unable to open %s: %s", argv[1], errbuf);
226 dlt = pcap_datalink(pcap);
227 if (!link_setup_handler(dlt))
228 die("Don't know how to handle data link type %d", dlt);
229 if (pcap_loop(pcap, -1, got_pcap_packet, NULL) < 0)
230 die("Capture failed: %s", pcap_geterr(pcap));
232 struct pcap_stat stats;
233 if (pcap_stats(pcap, &stats))
234 die("pcap_stats: %s", pcap_geterr(pcap));
235 printf("libpcap stats: %d packets received, %d dropped\n", stats.ps_recv, stats.ps_drop);
237 printf("Pcap: %Ld(%Ld) incomplete\n",
238 stat_pcap_incomplete.packets, stat_pcap_incomplete.bytes);
239 printf("Link: %Ld(%Ld) in, %Ld(%Ld) dwarves, %Ld(%Ld) strangers, %Ld(%Ld) ARPs\n",
240 stat_link_in.packets, stat_link_in.bytes,
241 stat_link_dwarf.packets, stat_link_dwarf.bytes,
242 stat_link_unknown.packets, stat_link_unknown.bytes,
243 stat_link_arp.packets, stat_link_arp.bytes);
244 printf("IP: %Ld(%Ld) in, %Ld(%Ld) invalid, %Ld(%Ld) boring, %Ld(%Ld) fragmented\n",
245 stat_ip_in.packets, stat_ip_in.bytes,
246 stat_ip_invalid.packets, stat_ip_invalid.bytes,
247 stat_ip_uninteresting.packets, stat_ip_uninteresting.bytes,
248 stat_ip_fragmented.packets, stat_ip_fragmented.bytes);
249 printf("TCP: %Ld(%Ld) in, %Ld(%Ld) invalid\n",
250 stat_tcp_in.packets, stat_tcp_in.bytes,
251 stat_tcp_invalid.packets, stat_tcp_invalid.bytes);