91 lines
3.3 KiB
OCaml
91 lines
3.3 KiB
OCaml
|
|
open Common
|
||
|
|
|
||
|
|
module B = Basic_backend.Make
|
||
|
|
module V = Vnetif.Make(B)
|
||
|
|
module E = Ethernet.Make(V)
|
||
|
|
module Static_arp = Static_arp.Make(E)
|
||
|
|
module Ip = Static_ipv4.Make(E)(Static_arp)
|
||
|
|
module Udp = Udp.Make(Ip)
|
||
|
|
|
||
|
|
type stack = {
|
||
|
|
backend : B.t;
|
||
|
|
netif : V.t;
|
||
|
|
ethif : E.t;
|
||
|
|
arp : Static_arp.t;
|
||
|
|
ip : Ip.t;
|
||
|
|
udp : Udp.t;
|
||
|
|
}
|
||
|
|
|
||
|
|
let get_stack ?(backend = B.create ~use_async_readers:true
|
||
|
|
~yield:(fun() -> Lwt.pause ()) ()) ip =
|
||
|
|
let open Lwt.Infix in
|
||
|
|
let cidr = Ipaddr.V4.Prefix.make 24 ip in
|
||
|
|
V.connect backend >>= fun netif ->
|
||
|
|
E.connect netif >>= fun ethif ->
|
||
|
|
Static_arp.connect ethif >>= fun arp ->
|
||
|
|
Ip.connect ~cidr ethif arp >>= fun ip ->
|
||
|
|
Udp.connect ip >>= fun udp ->
|
||
|
|
Lwt.return { backend; netif; ethif; arp; ip; udp }
|
||
|
|
|
||
|
|
let fails msg f args =
|
||
|
|
match f args with
|
||
|
|
| Ok _ -> Alcotest.fail msg
|
||
|
|
| Error _ -> ()
|
||
|
|
|
||
|
|
let marshal_unmarshal () =
|
||
|
|
let parse = Udp_packet.Unmarshal.of_cstruct in
|
||
|
|
fails "unmarshal a 0-length packet" parse (Cstruct.create 0);
|
||
|
|
fails "unmarshal a too-short packet" parse (Cstruct.create 2);
|
||
|
|
let with_data = Cstruct.create 8 in
|
||
|
|
Cstruct.memset with_data 0;
|
||
|
|
Udp_wire.set_src_port with_data 2000;
|
||
|
|
Udp_wire.set_dst_port with_data 21;
|
||
|
|
Udp_wire.set_length with_data 20;
|
||
|
|
let payload = Cstruct.of_string "abcdefgh1234" in
|
||
|
|
let with_data = Cstruct.concat [with_data; payload] in
|
||
|
|
match Udp_packet.Unmarshal.of_cstruct with_data with
|
||
|
|
| Error s -> Alcotest.fail s
|
||
|
|
| Ok (_header, data) ->
|
||
|
|
Alcotest.(check cstruct) "unmarshalling gives expected data" payload data;
|
||
|
|
Lwt.return_unit
|
||
|
|
|
||
|
|
let write () =
|
||
|
|
let open Lwt.Infix in
|
||
|
|
let dst = Ipaddr.V4.of_string_exn "192.168.4.20" in
|
||
|
|
get_stack dst >>= fun stack ->
|
||
|
|
Static_arp.add_entry stack.arp dst (Macaddr.of_string_exn "00:16:3e:ab:cd:ef");
|
||
|
|
Udp.write ~src_port:1212 ~dst_port:21 ~dst stack.udp (Cstruct.of_string "MGET *") >|= Result.get_ok
|
||
|
|
|
||
|
|
let unmarshal_regression () =
|
||
|
|
let i = Cstruct.create 1016 in
|
||
|
|
Cstruct.memset i 30;
|
||
|
|
Cstruct.set_char i 4 '\x04';
|
||
|
|
Cstruct.set_char i 5 '\x00';
|
||
|
|
Alcotest.(check (result reject pass)) "correctly return error for bad packet"
|
||
|
|
(Error "parse failed") (Udp_packet.Unmarshal.of_cstruct i);
|
||
|
|
Lwt.return_unit
|
||
|
|
|
||
|
|
|
||
|
|
let marshal_marshal () =
|
||
|
|
let error_str = Alcotest.result Alcotest.reject Alcotest.string in
|
||
|
|
let udp = {Udp_packet.src_port = 1; dst_port = 2} in
|
||
|
|
let payload = Cstruct.create 100 in
|
||
|
|
let buffer = Cstruct.create Udp_wire.sizeof_udp in
|
||
|
|
let src = Ipaddr.V4.of_string_exn "127.0.0.1" in
|
||
|
|
let dst = Ipaddr.V4.of_string_exn "127.0.0.1" in
|
||
|
|
let pseudoheader = Ipv4_packet.Marshal.pseudoheader ~src ~dst ~proto:`UDP (Cstruct.length buffer + Cstruct.length payload) in
|
||
|
|
Udp_packet.Marshal.into_cstruct ~pseudoheader ~payload udp (Cstruct.shift buffer 1)
|
||
|
|
|> Alcotest.check error_str "Buffer too short" (Error "Not enough space for a UDP header");
|
||
|
|
Udp_packet.Marshal.into_cstruct ~pseudoheader ~payload udp buffer
|
||
|
|
|> Alcotest.(check (result unit string)) "Buffer big enough for header" (Ok ());
|
||
|
|
Udp_packet.Unmarshal.of_cstruct (Cstruct.concat [buffer; payload])
|
||
|
|
|> Alcotest.(check (result (pair udp_packet cstruct) string)) "Save and reload" (Ok (udp, payload));
|
||
|
|
Lwt.return_unit
|
||
|
|
|
||
|
|
let suite = [
|
||
|
|
"unmarshal regression", `Quick, unmarshal_regression;
|
||
|
|
"marshal/marshal", `Quick, marshal_marshal;
|
||
|
|
"marshal/unmarshal", `Quick, marshal_unmarshal;
|
||
|
|
"write packets", `Quick, write;
|
||
|
|
]
|