Permalink
Browse files

add support for byte buffers, and flesh out the pcap parser, and add …

…little_endian module
  • Loading branch information...
1 parent 8a6a370 commit d032f0ecd5fc634b6c2107c58261edcb2f7ec8ea @avsm committed May 10, 2012
Showing with 174 additions and 54 deletions.
  1. +58 −5 lib/cstruct.ml
  2. +15 −1 lib/cstruct.mli
  3. +67 −21 lib_test/ipv4.ml
  4. +34 −27 syntax/pa_cstruct.ml
View
63 lib/cstruct.ml
@@ -33,12 +33,18 @@ module BE = struct
let get_uint16 s off =
let a = get_uint8 s off in
let b = get_uint8 s (off+1) in
- (b lsl 8) + a
+ (a lsl 8) + b
let get_uint32 s off =
- let a = Int32.of_int (get_uint16 s off) in
- let b = Int32.of_int (get_uint16 s (off+2)) in
- Int32.(add (shift_left b 16) a)
+ let a = get_uint8 s off in
+ let b = get_uint8 s (off+1) in
+ let c = get_uint8 s (off+2) in
+ let d = get_uint8 s (off+3) in
+ let e = (b lsl 16) + (c lsl 8) + d in
+ Int32.(add (shift_left (of_int a) 24) (of_int e))
+
+ let get_buffer s off len =
+ sub s off len
let set_uint8 s off v =
set s off (Char.chr v)
@@ -50,14 +56,53 @@ module BE = struct
let set_uint32 s off v =
set_uint16 s off (Int32.(to_int (shift_right_logical v 16)));
set_uint16 s (off+2) (Int32.(to_int (logand v 0xffffl)))
+
+ let set_buffer s off len src =
+ let dst = sub s off len in
+ blit src dst
end
module LE = struct
open Bigarray.Array1
let get_uint8 s off =
Char.code (get s off)
- (* TODO *)
+
+ let get_uint16 s off =
+ let a = get_uint8 s off in
+ let b = get_uint8 s (off+1) in
+ (b lsl 8) + b
+
+ let get_uint32 s off =
+ let a = get_uint8 s off in
+ let b = get_uint8 s (off+1) in
+ let c = get_uint8 s (off+2) in
+ let d = get_uint8 s (off+3) in
+ let e = (c lsl 16) + (b lsl 8) + a in
+ Int32.(add (shift_left (of_int d) 24) (of_int e))
+
+ let get_buffer s off len =
+ sub s off len
+
+ let set_uint8 s off v =
+ set s off (Char.chr v)
+
+ let set_uint16 s off v =
+ set_uint8 s off (v land 0xff);
+ set_uint8 s (off+1) (v lsr 8)
+
+ let set_uint32 s off v =
+ set_uint16 s off (Int32.(to_int (shift_right_logical v 16)));
+ set_uint16 s (off+2) (Int32.(to_int (logand v 0xffffl)))
+
+ let set_uint32 s off v =
+ set_uint16 s off (Int32.(to_int (logand v 0xffffl)));
+ set_uint16 s (off+2) (Int32.(to_int (shift_right_logical v 16)))
+
+ let set_buffer s off len src =
+ let dst = sub s off len in
+ blit src dst
+
end
let len buf = dim buf
@@ -71,3 +116,11 @@ let split buf off =
let body = sub buf off (len buf - off) in
header, body
+let hexdump buf =
+ let c = ref 0 in
+ for i = 0 to len buf - 1 do
+ if !c mod 16 = 0 then print_endline "";
+ printf "%.2x " (Char.code (get buf i));
+ incr c;
+ done;
+ print_endline ""
View
16 lib/cstruct.mli
@@ -21,18 +21,32 @@ type uint16 = int
type uint32 = int32
module BE : sig
-
val get_uint8 : buf -> int -> uint8
val get_uint16 : buf -> int -> uint16
val get_uint32 : buf -> int -> uint32
+ val get_buffer : buf -> int -> int -> buf
val set_uint8 : buf -> int -> uint8 -> unit
val set_uint16 : buf -> int -> uint16 -> unit
val set_uint32 : buf -> int -> uint32 -> unit
+ val set_buffer : buf -> int -> int -> buf -> unit
+end
+
+module LE : sig
+ val get_uint8 : buf -> int -> uint8
+ val get_uint16 : buf -> int -> uint16
+ val get_uint32 : buf -> int -> uint32
+ val get_buffer : buf -> int -> int -> buf
+ val set_uint8 : buf -> int -> uint8 -> unit
+ val set_uint16 : buf -> int -> uint16 -> unit
+ val set_uint32 : buf -> int -> uint32 -> unit
+ val set_buffer : buf -> int -> int -> buf -> unit
end
val len : buf -> int
val base_offset : buf -> int
val sub : buf -> int -> int -> buf
val split : buf -> int -> buf * buf
+
+val hexdump : buf -> unit
View
88 lib_test/ipv4.ml
@@ -15,53 +15,99 @@
*)
cstruct pcap_header {
- uint32_t magic_number; (* magic number *)
- uint16_t version_major; (* major version number *)
- uint16_t version_minor; (* minor version number *)
- uint32_t thiszone; (* GMT to local correction *)
- uint32_t sigfigs; (* accuracy of timestamps *)
- uint32_t snaplen; (* max length of captured packets, in octets *)
- uint32_t network (* data link type *)
-} as big_endian
-
+ uint32_t magic_number; (* magic number *)
+ uint16_t version_major; (* major version number *)
+ uint16_t version_minor; (* minor version number *)
+ uint32_t thiszone; (* GMT to local correction *)
+ uint32_t sigfigs; (* accuracy of timestamps *)
+ uint32_t snaplen; (* max length of captured packets, in octets *)
+ uint32_t network (* data link type *)
+} as little_endian
cstruct pcap_packet {
uint32_t ts_sec; (* timestamp seconds *)
uint32_t ts_usec; (* timestamp microseconds *)
uint32_t incl_len; (* number of octets of packet saved in file *)
uint32_t orig_len (* actual length of packet *)
+} as little_endian
+
+cstruct ethernet {
+ uint8_t dst[6];
+ uint8_t src[6];
+ uint16_t ethertype
} as big_endian
cstruct ipv4 {
- uint8_t hlen_version;
- uint8_t tos;
- uint16_t len;
- uint16_t id;
- uint16_t off;
- uint8_t ttl;
- uint8_t proto;
- uint16_t csum;
- uint32_t src;
- uint32_t dst
+ uint8_t hlen_version;
+ uint8_t tos;
+ uint16_t len;
+ uint16_t id;
+ uint16_t off;
+ uint8_t ttl;
+ uint8_t proto;
+ uint16_t csum;
+ uint8_t src[4];
+ uint8_t dst[4]
} as big_endian
+cstruct tcpv4 {
+ uint16_t src_port;
+ uint16_t dst_port;
+ uint32_t seqnum;
+ uint32_t acknum;
+ uint16_t offset_flags;
+ uint16_t window;
+ uint16_t checksum;
+ uint16_t urg
+} as big_endian
open Lwt
open Printf
let num_packets = ref 0
+let mac_to_string buf =
+ let i n = Cstruct.BE.get_uint8 buf n in
+ sprintf "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"
+ (i 0) (i 1) (i 2) (i 3) (i 4) (i 5)
+
+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.split 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.split ip sizeof_ipv4 in
+ let off = 0 in
+ let flags = "?" in
+ printf "tcpv4 port %d->%d seq %lu ack %lu win %d off %d flags %s\n"
+ (get_tcpv4_src_port tcp) (get_tcpv4_dst_port tcp) (get_tcpv4_seqnum tcp)
+ (get_tcpv4_acknum tcp) (get_tcpv4_window tcp) off flags;
+ end
+ |_ -> printf "unknown ip proto %d\n" proto
+ end
+ |_ -> printf "unknown body\n"
+
let rec print_pcap_packet buf =
incr num_packets;
let hdr, rest = Cstruct.split buf sizeof_pcap_packet in
- printf "** %lu.%lu bytes %lu (of %lu)\n"
+ printf "\n** %lu.%lu bytes %lu (of %lu)\n"
(get_pcap_packet_ts_sec hdr)
(get_pcap_packet_ts_usec hdr)
(get_pcap_packet_incl_len hdr)
(get_pcap_packet_orig_len hdr);
let plen = Int32.to_int (get_pcap_packet_incl_len hdr) in
let body, rest = Cstruct.split rest plen in
- (* print_pcap_body body; *)
+ print_packet body;
if Cstruct.len rest > 0 then print_pcap_packet rest
let print_pcap_header buf =
View
61 syntax/pa_cstruct.ml
@@ -26,6 +26,7 @@ type ty =
|UInt8
|UInt16
|UInt32
+ |Buffer of int
type field = {
field: string;
@@ -52,25 +53,35 @@ let width_of_field f =
|UInt8 -> 1
|UInt16 -> 2
|UInt32 -> 4
+ |Buffer len -> len
let field_to_string f =
sprintf "%s %s"
(match f.ty with
|UInt8 -> "uint8_t"
|UInt16 -> "uint16_t"
|UInt32 -> "uint32_t"
+ |Buffer len -> sprintf "uint8_t[%d]" len
) f.field
let to_string t =
sprintf "cstruct[%d] %s { %s }" t.len t.name
(String.concat "; " (List.map field_to_string t.fields))
-let create_field field field_type =
+let loc_err _loc err = Loc.raise _loc (Failure err)
+
+let parse_field _loc field field_type sz =
match ty_of_string field_type with
- |None -> None
- |Some ty ->
- let off = 0 in (* XXX *)
- Some { field; ty; off }
+ |None -> loc_err _loc (sprintf "Unknown type %s" field_type)
+ |Some ty -> begin
+ let ty = match ty,sz with
+ |_,None -> ty
+ |UInt8,Some sz -> Buffer (int_of_string sz)
+ |_,Some sz -> loc_err _loc "only uint8_t buffers supported"
+ in
+ let off = -1 in
+ { field; ty; off }
+ end
let create_struct _loc endian name fields =
let endian = match endian with
@@ -95,35 +106,32 @@ let mode_mod _loc =
|Little_endian -> <:expr< Cstruct.LE >>
|Host_endian -> <:expr< Cstruct.HE >>
-let parse_field _loc fname fty =
- match create_field fname fty with
- |Some field -> field
- |None -> Loc.raise _loc (Failure (sprintf "Unknown type %s" fty))
-
let getter_name s f = sprintf "get_%s_%s" s.name f.field
let setter_name s f = sprintf "set_%s_%s" s.name f.field
-let output_get _loc m s f =
- let m = mode_mod _loc m in
- let off = <:expr< $int:string_of_int f.off$ >> in
+let output_get _loc s f =
+ let m = mode_mod _loc s.endian in
+ let num x = <:expr< $int:string_of_int x$ >> in
<:str_item<
let $lid:getter_name s f$ v =
$match f.ty with
- |UInt8 -> <:expr< $m$.get_uint8 v $off$ >>
- |UInt16 -> <:expr< $m$.get_uint16 v $off$ >>
- |UInt32 -> <:expr< $m$.get_uint32 v $off$ >>
+ |UInt8 -> <:expr< $m$.get_uint8 v $num f.off$ >>
+ |UInt16 -> <:expr< $m$.get_uint16 v $num f.off$ >>
+ |UInt32 -> <:expr< $m$.get_uint32 v $num f.off$ >>
+ |Buffer len -> <:expr< $m$.get_buffer v $num f.off$ $num len$ >>
$
>>
-let output_set _loc m s f =
- let m = mode_mod _loc m in
- let off = <:expr< $int:string_of_int f.off$ >> in
+let output_set _loc s f =
+ let m = mode_mod _loc s.endian in
+ let num x = <:expr< $int:string_of_int x$ >> in
<:str_item<
let $lid:setter_name s f$ v x =
$match f.ty with
- |UInt8 -> <:expr< $m$.set_uint8 v $off$ x >>
- |UInt16 -> <:expr< $m$.set_uint16 v $off$ x >>
- |UInt32 -> <:expr< $m$.set_uint32 v $off$ x >>
+ |UInt8 -> <:expr< $m$.set_uint8 v $num f.off$ x >>
+ |UInt16 -> <:expr< $m$.set_uint16 v $num f.off$ x >>
+ |UInt32 -> <:expr< $m$.set_uint32 v $num f.off$ x >>
+ |Buffer len -> <:expr< $m$.set_buffer v $num f.off$ $num len$ x >>
$
>>
@@ -133,14 +141,13 @@ let output_sizeof _loc s =
>>
let output_struct _loc s =
- let m = Big_endian (* TODO *) in
(* Generate functions of the form {get/set}_<struct>_<field> *)
let expr = List.fold_left (fun a f ->
<:str_item<
$a$ ;;
$output_sizeof _loc s$ ;;
- $output_get _loc m s f$ ;;
- $output_set _loc m s f$
+ $output_get _loc s f$ ;;
+ $output_set _loc s f$
>>
) <:str_item< >> s.fields
in
@@ -150,8 +157,8 @@ EXTEND Gram
GLOBAL: str_item;
constr_field: [
- [ fty = LIDENT; fname = LIDENT ->
- parse_field _loc fname fty
+ [ fty = LIDENT; fname = LIDENT; sz = OPT [ "["; sz = INT; "]" -> sz ] ->
+ parse_field _loc fname fty sz
]
];

0 comments on commit d032f0e

Please sign in to comment.