Skip to content

Commit

Permalink
Add new Ipaddr_cstruct and Macaddr_cstruct libraries
Browse files Browse the repository at this point in the history
for conversion to/from cstructs

based on mirage#36

Co-authored-by: Nicolás Ojeda Bär <[email protected]>
  • Loading branch information
avsm and nojb committed Jul 11, 2019
1 parent e614dc9 commit c303536
Show file tree
Hide file tree
Showing 15 changed files with 341 additions and 9 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ script: bash ./.travis-docker.sh
env:
global:
- PACKAGE="ipaddr"
- PINS="ipaddr:. macaddr:."
- PINS="ipaddr:. macaddr:. ipaddr-sexp:. macaddr-sexp:. ipaddr-cstruct:. macaddr-cstruct:."
matrix:
- DISTRO=debian-stable OCAML_VERSION=4.04
- DISTRO=ubuntu OCAML_VERSION=4.05
Expand Down
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
subpackages and instead have `ipaddr-sexp` and `macaddr-sexp`
to match the opam package names.

* Add new `Ipaddr_cstruct` and `Macaddr_cstruct` libraries
for conversion to/from cstructs (#36 @nojb @avsm)

## v3.1.0 (2019-03-02)

* Do not leak a `Not_found` exception when parsing `[:`
Expand Down
3 changes: 2 additions & 1 deletion dune-project
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
(lang dune 1.0)
(lang dune 1.9)
(name ipaddr)
(allow_approximate_merlin)
24 changes: 24 additions & 0 deletions ipaddr-cstruct.opam
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
opam-version: "2.0"
maintainer: "[email protected]"
authors: ["David Sheets" "Anil Madhavapeddy" "Hugo Heuzard"]
synopsis: "A library for manipulation of IP address representations using Cstructs"
license: "ISC"
tags: ["org:mirage" "org:xapi-project"]
homepage: "https://github.com/mirage/ocaml-ipaddr"
doc: "https://mirage.github.io/ocaml-ipaddr/"
bug-reports: "https://github.com/mirage/ocaml-ipaddr/issues"
depends: [
"ocaml" {>= "4.04.0"}
"dune" {build}
"ipaddr"
"cstruct"
]
build: [
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
dev-repo: "git+https://github.com/mirage/ocaml-ipaddr.git"
description: """
Cstruct convertions for macaddr
"""
3 changes: 2 additions & 1 deletion ipaddr-sexp.opam
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
opam-version: "2.0"
maintainer: "[email protected]"
authors: ["David Sheets" "Anil Madhavapeddy" "Hugo Heuzard"]
synopsis: "A library for manipulation of IP (and MAC) address representations"
synopsis: "A library for manipulation of IP address representations usnig sexp"
description: """
Sexp convertions for ipaddr
"""
Expand All @@ -15,6 +15,7 @@ depends: [
"ocaml" {>= "4.04.0"}
"dune" {build}
"ipaddr"
"ipaddr-cstruct" {with-test}
"ounit" {with-test}
"ppx_sexp_conv" {>= "v0.9.0"}
]
Expand Down
12 changes: 12 additions & 0 deletions lib/dune
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@
(modules ipaddr_unix)
(libraries unix ipaddr))

(library
(name ipaddr_cstruct)
(public_name ipaddr-cstruct)
(modules ipaddr_cstruct)
(libraries ipaddr cstruct))

(library
(name macaddr_cstruct)
(public_name macaddr-cstruct)
(modules macaddr_cstruct)
(libraries macaddr cstruct))

(library
(name ipaddr_top)
(public_name ipaddr.top)
Expand Down
76 changes: 76 additions & 0 deletions lib/ipaddr_cstruct.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
(*
* Copyright (c) 2019 Anil Madhavapeddy
* Copyright (c) 2014 Nicolás Ojeda Bär
*
* 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.
*
*)

let need_more x = Ipaddr.Parse_error ("not enough data", x)

let try_with_result fn a =
try Ok (fn a)
with Ipaddr.Parse_error (msg, _) -> Error (`Msg ("Ipaddr: " ^ msg))

module V4 = struct

let of_cstruct_exn cs =
let len = Cstruct.len cs in
if len < 4 then raise (need_more (Cstruct.to_string cs));
Ipaddr.V4.of_int32 (Cstruct.BE.get_uint32 cs 0)

let of_cstruct cs =
try_with_result of_cstruct_exn cs

let write_cstruct_exn i cs =
let len = Cstruct.len cs in
if len < 4 then raise (need_more (Cstruct.to_string cs));
Cstruct.BE.set_uint32 cs 0 (Ipaddr.V4.to_int32 i)

let to_cstruct ?(allocator = Cstruct.create) i =
let cs = allocator 4 in
write_cstruct_exn i cs;
cs

end

module V6 = struct

open Ipaddr.V6

let of_cstruct_exn cs =
let len = Cstruct.len cs in
if len < 16 then raise (need_more (Cstruct.to_string cs));
let hihi = Cstruct.BE.get_uint32 cs 0 in
let hilo = Cstruct.BE.get_uint32 cs 4 in
let lohi = Cstruct.BE.get_uint32 cs 8 in
let lolo = Cstruct.BE.get_uint32 cs 12 in
of_int32 (hihi, hilo, lohi, lolo)

let of_cstruct cs =
try_with_result of_cstruct_exn cs

let write_cstruct_exn i cs =
let len = Cstruct.len cs in
if len < 16 then raise (need_more (Cstruct.to_string cs));
let a, b, c, d = to_int32 i in
Cstruct.BE.set_uint32 cs 0 a;
Cstruct.BE.set_uint32 cs 4 b;
Cstruct.BE.set_uint32 cs 8 c;
Cstruct.BE.set_uint32 cs 12 d

let to_cstruct ?(allocator = Cstruct.create) i =
let cs = allocator 16 in
write_cstruct_exn i cs;
cs
end
61 changes: 61 additions & 0 deletions lib/ipaddr_cstruct.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
(*
* Copyright (c) 2019 Anil Madhavapeddy
* Copyright (c) 2014 Nicolás Ojeda Bär
*
* 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.
*
*)

(** Convert to and from Cstructs and IP addresses *)

(** Ipv4 address conversions *)
module V4 : sig

(** [of_cstruct c] parses the first 4 octets of [c] into an IPv4 address. *)
val of_cstruct : Cstruct.t -> (Ipaddr.V4.t, [> `Msg of string ]) result

(** [of_cstruct_exn] parses the first 4 octets of [c] into an IPv4 address.
Raises {!Ipaddr.Parse_failure} on error. *)
val of_cstruct_exn : Cstruct.t -> Ipaddr.V4.t

(** [to_cstruct ipv4] is a cstruct of length 4 encoding [ipv4].
The cstruct is allocated using [allocator]. If [allocator] is
not provided, [Cstruct.create] is used. *)
val to_cstruct: ?allocator:(int -> Cstruct.t) -> Ipaddr.V4.t -> Cstruct.t

(** [write_cstruct_exn ipv4 cs] writes 4 bytes into [cs] representing
the [ipv4] address octets. Raises {!Ipaddr.Parse_error} if [cs]
is not at least 4 bytes long. *)
val write_cstruct_exn : Ipaddr.V4.t -> Cstruct.t -> unit
end

(** Ipv6 address conversions *)
module V6 : sig

(** [of_cstruct c] parses the first 16 octets of [c] into an IPv6 address. *)
val of_cstruct : Cstruct.t -> (Ipaddr.V6.t, [> `Msg of string ]) result

(** [of_cstruct_exn] parses the first 16 octets of [c] into an IPv6 address.
Raises {!Ipaddr.Parse_failure} on error. *)
val of_cstruct_exn : Cstruct.t -> Ipaddr.V6.t

(** [to_cstruct ipv6] is a cstruct of length 16 encoding [ipv6].
The cstruct is allocated using [allocator]. If [allocator] is
not provided, [Cstruct.create] is used. *)
val to_cstruct: ?allocator:(int -> Cstruct.t) -> Ipaddr.V6.t -> Cstruct.t

(** [write_cstruct_exn ipv6 cs] writes 16 bytes into [cs] representing
the [ipv6] address octets. Raises {!Ipaddr.Parse_error} if [cs]
is not at least 16 bytes long. *)
val write_cstruct_exn : Ipaddr.V6.t -> Cstruct.t -> unit
end
40 changes: 40 additions & 0 deletions lib/macaddr_cstruct.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
(*
* Copyright (c) 2019 Anil Madhavapeddy
* Copyright (c) 2014 Nicolás Ojeda Bär
*
* 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.
*
*)

let try_with_result fn a =
try Ok (fn a)
with Macaddr.Parse_error (msg, _) -> Error (`Msg ("Macaddr: " ^ msg))

let of_cstruct_exn cs =
if Cstruct.len cs <> 6
then raise (Macaddr.Parse_error ("MAC is exactly 6 bytes", Cstruct.to_string cs))
else Cstruct.to_string cs |> Macaddr.of_octets_exn

let of_cstruct cs =
try_with_result of_cstruct_exn cs

let write_cstruct_exn (mac:Macaddr.t) cs =
let len = Cstruct.len cs in
let mac = Macaddr.to_octets mac in
if len <> 6 then raise (Macaddr.Parse_error ("MAC is exactly 6 bytes", mac));
Cstruct.blit_from_string mac 0 cs 0 6

let to_cstruct ?(allocator = Cstruct.create) mac =
let cs = allocator 6 in
write_cstruct_exn mac cs;
cs
36 changes: 36 additions & 0 deletions lib/macaddr_cstruct.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
(*
* Copyright (c) 2019 Anil Madhavapeddy
* Copyright (c) 2014 Nicolás Ojeda Bär
*
* 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.
*
*)

(** Convert to and from Cstructs and MAC address. *)

(** [of_cstruct c] parses the 6 octets of [c] into a MAC address. *)
val of_cstruct : Cstruct.t -> (Macaddr.t, [> `Msg of string ]) result

(** [of_cstruct_exn] parses the 6 octets of [c] into a MAC address.
Raises {!Macaddr.Parse_failure} on error. *)
val of_cstruct_exn : Cstruct.t -> Macaddr.t

(** [to_cstruct mac] is a cstruct of length 4 encoding [ipv4].
The cstruct is allocated using [allocator]. If [allocator] is
not provided, [Cstruct.create] is used. *)
val to_cstruct: ?allocator:(int -> Cstruct.t) -> Macaddr.t -> Cstruct.t

(** [write_cstruct_exn mac cs] writes 6 bytes into [cs] representing
the [mac] address octets. Raises {!Macaddr.Parse_error} if [cs]
is not 6 bytes long. *)
val write_cstruct_exn : Macaddr.t -> Cstruct.t -> unit
10 changes: 5 additions & 5 deletions lib_test/dune
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@

(test
(name test_ipaddr)
(package ipaddr)
(package ipaddr-sexp)
(modules test_ipaddr)
(libraries ipaddr test_ipaddr_sexp oUnit))
(libraries ipaddr ipaddr-cstruct test_ipaddr_sexp oUnit))

(test
(name test_macaddr)
(package macaddr)
(package macaddr-sexp)
(modules test_macaddr)
(libraries macaddr test_macaddr_sexp oUnit))
(libraries macaddr macaddr-cstruct test_macaddr_sexp oUnit))

(test
(name test_ppx)
(modules test_ppx)
(package ipaddr)
(package ipaddr-sexp)
(libraries ipaddr macaddr test_ipaddr_sexp test_macaddr_sexp oUnit))
34 changes: 34 additions & 0 deletions lib_test/test_ipaddr.ml
Original file line number Diff line number Diff line change
Expand Up @@ -290,13 +290,29 @@ module Test_v4 = struct
(V4.to_domain_name ip) name ;
assert_equal ~msg:"of_domain_name" (V4.of_domain_name name) (Some ip)

let test_cstruct_rt () =
let addr = "\254\099\003\128" in
assert_equal ~msg:(String.escaped addr)
(Cstruct.to_string Ipaddr_cstruct.V4.(to_cstruct (of_cstruct_exn (Cstruct.of_string addr)))) addr

let test_cstruct_rt_bad () =
let addrs = [
need_more "\254\099\003";
] in
List.iter (fun (addr,exn) ->
assert_raises ~msg:(String.escaped addr) exn
(fun () -> Ipaddr_cstruct.V4.of_cstruct_exn (Cstruct.of_string addr))
) addrs

let suite = "Test V4" >::: [
"string_rt" >:: test_string_rt;
"string_rt_bad" >:: test_string_rt_bad;
"string_raw_rt" >:: test_string_raw_rt;
"string_raw_rt_bad" >:: test_string_raw_rt_bad;
"bytes_rt" >:: test_bytes_rt;
"bytes_rt_bad" >:: test_bytes_rt_bad;
"cstruct_rt" >:: test_cstruct_rt;
"cstruct_rt_bad" >:: test_cstruct_rt_bad;
"int32_rt" >:: test_int32_rt;
"prefix_string_rt" >:: test_prefix_string_rt;
"prefix_string_rt_bad" >:: test_prefix_string_rt_bad;
Expand Down Expand Up @@ -415,6 +431,22 @@ module Test_v6 = struct
(fun () -> V6.of_octets_exn addr)
) addrs

let test_cstruct_rt () =
let addr =
"\000\000\000\000\000\000\000\000\000\000\255\255\192\168\000\001"
in
let v6 = Ipaddr_cstruct.V6.of_cstruct_exn (Cstruct.of_string addr) in
assert_equal ~msg:(String.escaped addr) (Cstruct.to_string Ipaddr_cstruct.V6.(to_cstruct v6)) addr

let test_cstruct_rt_bad () =
let addrs = [
need_more "\000\000\000\000\000\000\000\000\000\000\255\255\192\168\001";
] in
List.iter (fun (addr,exn) ->
assert_raises ~msg:(String.escaped addr) exn
(fun () -> Ipaddr_cstruct.V6.of_cstruct_exn (Cstruct.of_string addr))
) addrs

let test_int32_rt () =
let (a,b,c,d) as addr =
0x2001_0665_l, 0x0000_0000_l, 0xff00_00ff_l, 0xfe00_0001_l
Expand Down Expand Up @@ -622,6 +654,8 @@ module Test_v6 = struct
"string_raw_rt_bad" >:: test_string_raw_rt_bad;
"bytes_rt" >:: test_bytes_rt;
"bytes_rt_bad" >:: test_bytes_rt_bad;
"cstruct_rt" >:: test_cstruct_rt;
"cstruct_rt_bad" >:: test_cstruct_rt_bad;
"int32_rt" >:: test_int32_rt;
"prefix_string_rt" >:: test_prefix_string_rt;
"prefix_string_rt_bad" >:: test_prefix_string_rt_bad;
Expand Down
Loading

0 comments on commit c303536

Please sign in to comment.