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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
(*
* Copyright (c) 2012-2016 Anil Madhavapeddy <anil@recoil.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)
[%%cstruct
type pcap_header = {
magic_number: uint32_t; (* magic number *)
version_major: uint16_t; (* major version number *)
version_minor: uint16_t; (* minor version number *)
thiszone: uint32_t; (* GMT to local correction *)
sigfigs: uint32_t; (* accuracy of timestamps *)
snaplen: uint32_t; (* max length of captured packets, in octets *)
network: uint32_t; (* data link type *)
} [@@little_endian]]
[%%cstruct
type pcap_packet = {
ts_sec: uint32_t; (* timestamp seconds *)
ts_usec: uint32_t; (* timestamp microseconds *)
incl_len: uint32_t; (* number of octets of packet saved in file *)
orig_len: uint32_t; (* actual length of packet *)
} [@@little_endian]]
[%%cstruct
type ethernet = {
dst: uint8_t [@len 6];
src: uint8_t [@len 6];
ethertype: uint16_t;
} [@@big_endian]]
[%%cstruct
type ipv4 = {
hlen_version: uint8_t;
tos: uint8_t;
len: uint16_t;
id: uint16_t;
off: uint16_t;
ttl: uint8_t;
proto: uint8_t;
csum: uint16_t;
src: uint8_t [@len 4];
dst: uint8_t [@len 4];
} [@@big_endian]]
[%%cstruct
type tcpv4 = {
src_port: uint16_t;
dst_port: uint16_t;
seqnum: uint32_t;
acknum: uint32_t;
offset_flags: uint16_t;
window: uint16_t;
checksum: uint16_t;
urg: uint16_t;
} [@@big_endian]]
let mac_to_string buf =
let i n = Cstruct.get_uint8 buf n in
Printf.sprintf "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"
(i 0) (i 1) (i 2) (i 3) (i 4) (i 5)
open Printf
let print_packet p =
let dst_mac = mac_to_string (get_ethernet_dst p) in
let src_mac = mac_to_string (get_ethernet_src p) in
let ethertype = get_ethernet_ethertype p in
printf "ether %s -> %s etype %x\n" src_mac dst_mac ethertype;
match ethertype with
|0x0800 -> begin
let ip = Cstruct.shift p sizeof_ethernet in
let version = get_ipv4_hlen_version ip lsr 4 in
let hlen = (get_ipv4_hlen_version ip land 0xf) * 4 in
let ttl = get_ipv4_ttl ip in
let proto = get_ipv4_proto ip in
printf "ipv%d hlen %d ttl %d proto %d\n" version hlen ttl proto;
match proto with
|6 -> begin (* tcp *)
let tcp = Cstruct.shift ip sizeof_ipv4 in
let off = 0 in
let x = get_tcpv4_offset_flags tcp in
let data_offset = (x lsr 12) * 4 in
let options =
match data_offset - sizeof_tcpv4 with
|0 -> 0
|n -> n (* TODO parse *)
in
let payload = Cstruct.shift tcp data_offset in
let fin = (x land 1) = 1 in
let syn = (x land 2) = 2 in
let flags = "?" in
let src_port = get_tcpv4_src_port tcp in
let dst_port = get_tcpv4_dst_port tcp in
let seqnum = get_tcpv4_seqnum tcp in
let acknum = get_tcpv4_acknum tcp in
let window = get_tcpv4_window tcp in
printf "tcpv4 port %d->%d seq %lu ack %lu win %d off %d flags %s opt %d fin %b syn %b payload_len=%d\n"
src_port dst_port seqnum
acknum window off flags options fin syn (Cstruct.length payload);
()
end
|_ -> printf "unknown ip proto %d\n" proto
end
|x -> printf "unknown body %x\n" x
let print_pcap_packet (hdr,pkt) =
let ts_sec = get_pcap_packet_ts_sec hdr in
let ts_usec = get_pcap_packet_ts_usec hdr in
let incl_len = get_pcap_packet_incl_len hdr in
let orig_len = get_pcap_packet_orig_len hdr in
printf "\n** %lu.%lu bytes %lu (of %lu)\n"
ts_sec ts_usec incl_len orig_len;
print_packet pkt
let print_pcap_header buf =
let magic = get_pcap_header_magic_number buf in
let endian =
match magic with
|0xa1b2c3d4l -> "bigendian"
|0xd4c3b2a1l -> "littlendian"
|_ -> "not a pcap file"
in
let version_major = get_pcap_header_version_major buf in
let version_minor = get_pcap_header_version_minor buf in
let thiszone = get_pcap_header_thiszone buf in
let sigfis = get_pcap_header_sigfigs buf in
let snaplen = get_pcap_header_snaplen buf in
let header_network = get_pcap_header_network buf in
printf "pcap_header (len %d)\n" sizeof_pcap_header;
printf "magic_number %lx (%s)\n%!" magic endian;
printf "version %d %d\n" version_major version_minor;
printf "timezone shift %lu\n" thiszone;
printf "timestamp accuracy %lu\n" sigfis;
printf "snaplen %lu\n" snaplen;
printf "lltype %lx\n" header_network
let parse () =
printf "start parse\n%!";
let fd = Unix.(openfile "http.cap" [O_RDONLY] 0) in
let t = Unix_cstruct.of_fd fd in
printf "total pcap file length %d\n%!" (Cstruct.length t);
let header, body = Cstruct.split t sizeof_pcap_header in
print_pcap_header header;
let packets = Cstruct.iter
(fun buf -> Some (sizeof_pcap_packet + Int32.to_int (get_pcap_packet_incl_len buf)))
(fun buf -> buf, Cstruct.shift buf sizeof_pcap_packet)
body
in
let num_packets = Cstruct.fold
(fun a packet -> print_pcap_packet packet; (a+1))
packets 0
in
printf "num_packets %d\n%!" num_packets
let () = parse ()
|