Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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

…little_endian module
  • Loading branch information...
commit d032f0ecd5fc634b6c2107c58261edcb2f7ec8ea 1 parent 8a6a370
Anil Madhavapeddy authored
63 lib/cstruct.ml
View
@@ -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,6 +56,10 @@ 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
@@ -57,7 +67,42 @@ module LE = struct
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 ""
16 lib/cstruct.mli
View
@@ -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
88 lib_test/ipv4.ml
View
@@ -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 =
61 syntax/pa_cstruct.ml
View
@@ -26,6 +26,7 @@ type ty =
|UInt8
|UInt16
|UInt32
+ |Buffer of int
type field = {
field: string;
@@ -52,6 +53,7 @@ let width_of_field f =
|UInt8 -> 1
|UInt16 -> 2
|UInt32 -> 4
+ |Buffer len -> len
let field_to_string f =
sprintf "%s %s"
@@ -59,18 +61,27 @@ let field_to_string f =
|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
]
];
Please sign in to comment.
Something went wrong with that request. Please try again.