My favorites | Sign in
Project Home Downloads Wiki Issues Source
Checkout   Browse   Changes    
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
(* Print out packets from a tcpdump / libpcap / wireshark capture file.
* $Id$
*
* To test this, capture some data using:
* /usr/sbin/tcpdump -s 1500 -w /tmp/dump
* then analyze it using:
* ./libpcap /tmp/dump
*
* The file format is documented here:
* http://wiki.wireshark.org/Development/LibpcapFileFormat
*
* libpcap endianness is determined at runtime.
*)

open Printf

let rec main () =
if Array.length Sys.argv <= 1 then failwith "libpcap dumpfile";
let bits = Bitstring.bitstring_of_file Sys.argv.(1) in
let endian, file_header, bits = libpcap_header bits in

(* Read the packets and print them out. *)
let rec loop bits =
let pkt_header, pkt_data, bits = libpcap_packet endian file_header bits in
decode_and_print_packet file_header pkt_header pkt_data;
loop bits
in
try loop bits
with
End_of_file -> ()

(* Determine the endianness (at runtime) from the magic number. *)
and endian_of = function
| 0xa1b2c3d4_l -> Bitstring.BigEndian
| 0xd4c3b2a1_l -> Bitstring.LittleEndian
| _ -> assert false

and libpcap_header bits =
bitmatch bits with
| { ((0xa1b2c3d4_l|0xd4c3b2a1_l) as magic) : 32; (* magic number *)
major : 16 : endian (endian_of magic); (* version *)
minor : 16 : endian (endian_of magic);
timezone : 32 : endian (endian_of magic); (* timezone correction (secs)*)
_ : 32 : endian (endian_of magic); (* always 0 apparently *)
snaplen : 32 : endian (endian_of magic); (* max length of capt pckts *)
network : 32 : endian (endian_of magic); (* data link layer type *)
rest : -1 : bitstring
} ->
endian_of magic, (major, minor, timezone, snaplen, network), rest

| { _ } ->
failwith "not a libpcap/tcpdump packet capture file"

and libpcap_packet e file_header bits =
bitmatch bits with
| { ts_sec : 32 : endian (e); (* packet timestamp seconds *)
ts_usec : 32 : endian (e); (* packet timestamp microseconds *)
incl_len : 32 : endian (e); (* packet length saved in this file *)
orig_len : 32 : endian (e); (* packet length originally on wire *)
pkt_data : Int32.to_int incl_len*8 : bitstring;
rest : -1 : bitstring
} ->
(ts_sec, ts_usec, incl_len, orig_len), pkt_data, rest

| { _ } -> raise End_of_file

and decode_and_print_packet file_header pkt_header pkt_data =
let (ts_sec, ts_usec, _, orig_len) = pkt_header in
printf "%ld.%ld %ldB " ts_sec ts_usec orig_len;

(* Assume an ethernet frame containing an IPv4/6 packet. We ignore
* the ethertype field and determine the IP version from the packet
* itself. If it doesn't match our assumptions, hexdump it.
*)
(bitmatch pkt_data with
| { d0 : 8; d1 : 8; d2 : 8; d3 : 8; d4 : 8; d5 : 8; (* ether dest *)
s0 : 8; s1 : 8; s2 : 8; s3 : 8; s4 : 8; s5 : 8; (* ether src *)
_ : 16; (* ethertype *)
packet : -1 : bitstring (* payload *)
} ->
printf "%x:%x:%x:%x:%x:%x < %x:%x:%x:%x:%x:%x "
d0 d1 d2 d3 d4 d5 s0 s1 s2 s3 s4 s5;

(bitmatch packet with
| { 4 : 4; (* IPv4 *)
hdrlen : 4; tos : 8; length : 16;
identification : 16; flags : 3; fragoffset : 13;
ttl : 8; protocol : 8; checksum : 16;
s0 : 8; s1 : 8; s2 : 8; s3 : 8;
d0 : 8; d1 : 8; d2 : 8; d3 : 8;
_(*options*) : (hdrlen-5)*32 : bitstring;
_(*payload*) : -1 : bitstring } ->
printf "IPv4 %d.%d.%d.%d < %d.%d.%d.%d "
s0 s1 s2 s3 d0 d1 d2 d3

| { 6 : 4; (* IPv6 *)
tclass : 8; flow : 20;
length : 16; nexthdr : 8; ttl : 8;
_(*source*) : 128 : bitstring;
_(*dest*) : 128 : bitstring;
_(*payload*) : -1 : bitstring } ->
printf "IPv6 ";

| { _ } ->
printf "\n"; Bitstring.hexdump_bitstring stdout packet
)

| { _ } ->
printf "\n"; Bitstring.hexdump_bitstring stdout pkt_data
);
printf "\n"

let () = main ()

Change log

r142 by richard.wm.jones on Jul 17, 2008   Diff
Renaming bitmatch -> bitstring.
Go to: 
Project members, sign in to write a code review

Older revisions

r79 by richard.wm.jones on May 21, 2008   Diff
Endianness expressions.
r76 by richard.wm.jones on May 19, 2008   Diff
Added libpcap parsing example.
All revisions of this file

File info

Size: 3886 bytes, 113 lines

File properties

svn:keywords
Id
Powered by Google Project Hosting