1 (* Print out packets from a tcpdump / libpcap / wireshark capture file.
4 * To test this, capture some data using:
5 * /usr/sbin/tcpdump -s 1500 -w /tmp/dump
6 * then analyze it using:
9 * The file format is documented here:
10 * http://wiki.wireshark.org/Development/LibpcapFileFormat
12 * libpcap endianness is determined at runtime.
18 if Array.length Sys.argv <= 1 then failwith "libpcap dumpfile";
19 let bits = Bitstring.bitstring_of_file Sys.argv.(1) in
20 let endian, file_header, bits = libpcap_header bits in
22 (* Read the packets and print them out. *)
24 let pkt_header, pkt_data, bits = libpcap_packet endian file_header bits in
25 decode_and_print_packet file_header pkt_header pkt_data;
32 (* Determine the endianness (at runtime) from the magic number. *)
33 and endian_of = function
34 | 0xa1b2c3d4_l -> Bitstring.BigEndian
35 | 0xd4c3b2a1_l -> Bitstring.LittleEndian
38 and libpcap_header bits =
40 | { ((0xa1b2c3d4_l|0xd4c3b2a1_l) as magic) : 32; (* magic number *)
41 major : 16 : endian (endian_of magic); (* version *)
42 minor : 16 : endian (endian_of magic);
43 timezone : 32 : endian (endian_of magic); (* timezone correction (secs)*)
44 _ : 32 : endian (endian_of magic); (* always 0 apparently *)
45 snaplen : 32 : endian (endian_of magic); (* max length of capt pckts *)
46 network : 32 : endian (endian_of magic); (* data link layer type *)
49 endian_of magic, (major, minor, timezone, snaplen, network), rest
52 failwith "not a libpcap/tcpdump packet capture file"
54 and libpcap_packet e file_header bits =
56 | { ts_sec : 32 : endian (e); (* packet timestamp seconds *)
57 ts_usec : 32 : endian (e); (* packet timestamp microseconds *)
58 incl_len : 32 : endian (e); (* packet length saved in this file *)
59 orig_len : 32 : endian (e); (* packet length originally on wire *)
60 pkt_data : Int32.to_int incl_len*8 : bitstring;
63 (ts_sec, ts_usec, incl_len, orig_len), pkt_data, rest
65 | { _ } -> raise End_of_file
67 and decode_and_print_packet file_header pkt_header pkt_data =
68 let (ts_sec, ts_usec, _, orig_len) = pkt_header in
69 printf "%ld.%ld %ldB " ts_sec ts_usec orig_len;
71 (* Assume an ethernet frame containing an IPv4/6 packet. We ignore
72 * the ethertype field and determine the IP version from the packet
73 * itself. If it doesn't match our assumptions, hexdump it.
75 (bitmatch pkt_data with
76 | { d0 : 8; d1 : 8; d2 : 8; d3 : 8; d4 : 8; d5 : 8; (* ether dest *)
77 s0 : 8; s1 : 8; s2 : 8; s3 : 8; s4 : 8; s5 : 8; (* ether src *)
78 _ : 16; (* ethertype *)
79 packet : -1 : bitstring (* payload *)
81 printf "%x:%x:%x:%x:%x:%x < %x:%x:%x:%x:%x:%x "
82 d0 d1 d2 d3 d4 d5 s0 s1 s2 s3 s4 s5;
86 hdrlen : 4; tos : 8; length : 16;
87 identification : 16; flags : 3; fragoffset : 13;
88 ttl : 8; protocol : 8; checksum : 16;
89 s0 : 8; s1 : 8; s2 : 8; s3 : 8;
90 d0 : 8; d1 : 8; d2 : 8; d3 : 8;
91 _(*options*) : (hdrlen-5)*32 : bitstring;
92 _(*payload*) : -1 : bitstring } ->
93 printf "IPv4 %d.%d.%d.%d < %d.%d.%d.%d "
94 s0 s1 s2 s3 d0 d1 d2 d3
97 tclass : 8; flow : 20;
98 length : 16; nexthdr : 8; ttl : 8;
99 _(*source*) : 128 : bitstring;
100 _(*dest*) : 128 : bitstring;
101 _(*payload*) : -1 : bitstring } ->
105 printf "\n"; Bitstring.hexdump_bitstring stdout packet
109 printf "\n"; Bitstring.hexdump_bitstring stdout pkt_data