169 lines
5.6 KiB
OCaml
169 lines
5.6 KiB
OCaml
(*
|
|
* 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 ()
|