···11+## v5.6.1 (2025-08-01)
22+33+* Add Ipaddr.Prefix.bits (#125 @psafont)
44+55+## v5.6.0 (2024-05-22)
66+77+* Add host and subnet Seq.t iterators for Ipaddr.V4.prefix, Ipaddr.V6.Prefix
88+ and Ipaddr.Prefix (#107 @verbosemode @dinosaure)
99+* Ipaddr.V4.compare: use Int32.unsigned_compare, as provided since OCaml 4.08
1010+ (#118 @reynir)
1111+* Ipaddr.V6.t is a string, not a byte vector anymore (so it is immutable)
1212+ (#119 @reynir, restoring 4.08 compatibility #121)
1313+* Provide Ipaddr.Prefix.address (since 5.0.0, Ipaddr.V4.Prefix.address and
1414+ Ipaddr.V6.Prefix.address have been provided, but Ipaddr.Prefix.address was
1515+ forgotten) (#122 @hannesm)
1616+* Fix further docstrings (#123, fixes #81, @hannesm @reynir)
1717+1818+## v5.5.0 (2023-03-31)
1919+2020+* add `Ipaddr` `of_octet` functions (#117, @ryangibb).
2121+2222+## v5.4.0 (2023-03-13)
2323+2424+* Use Bytes.t for IPv6 addresses (#115 @verbosemode, fixes #16 @dsheets)
2525+* Also fixes `V6.to_int64` (reported by @RyanGibb in #113)
2626+2727+## v5.3.1 (2022-07-04)
2828+2929+* Remove stdlib-shims dependency, require OCaml 4.08+ (@hannesm, #112)
3030+* Switch to ounit2 (@Alessandro-Barbieri, #111)
3131+3232+## v5.3.0 (2022-03-04)
3333+3434+* Add `with_port_of_string` function (@dinosaure, @hannesm, #108)
3535+* **breaking-change** Be restrictive on `Ipaddr.of_string` (@dinosaure, @hannesm, #109)
3636+ Before this release, `Ipaddr.of_string` accepts remaining bytes and returns
3737+ a valid value such as `"127.0.0.1aaaa"` is valid. Now, `ipaddr` does not
3838+ accept a string with remaining bytes.
3939+4040+## v5.2.0 (2021-09-11)
4141+4242+* Use Cstruct.length instead of deprecated Cstruct.len (#106, @hannesm)
4343+* Provide instantiated functors Set, Map, V4.Set, V4.Map, V6.Set, V6.Map
4444+ (#106, @hannesm)
4545+4646+## v5.1.0 (2021-06-08)
4747+4848+* Reject octal notation in IPv4 (cve-2021-29921, #104, @jsachs)
4949+* CI fixes, upgrade to ocamlformat 0.18 (@hannesm)
5050+5151+## v5.0.1 (2020-09-30)
5252+5353+* Fix V4.Prefix.broadcast and last with /32 prefixes (#102 @verbosemode)
5454+5555+## v5.0.0 (2020-06-16)
5656+5757+* Do not zero out the non-prefix-length part of the address in
5858+ `{V4,V6}.Prefix.t` (#99 @hannesm)
5959+ Removed `{V4,V6}.Prefix.of_address_string{,_exn}` and
6060+ `{V4,V6}.Prefix.to_address_{string.buffer}`
6161+6262+ To port code:
6363+ - if you rely on `Prefix.of_string` to zero out the non-prefix-length address
6464+ bits, call `Prefix.prefix : t -> t` subsequently.
6565+ - `Prefix.of_address_string{,_exn}` can be replaced by
6666+ `Prefix.of_string{,_exn}`, to retrieve the address use
6767+ `Prefix.address : t -> addr`.
6868+ - The `Prefix.to_address_{string,buffer}` can be replaced by
6969+ `Prefix.to_{string,buffer}`, where `Prefix.t` already contains the IP
7070+ address to be printed.
7171+ - Instead of passing `{V4,V6}.t * {V4,V6}.Prefix.t` for an
7272+ address and subnet configuration, `{V4,V6}.Prefix.t` is sufficient.
7373+7474+* Implement `{V4,V6,}.succ`, `{V4,V6,}.pred`, `{V4,V6}.Prefix.first`, and
7575+ `{V4,V6}.Prefix.last` functions (#94 @NightBlues)
7676+7777+* Rename `Prefix.of_netmask` to `Prefix.of_netmask_exn` with labelled
7878+ arguments (~netmask and ~address), provide `Prefix.of_netmask` which returns
7979+ a (t, [> `Msg of string ]) result value (#95 @hannesm)
8080+8181+* Fix undefined behaviour of `V4.Prefix.mem` with a CIDR with prefix length 0
8282+ (#98 @verbosemode)
8383+8484+* Use stdlib-shims to prevent deprecation warnings on OCaml 4.08
8585+ (@avsm)
8686+8787+* Remove unnecessary "sexplib0" dependency (#95 @hannesm)
8888+8989+* Remove "{build}" directive from "dune" dependency (#93 @CraigFe)
9090+9191+## v4.0.0 (2019-07-12)
9292+9393+* Rename the `to/from_bytes` functions to refer to `octets`
9494+ instead. This distinguishes the meaning of human-readable
9595+ addresses (`string`s in this library) and byte-packed
9696+ representations(`octet`s in this library) from the OCaml
9797+ `bytes` type that represents mutable strings.
9898+9999+ Porting code should just be a matter of renaming functions
100100+ such as:
101101+ - `Ipaddr.of_bytes` becomes `Ipaddr.of_octets`
102102+ - `Macaddr.to_bytes` becomes `Macaddr.to_octets`
103103+104104+* Introduce new `write_octets` functions that can write
105105+ octet representations of IPv4/v6 into an existing bytestring.
106106+107107+* Use the `domain-name` library to produce domain names
108108+ from IP addresses.
109109+110110+* Remove the `ipaddr.sexp` and `macaddr.sexp` ocamlfind
111111+ subpackages and instead have `ipaddr-sexp` and `macaddr-sexp`
112112+ to match the opam package names.
113113+114114+* Add new `Ipaddr_cstruct` and `Macaddr_cstruct` libraries
115115+ for conversion to/from cstructs (#36 @nojb @avsm)
116116+117117+## v3.1.0 (2019-03-02)
118118+119119+* Do not leak a `Not_found` exception when parsing `[:`
120120+ in IPv6 and instead raise `Parse_error` as other errors
121121+ do (found by fuzz testing in #84 by @dinosaure)
122122+* Install automatic toplevel printers for the Ipaddr
123123+ types via `[@@ocaml.toplevel_printer]`. This enables
124124+ utop to automatically install the printers (@avsm)
125125+126126+## 3.0.0 (2019-01-02)
127127+128128+This release features several backwards incompatible changes,
129129+but ones that should increase the portability and robustness
130130+of the library.
131131+132132+* Remove the sexp serialisers from the main interface in favour
133133+ of `pp` functions. Use the `Ipaddr_sexp` module if you still
134134+ need a sexp serialiser.
135135+136136+ To use these with ppx-based derivers, simply replace the
137137+ reference to the `Ipaddr` type definition with `Ipaddr_sexp`.
138138+ That will import the sexp-conversion functions, and the actual
139139+ type definitions are simply aliases to the corresponding type
140140+ within `Ipaddr`. For example, you might do:
141141+142142+ ```
143143+ type t = {
144144+ ip: Ipaddr_sexp.t;
145145+ mac: Macaddr_sexp.t;
146146+ } [@@deriving sexp]
147147+ ```
148148+149149+ The actual types of the records will be aliases to the main
150150+ library types, and there will be two new functions available
151151+ as converters. The signature after ppx has run will be:
152152+153153+ ```
154154+ type t = {
155155+ ip: Ipaddr.t;
156156+ mac: Macaddr.t;
157157+ }
158158+ val sexp_of_t : t -> Sexplib0.t
159159+ val t_of_sexp : Sexplib0.t -> t
160160+ ```
161161+162162+* Break out the `Macaddr` module into a separate opam package so
163163+ that the `Ipaddr` module can be wrapped. Use the `macaddr`
164164+ opam library now if you need just the MAC address functionality.
165165+166166+* Replace all the `of_string/bytes` functions that formerly returned
167167+ option types with the `Rresult` result types instead. This stops
168168+ the cause of the exception from being swallowed, and the error
169169+ message in the new functions can be displayed usefully.
170170+171171+* In the `Ipaddr.V6.to_string` and `to_buffer` functions, remove the
172172+ optional labelled argument `v4` and always output v4-mapped strings
173173+ as recommended by RFC5952. (#80 by @hannesm).
174174+175175+* Remove `pp_hum` which was deprecated in 2.9.0.
176176+177177+* Sexplib0 is now used which is more lightweight tha the full
178178+ Sexplib library. Minimum OCaml version is now 4.04.0+ as a result
179179+ of this dependency.
180180+181181+* Improvements to the ocamldoc formatting strings for better
182182+ layout and odoc compatibility.
183183+184184+## 2.9.0 (2018-12-11)
185185+186186+* Add `pp` functions for prettyprinting and deprecate `pp_hum` variants.
187187+ The two functions are currently the same, so porting is just a matter
188188+ of replacing existing uses of `pp_hum` with `pp` (#71 @verbosemode)
189189+* Fix deprecation warnings on newer OCaml standard libraries (#74 @cfcs).
190190+* Fix `base-unix` depopt to be a real dependency (#68 @rgrinberg).
191191+* Fix missing `sexplib` dependency (#66 #67 @bmillwood).
192192+* Port to Dune from jbuilder and update opam metadata to 2.0 format (#76 @avsm).
193193+* Remove unused variable and bindings warnings in the implementation and
194194+ signatures (#76 @avsm)
195195+* Fix toplevel handling of the `ipaddr.top` package by linking
196196+ to compiler-libs instead of compiler-libs.toplevel (#76 @avsm based on
197197+ fix in mirage/ocaml-uri#130 by @yallop)
198198+* Update Travis to test latest distros by using their aliases (#76 @avsm)
199199+* Upgrade opam metadata to the 2.0 format (#76 @avsm)
200200+201201+## 2.8.0 (2017-06-01)
202202+203203+* Port to Jbuilder (#65 @vbmithr @avsm).
204204+ There should be no observable changes, except that `Ipaddr_unix` is now
205205+ in a separate subdirectory. This means that packages that implicitly
206206+ depended on the module without including the ocamlfind `ipaddr.unix`
207207+ package may now fail. Just adding the ocamlfind dependency will fix it,
208208+ and is backwards compatible with older Ipaddr releases.
209209+* Minimum version of OCaml required is now 4.03.0 (formerly was 4.02.2),
210210+ due to the use of recent `ppx_sexp_conv` with Jbuilder also having that
211211+ as the minimum supported compiler version.
212212+213213+## 2.7.2 (2017-02-16)
214214+215215+* Fix a missing findlib toploop package (#61 from Vincent Bernardoff)
216216+217217+## 2.7.1 (2016-11-16)
218218+219219+* Use topkg for build (#60 from Jochen Bartl)
220220+221221+## 2.7.0 (2016-02-14)
222222+223223+* Remove `sexplib.syntax`, `type_conv` deps and camlp4 transitive dependency
224224+* Add `ppx_sexp_conv` dependency
225225+* Require OCaml 4.02.2+
226226+* Add `Ipaddr.Prefix.subset`, `Ipaddr.V4.Prefix.subset` and `Ipaddr.V6.subset`
227227+ predicates to test containment of subnets (#52 from @seliopou)
228228+229229+## 2.6.1 (2015-02-20)
230230+231231+* Fix findlib requires in oasis to restore pre-4.02.1 compatibility
232232+233233+## 2.6.0 (2015-02-19)
234234+235235+* Change IPv6 link-local address prefix from fe80::/10 to fe80::/64. (#39)
236236+* Remove type bytes = string alias (potentially breaking)
237237+* Turn on -safe-string (#41)
238238+* {V4,V6}.`to_bytes_raw` now uses Bytes.t rather than string (potentially breaking)
239239+* Add multicast MAC conversions from RFC 1112 and RFC 2464
240240+* Add `to_domain_name` conversions to DNS label lists (in-addr.arpa and ip6.arpa)
241241+* Add `V6.interface_routers`, `V6.site_routers`, and `V6.Prefix.solicited_node`
242242+* Add `V6.link_address_of_mac` to convert a MAC into a link local IP address
243243+244244+## 2.5.0 (2014-05-27)
245245+246246+* Add `with sexp` (de)serializers to all of the Ipaddr and Macaddr types. (#31)
247247+248248+## 2.4.0 (2014-02-11)
249249+250250+* Add `Ipaddr.V6.Prefix.of_netmask` for conversion from an IPv6
251251+ address/netmask to prefix (useful for some binary interfaces). See #27.
252252+* Add `Ipaddr.V6.Prefix.netmask` to generate a netmask address from a
253253+ prefix (useful for some binary interfaces). See #27.
254254+* Add `Ipaddr.Prefix.network` for generic prefix -> address conversion
255255+* Add `Ipaddr.Prefix.netmask` for generic prefix -> netmask conversion
256256+257257+## 2.3.0 (2014-02-05)
258258+259259+* Add `Ipaddr.V4.Prefix.of_netmask` for conversion from an
260260+ address/netmask to prefix
261261+* Add `Ipaddr.V4.Prefix.netmask` to generate a netmask address from a prefix
262262+263263+## 2.2.0 (2014-01-27)
264264+265265+* Add an [Ipaddr_unix] module to convert to-and-from the standard library.
266266+* Add a toplevel pretty printer in the `ipaddr.top` package.
267267+268268+## 2.1.0 (2014-01-20)
269269+270270+* Add `of_string_raw` to `Ipaddr.V4.Prefix` and `Ipaddr.V6.Prefix`
271271+* Add `of_addr` to `Ipaddr.V4.Prefix` and `Ipaddr.V6.Prefix`
272272+* Add type `('v4,'v6) v4v6` to `Ipaddr` to represent version disjuncts
273273+* Add `Ipaddr.Prefix` module for generic prefix manipulation
274274+275275+## 2.0.0 (2014-01-17)
276276+277277+* Change `Ipaddr.V4.make` to accept `int` rather than `int32` (breaking)
278278+* Add IPv6 support
279279+* Add generic IP address support
280280+* Add type `scope` for classifying address scopes
281281+* Add `Ipaddr.V4.of_string_raw` for parsing inside of larger strings
282282+* Add `Ipaddr.V4.to_int16` and `Ipaddr.V4.of_int16`
283283+* Add `unspecified`, `nodes`, and `routers` constants to `Ipaddr.V4`
284284+* Add `Ipaddr.V4.Prefix.network_address` to put an address into a subnet
285285+* Add `of_address_string_exn`, `of_address_string`, `to_address_string`,
286286+ `to_address_buffer` to `Ipaddr.V4.Prefix` to parse/print combined addr/prefix
287287+* Add `multicast_org`, `multicast_admin`, `multicast_link` subnet constants to
288288+ `Ipaddr.V4.Prefix`
289289+* Add `Ipaddr.V4.scope` to classify IPv4 addresses
290290+* Add `Ipaddr.V4.is_global` and `Ipaddr.V4.is_multicast` predicates
291291+* Add optional `sep:char` argument to `Macaddr.to_string`
292292+* Remove internal use of Scanf.scanf
293293+294294+## 1.0.0 (2013-10-16)
295295+296296+* Add Travis-CI testing scripts.
297297+* Include debug symbols and annot files by default.
298298+299299+## 0.2.3 (2013-09-20)
300300+301301+* Add `Ipaddr.V4.Prefix.bits` function to produce bits of prefix from prefix.
302302+303303+## 0.2.2 (2013-08-07)
304304+305305+* Add `Macaddr.make_local` function to create local unicast MAC
306306+ addresses from an octet generation function.
307307+* Add `Macaddr.get_oui` accessor to extract the Organizationally Unique
308308+ Identifier as an integer.
309309+* Add `Macaddr.is_local` predicate to test for a locally administered address.
310310+* Add `Macaddr.is_unicast` predicate to test for a unicast MAC address.
311311+312312+## 0.2.1 (2013-08-01)
313313+* Add `Ipaddr.V4.any`, `Ipaddr.V4.broadcast`, `Ipaddr.V4.localhost`
314314+ special constant addresses.
315315+* Add `Ipaddr.V4.Prefix.global` (0.0.0.0/0) subnet constant.
316316+* Add `Ipaddr.V4.Prefix.network` function to produce subnet address from prefix.
317317+318318+## 0.2.0 (2013-08-01)
319319+* Add `Macaddr` module for handling MAC-48 (Ethernet) addresses.
320320+* `Ipaddr.Parse_error` now contains both the error condition and the
321321+ failing input.
322322+* Add ocamldoc-compatible comments on all interfaces.
323323+324324+## 0.1.1 (2013-07-31)
325325+* Add loopback and link local addresses to the private blocks.
326326+* Fix build system so Makefile is generated by OASIS.
327327+328328+## 0.1.0 (2013-07-24)
329329+* Initial public release.
330330+* Includes IPv4 and IPv4 CIDR prefix support.
+16
vendor/opam/ipaddr/LICENSE.md
···11+ISC License
22+33+Copyright (c) 2013-2015 David Sheets <sheets@alum.mit.edu>
44+Copyright (c) 2010-2011, 2014 Anil Madhavapeddy <anil@recoil.org>
55+66+Permission to use, copy, modify, and distribute this software for any
77+purpose with or without fee is hereby granted, provided that the above
88+copyright notice and this permission notice appear in all copies.
99+1010+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1111+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1212+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1313+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1414+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1515+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1616+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
···11+# ipaddr: IP and MAC address manipulation
22+33+A library for manipulation of IP and MAC address representations.
44+55+Features:
66+77+ * ounit2-based tests
88+ * IPv4 and IPv6 support
99+ * IPv4 and IPv6 CIDR prefix support
1010+ * IPv4 and IPv6 [CIDR-scoped address](http://tools.ietf.org/html/rfc4291#section-2.3) support
1111+ * `Ipaddr.V4` and `Ipaddr.V4.Prefix` modules are `Map.OrderedType`
1212+ * `Ipaddr.V6` and `Ipaddr.V6.Prefix` modules are `Map.OrderedType`
1313+ * `Ipaddr` and `Ipaddr.Prefix` modules are `Map.OrderedType`
1414+ * `Ipaddr_unix` in findlib subpackage `ipaddr.unix` provides compatibility with the standard library `Unix` module
1515+ * `Ipaddr_top` in findlib subpackage `ipaddr.top` provides top-level pretty printers
1616+ * IP address scope classification
1717+ * IPv4-mapped addresses in IPv6 (::ffff:0:0/96) are an embedding of IPv4
1818+ * MAC-48 (Ethernet) address support
1919+ * `Macaddr` is a `Map.OrderedType`
2020+ * All types have sexplib serializers/deserializers optionally via the `Ipaddr_sexp` and `Macaddr_sexp` libraries.
2121+2222+## Usage
2323+2424+There are the following opam packages included:
2525+2626+- `ipaddr`: the `Ipaddr` and associated modules
2727+- `ipaddr-sexp`
2828+- `ipaddr-cstruct`
2929+- `macaddr`: the `Macaddr` and associated modules.
3030+- `macaddr-sexp`
3131+- `macaddr-cstruct`
3232+3333+There are the following ocamlfind libraries included as part of this
3434+repository, included as part of the respective opam packages.
3535+3636+- `ipaddr`: The `Ipaddr` module for IPv4/6 manipulation.
3737+- `ipaddr.top`: Toplevel printers for Ipaddr.
3838+- `ipaddr-cstruct`: The `Ipaddr_cstruct` module
3939+- `macaddr`: The `Macaddr` module for MAC address manipulation.
4040+- `macaddr.top`: Toplevel printers for Macaddr.
4141+- `macaddr-cstruct`: The `Macaddr_cstruct` module
4242+- `ipaddr-sexp`: S-expression converters for Ipaddr.
4343+- `macaddr-sexp`: S-expression converters for Macaddr.
4444+4545+## Installation and development
4646+4747+The packages are released to the opam-repository. An `opam install ipaddr`
4848+(or any other above mentioned package) will install it. If you want to install
4949+the latest development commit, `opam pin add ipaddr --dev` will do this.
5050+5151+A local build, after a `git clone` can be done with `dune build`, a
5252+`dune runtest` compiles and executes the testsuite. If dependencies are missing,
5353+`opam install (-t) --deps-only .` in the cloned directory will install them.
5454+5555+The auto-formatter [`ocamlformat`](https://github.com/ocaml-ppx/ocamlformat) is
5656+used, please execute `dune build @fmt --auto-promote` before submitting a pull
5757+request.
5858+5959+## Contact
6060+6161+- Issues: <https://github.com/mirage/ocaml-ipaddr/issues>
6262+- E-mail: <mirageos-devel@lists.xenproject.org>
6363+- API Documentation: <http://docs.mirage.io/ipaddr/>
6464+- Discussion: <https://discuss.ocaml.org> with the `mirageos` tag.
···11+(*
22+ * Copyright (c) 2013-2015 David Sheets <sheets@alum.mit.edu>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ *
1616+ *)
1717+1818+exception Parse_error of string * string
1919+2020+type scope = Point | Interface | Link | Admin | Site | Organization | Global
2121+2222+let try_with_result fn a =
2323+ try Ok (fn a) with Parse_error (msg, _) -> Error (`Msg ("Ipaddr: " ^ msg))
2424+2525+let failwith_msg = function Ok x -> x | Error (`Msg m) -> failwith m
2626+2727+let string_of_scope = function
2828+ | Point -> "point"
2929+ | Interface -> "interface"
3030+ | Link -> "link"
3131+ | Admin -> "admin"
3232+ | Site -> "site"
3333+ | Organization -> "organization"
3434+ | Global -> "global"
3535+3636+let scope_of_string = function
3737+ | "point" -> Ok Point
3838+ | "interface" -> Ok Interface
3939+ | "link" -> Ok Link
4040+ | "admin" -> Ok Admin
4141+ | "site" -> Ok Site
4242+ | "organization" -> Ok Organization
4343+ | "global" -> Ok Global
4444+ | s -> Error (`Msg ("unknown scope: " ^ s))
4545+4646+let pp_scope fmt s = Format.pp_print_string fmt (string_of_scope s)
4747+let ( ~| ) = Int32.of_int
4848+let ( |~ ) = Int32.to_int
4949+let ( &&& ) x y = Int32.logand x y
5050+let ( ||| ) x y = Int32.logor x y
5151+let ( <|< ) x y = Int32.shift_left x y
5252+let ( >|> ) x y = Int32.shift_right_logical x y
5353+let ( >! ) x y = x >|> y &&& 0xFF_l
5454+let ( <! ) x y = x &&& 0xFF_l <|< y
5555+let need_more x = Parse_error ("not enough data", x)
5656+let char_0 = int_of_char '0'
5757+let char_a = int_of_char 'a'
5858+let char_A = int_of_char 'A'
5959+6060+let int_of_char c =
6161+ match c with
6262+ | '0' .. '9' -> Stdlib.int_of_char c - char_0
6363+ | 'a' .. 'f' -> 10 + Stdlib.int_of_char c - char_a
6464+ | 'A' .. 'F' -> 10 + Stdlib.int_of_char c - char_A
6565+ | _ -> -1
6666+6767+let bad_char i s =
6868+ let msg = Printf.sprintf "invalid character '%c' at %d" s.[i] i in
6969+ Parse_error (msg, s)
7070+7171+let octal_notation s =
7272+ let msg = Printf.sprintf "octal notation disallowed" in
7373+ Parse_error (msg, s)
7474+7575+let is_number base n = n >= 0 && n < base
7676+7777+let parse_int base s i =
7878+ let len = String.length s in
7979+ let rec next prev =
8080+ let j = !i in
8181+ if j >= len then prev
8282+ else
8383+ let c = s.[j] in
8484+ let k = int_of_char c in
8585+ if is_number base k then (
8686+ incr i;
8787+ next ((prev * base) + k))
8888+ else prev
8989+ in
9090+ let i = !i in
9191+ if i < len then
9292+ if is_number base (int_of_char s.[i]) then next 0 else raise (bad_char i s)
9393+ else raise (need_more s)
9494+9595+let parse_dec_int s i = parse_int 10 s i
9696+let parse_hex_int s i = parse_int 16 s i
9797+9898+let expect_char s i c =
9999+ if !i < String.length s then
100100+ if s.[!i] <> c then raise (bad_char !i s) else incr i
101101+ else raise (need_more s)
102102+103103+let expect_end s i = if String.length s <= !i then () else raise (bad_char !i s)
104104+105105+let reject_octal s i =
106106+ if !i + 1 < String.length s then
107107+ if s.[!i] == '0' && is_number 10 (int_of_char s.[!i + 1]) then
108108+ raise (octal_notation s)
109109+110110+module V4 = struct
111111+ type t = int32
112112+113113+ let compare = Int32.unsigned_compare
114114+ let make a b c d = ~|a <! 24 ||| (~|b <! 16) ||| (~|c <! 8 ||| (~|d <! 0))
115115+116116+ (* parsing *)
117117+118118+ let parse_dotted_quad s i =
119119+ reject_octal s i;
120120+ let a = parse_dec_int s i in
121121+ expect_char s i '.';
122122+ reject_octal s i;
123123+ let b = parse_dec_int s i in
124124+ expect_char s i '.';
125125+ reject_octal s i;
126126+ let c = parse_dec_int s i in
127127+ expect_char s i '.';
128128+ reject_octal s i;
129129+ let d = parse_dec_int s i in
130130+ let valid a = a land 0xff <> a in
131131+ if valid a then raise (Parse_error ("first octet out of bounds", s))
132132+ else if valid b then raise (Parse_error ("second octet out of bounds", s))
133133+ else if valid c then raise (Parse_error ("third octet out of bounds", s))
134134+ else if valid d then raise (Parse_error ("fourth octet out of bounds", s))
135135+ else make a b c d
136136+137137+ (* string conversion *)
138138+139139+ let of_string_raw = parse_dotted_quad
140140+141141+ let of_string_exn s =
142142+ let o = ref 0 in
143143+ let x = of_string_raw s o in
144144+ expect_end s o;
145145+ x
146146+147147+ let of_string s = try_with_result of_string_exn s
148148+149149+ let with_port_of_string ~default s =
150150+ try
151151+ let len = String.length s and o = ref 0 in
152152+ let ipv4 = of_string_raw s o in
153153+ if !o < len && s.[!o] = ':' then (
154154+ incr o;
155155+ let port = parse_dec_int s o in
156156+ expect_end s o;
157157+ Ok (ipv4, port))
158158+ else (
159159+ expect_end s o;
160160+ Ok (ipv4, default))
161161+ with Parse_error (msg, _) -> Error (`Msg ("Ipaddr: " ^ msg))
162162+163163+ let to_buffer b i =
164164+ Printf.bprintf b "%ld.%ld.%ld.%ld" (i >! 24) (i >! 16) (i >! 8) (i >! 0)
165165+166166+ let to_string i =
167167+ let b = Buffer.create 15 in
168168+ to_buffer b i;
169169+ Buffer.contents b
170170+171171+ let pp ppf i = Format.fprintf ppf "%s" (to_string i)
172172+173173+ (* Octets conversion *)
174174+175175+ let of_octets_exn ?(off = 0) bs =
176176+ try
177177+ make
178178+ (Char.code bs.[0 + off])
179179+ (Char.code bs.[1 + off])
180180+ (Char.code bs.[2 + off])
181181+ (Char.code bs.[3 + off])
182182+ with _ -> raise (need_more bs)
183183+184184+ let of_octets ?off bs = try_with_result (of_octets_exn ?off) bs
185185+186186+ let write_octets_exn ?(off = 0) i b =
187187+ try
188188+ Bytes.set b (0 + off) (Char.chr (( |~ ) (i >! 24)));
189189+ Bytes.set b (1 + off) (Char.chr (( |~ ) (i >! 16)));
190190+ Bytes.set b (2 + off) (Char.chr (( |~ ) (i >! 8)));
191191+ Bytes.set b (3 + off) (Char.chr (( |~ ) (i >! 0)))
192192+ with _ -> raise (need_more (Bytes.to_string b))
193193+194194+ let write_octets ?off i bs = try_with_result (write_octets_exn ?off i) bs
195195+196196+ let to_octets i =
197197+ String.init 4 (function
198198+ | 0 -> Char.chr (( |~ ) (i >! 24))
199199+ | 1 -> Char.chr (( |~ ) (i >! 16))
200200+ | 2 -> Char.chr (( |~ ) (i >! 8))
201201+ | 3 -> Char.chr (( |~ ) (i >! 0))
202202+ | _ -> assert false)
203203+204204+ (* Int32 *)
205205+ let of_int32 i = i
206206+ let to_int32 i = i
207207+208208+ (* Int16 *)
209209+ let of_int16 (a, b) = ~|a <|< 16 ||| ~|b
210210+ let to_int16 a = (( |~ ) (a >|> 16), ( |~ ) (a &&& 0xFF_FF_l))
211211+212212+ (* MAC *)
213213+ (* {{:http://tools.ietf.org/html/rfc1112#section-6.2}RFC 1112}. *)
214214+ let multicast_to_mac i =
215215+ let macb = Bytes.create 6 in
216216+ Bytes.set macb 0 (Char.chr 0x01);
217217+ Bytes.set macb 1 (Char.chr 0x00);
218218+ Bytes.set macb 2 (Char.chr 0x5E);
219219+ Bytes.set macb 3 (Char.chr (( |~ ) (i >|> 16 &&& 0x7F_l)));
220220+ Bytes.set macb 4 (Char.chr (( |~ ) (i >! 8)));
221221+ Bytes.set macb 5 (Char.chr (( |~ ) (i >! 0)));
222222+ Macaddr.of_octets_exn (Bytes.to_string macb)
223223+224224+ (* Host *)
225225+ let to_domain_name i =
226226+ let name =
227227+ [
228228+ Int32.to_string (i >! 0);
229229+ Int32.to_string (i >! 8);
230230+ Int32.to_string (i >! 16);
231231+ Int32.to_string (i >! 24);
232232+ "in-addr";
233233+ "arpa";
234234+ ]
235235+ in
236236+ Domain_name.(host_exn (of_strings_exn name))
237237+238238+ let of_domain_name n =
239239+ match Domain_name.to_strings n with
240240+ | [ a; b; c; d; in_addr; arpa ]
241241+ when Domain_name.(
242242+ equal_label arpa "arpa" && equal_label in_addr "in-addr") -> (
243243+ let conv bits data =
244244+ let i = Int32.of_int (parse_dec_int data (ref 0)) in
245245+ if i > 0xFFl then
246246+ raise (Parse_error ("label with a too big number", data))
247247+ else i <! bits
248248+ in
249249+ try
250250+ let ( + ) = Int32.add in
251251+ Some (conv 0 a + conv 8 b + conv 16 c + conv 24 d)
252252+ with Parse_error _ -> None)
253253+ | _ -> None
254254+255255+ let succ t =
256256+ if Int32.equal t 0xFF_FF_FF_FFl then
257257+ Error (`Msg "Ipaddr: highest address has been reached")
258258+ else Ok (Int32.succ t)
259259+260260+ let pred t =
261261+ if Int32.equal t 0x00_00_00_00l then
262262+ Error (`Msg "Ipaddr: lowest address has been reached")
263263+ else Ok (Int32.pred t)
264264+265265+ (* constant *)
266266+267267+ let any = make 0 0 0 0
268268+ let unspecified = make 0 0 0 0
269269+ let broadcast = make 255 255 255 255
270270+ let localhost = make 127 0 0 1
271271+ let nodes = make 224 0 0 1
272272+ let routers = make 224 0 0 2
273273+274274+ module Prefix = struct
275275+ type addr = t
276276+ type t = addr * int
277277+278278+ let compare (pre, sz) (pre', sz') =
279279+ let c = compare pre pre' in
280280+ if c = 0 then Stdlib.compare sz sz' else c
281281+282282+ let ip = make
283283+284284+ let mask sz =
285285+ if sz <= 0 then 0_l
286286+ else if sz >= 32 then 0x0_FF_FF_FF_FF_l
287287+ else 0x0_FF_FF_FF_FF_l <|< 32 - sz
288288+289289+ let prefix (pre, sz) = (pre &&& mask sz, sz)
290290+ let make sz pre = (pre, sz)
291291+292292+ let network_address (pre, sz) addr =
293293+ pre &&& mask sz ||| (addr &&& Int32.lognot (mask sz))
294294+295295+ (* string conversion *)
296296+297297+ let _of_string_raw s i =
298298+ let quad = of_string_raw s i in
299299+ expect_char s i '/';
300300+ let p = parse_dec_int s i in
301301+ if p > 32 || p < 0 then raise (Parse_error ("invalid prefix size", s));
302302+ (p, quad)
303303+304304+ let of_string_raw s i =
305305+ let p, quad = _of_string_raw s i in
306306+ make p quad
307307+308308+ let _of_string_exn s =
309309+ let i = ref 0 in
310310+ let res = _of_string_raw s i in
311311+ expect_end s i;
312312+ res
313313+314314+ let of_string_exn s =
315315+ let p, quad = _of_string_exn s in
316316+ make p quad
317317+318318+ let of_string s = try_with_result of_string_exn s
319319+320320+ let _of_netmask_exn ~netmask address =
321321+ let rec find_greatest_one bits i =
322322+ if bits = 0_l then i - 1 else find_greatest_one (bits >|> 1) (i + 1)
323323+ in
324324+ let one = netmask &&& Int32.neg netmask in
325325+ let sz = 32 - find_greatest_one one (if one = 0_l then 33 else 0) in
326326+ if netmask <> mask sz then
327327+ raise (Parse_error ("invalid netmask", to_string netmask))
328328+ else make sz address
329329+330330+ let of_netmask_exn ~netmask ~address = _of_netmask_exn ~netmask address
331331+332332+ let of_netmask ~netmask ~address =
333333+ try_with_result (_of_netmask_exn ~netmask) address
334334+335335+ let to_buffer buf (pre, sz) = Printf.bprintf buf "%a/%d" to_buffer pre sz
336336+337337+ let to_string subnet =
338338+ let b = Buffer.create 18 in
339339+ to_buffer b subnet;
340340+ Buffer.contents b
341341+342342+ let pp ppf i = Format.fprintf ppf "%s" (to_string i)
343343+344344+ let mem ip (pre, sz) =
345345+ let m = mask sz in
346346+ ip &&& m = (pre &&& m)
347347+348348+ let subset ~subnet:(pre1, sz1) ~network:(pre2, sz2) =
349349+ sz1 >= sz2 && mem pre1 (pre2, sz2)
350350+351351+ let of_addr ip = make 32 ip
352352+ let global = make 0 (ip 0 0 0 0)
353353+ let relative = make 8 (ip 0 0 0 0)
354354+ let loopback = make 8 (ip 127 0 0 0)
355355+ let link = make 16 (ip 169 254 0 0)
356356+ let multicast = make 4 (ip 224 0 0 0)
357357+ let multicast_org = make 14 (ip 239 192 0 0)
358358+ let multicast_admin = make 16 (ip 239 255 0 0)
359359+ let multicast_link = make 24 (ip 224 0 0 0)
360360+361361+ (* http://tools.ietf.org/html/rfc2365 *)
362362+363363+ let private_10 = make 8 (ip 10 0 0 0)
364364+ let private_172 = make 12 (ip 172 16 0 0)
365365+ let private_192 = make 16 (ip 192 168 0 0)
366366+367367+ let private_blocks =
368368+ [ loopback; link; private_10; private_172; private_192 ]
369369+370370+ let broadcast (pre, sz) =
371371+ Int32.logor pre (Int32.logxor (mask sz) 0xFF_FF_FF_FFl)
372372+373373+ let network (pre, sz) = pre &&& mask sz
374374+ let address (addr, _) = addr
375375+ let bits (_, sz) = sz
376376+ let netmask subnet = mask (bits subnet)
377377+ let hostmask cidr = Int32.logxor (netmask cidr) 0xFF_FF_FF_FFl
378378+379379+ let first ((_, sz) as cidr) =
380380+ if sz > 30 then network cidr else network cidr |> succ |> failwith_msg
381381+382382+ let last ((_, sz) as cidr) =
383383+ if sz > 30 then broadcast cidr else broadcast cidr |> pred |> failwith_msg
384384+385385+ let hosts ?(usable = true) ((_, sz) as cidr) =
386386+ let rec iter_seq start stop =
387387+ if compare (start, 32) (stop, 32) > 0 then Seq.Nil
388388+ else
389389+ match succ start with
390390+ | Ok start_succ -> Seq.Cons (start, fun () -> iter_seq start_succ stop)
391391+ | Error _ -> Seq.Cons (start, fun () -> Seq.Nil)
392392+ in
393393+ if usable && sz = 32 then fun () -> Seq.Nil
394394+ else
395395+ let start, stop =
396396+ if usable then (first cidr, last cidr)
397397+ else (network cidr, broadcast cidr)
398398+ in
399399+ fun () -> iter_seq start stop
400400+401401+ let subnets n ((_, sz) as cidr) =
402402+ let rec iter_seq start stop steps =
403403+ if compare (start, 32) (stop, 32) > 0 then Seq.Nil
404404+ else
405405+ let prefix = make n start in
406406+ let start_succ = Int32.add start steps in
407407+ if start_succ = 0l then Seq.Cons (prefix, fun () -> Seq.Nil)
408408+ else Seq.Cons (prefix, fun () -> iter_seq start_succ stop steps)
409409+ in
410410+ if sz > n || n > 32 then fun () -> Seq.Nil
411411+ else
412412+ let start = network cidr in
413413+ let stop = broadcast cidr in
414414+ let steps = Int32.add (hostmask cidr) 1l >|> n - sz in
415415+ fun () -> iter_seq start stop steps
416416+ end
417417+418418+ (* TODO: this could be optimized with something trie-like *)
419419+ let scope i =
420420+ let mem = Prefix.mem i in
421421+ if mem Prefix.loopback then Interface
422422+ else if mem Prefix.link then Link
423423+ else if List.exists mem Prefix.private_blocks then Organization
424424+ else if i = unspecified then Point
425425+ else if i = broadcast then Admin
426426+ else if mem Prefix.relative then Admin
427427+ else if mem Prefix.multicast then
428428+ if mem Prefix.multicast_org then Organization
429429+ else if mem Prefix.multicast_admin then Admin
430430+ else if mem Prefix.multicast_link then Link
431431+ else Global
432432+ else Global
433433+434434+ let is_global i = scope i = Global
435435+ let is_multicast i = Prefix.(mem i multicast)
436436+ let is_private i = scope i <> Global
437437+438438+ module Set = Set.Make (struct
439439+ type nonrec t = t
440440+441441+ let compare (a : t) (b : t) = compare a b
442442+ end)
443443+444444+ module Map = Map.Make (struct
445445+ type nonrec t = t
446446+447447+ let compare (a : t) (b : t) = compare a b
448448+ end)
449449+end
450450+451451+module S128 : sig
452452+ exception Overflow
453453+454454+ type t
455455+456456+ val zero : t [@@ocaml.warning "-32"]
457457+ val max_int : t
458458+ val compare : t -> t -> int
459459+ val equal : t -> t -> bool
460460+ val fold_left : ('a -> int -> 'a) -> 'a -> t -> 'a
461461+ val of_octets_exn : string -> t
462462+ val to_octets : t -> string
463463+ val of_int64 : int64 * int64 -> t
464464+ val to_int64 : t -> int64 * int64
465465+ val of_int32 : int32 * int32 * int32 * int32 -> t
466466+ val to_int32 : t -> int32 * int32 * int32 * int32
467467+ val of_int16 : int * int * int * int * int * int * int * int -> t
468468+ val to_int16 : t -> int * int * int * int * int * int * int * int
469469+ val add_exn : t -> t -> t [@@ocaml.warning "-32"]
470470+ val pred_exn : t -> t [@@ocaml.warning "-32"]
471471+ val add : t -> t -> t option
472472+ val logand : t -> t -> t
473473+ val logor : t -> t -> t
474474+ val logxor : t -> t -> t
475475+ val lognot : t -> t
476476+477477+ module Byte : sig
478478+ val get_lsbits : int -> int -> int [@@ocaml.warning "-32"]
479479+ val get_msbits : int -> int -> int [@@ocaml.warning "-32"]
480480+ val set_msbits : int -> int -> int -> int [@@ocaml.warning "-32"]
481481+ val fold_left : ('a -> bool -> 'a) -> 'a -> int -> 'a
482482+ end
483483+484484+ val shift_right : t -> int -> t
485485+ val shift_left : t -> int -> t
486486+ val write_octets_exn : ?off:int -> t -> bytes -> unit
487487+ val succ_exn : t -> t
488488+ val succ : t -> (t, [> `Msg of string ]) result
489489+ val pred : t -> (t, [> `Msg of string ]) result
490490+end = struct
491491+ exception Overflow
492492+493493+ type t = string
494494+495495+ let mk_zero () = Bytes.make 16 '\x00'
496496+ let zero = Bytes.unsafe_to_string (mk_zero ())
497497+ let max_int = String.make 16 '\xff'
498498+ let compare = String.compare
499499+ let equal = String.equal
500500+501501+ let fold_left f init s =
502502+ (* With OCaml>=4.13.0:
503503+ [String.fold_left (fun acc c -> f acc (Char.code c)) init s] *)
504504+ let a = ref init in
505505+ for i = 0 to 15 do
506506+ a := f !a (Char.code (String.get s i))
507507+ done;
508508+ !a
509509+510510+ let iteri_right2 f x y =
511511+ for i = 15 downto 0 do
512512+ let x' = Char.code (String.get x i) in
513513+ let y' = Char.code (String.get y i) in
514514+ f i x' y'
515515+ done
516516+517517+ let of_octets_exn s =
518518+ if String.length s <> 16 then invalid_arg "not 16 bytes long";
519519+ s
520520+521521+ let to_octets = Fun.id
522522+523523+ let of_int64 (a, b) =
524524+ let b' = mk_zero () in
525525+ Bytes.set_int64_be b' 0 a;
526526+ Bytes.set_int64_be b' 8 b;
527527+ Bytes.unsafe_to_string b'
528528+529529+ let to_int64 s =
530530+ (* with OCaml>=4.13, use String.get_int64_be *)
531531+ let b = Bytes.unsafe_of_string s in
532532+ (Bytes.get_int64_be b 0, Bytes.get_int64_be b 8)
533533+534534+ let of_int32 (a, b, c, d) =
535535+ let b' = mk_zero () in
536536+ Bytes.set_int32_be b' 0 a;
537537+ Bytes.set_int32_be b' 4 b;
538538+ Bytes.set_int32_be b' 8 c;
539539+ Bytes.set_int32_be b' 12 d;
540540+ Bytes.unsafe_to_string b'
541541+542542+ let to_int32 s =
543543+ (* with OCaml>=4.13, use String.get_int32_be *)
544544+ let b = Bytes.unsafe_of_string s in
545545+ ( Bytes.get_int32_be b 0,
546546+ Bytes.get_int32_be b 4,
547547+ Bytes.get_int32_be b 8,
548548+ Bytes.get_int32_be b 12 )
549549+550550+ let of_int16 (a, b, c, d, e, f, g, h) =
551551+ let b' = mk_zero () in
552552+ Bytes.set_uint16_be b' 0 a;
553553+ Bytes.set_uint16_be b' 2 b;
554554+ Bytes.set_uint16_be b' 4 c;
555555+ Bytes.set_uint16_be b' 6 d;
556556+ Bytes.set_uint16_be b' 8 e;
557557+ Bytes.set_uint16_be b' 10 f;
558558+ Bytes.set_uint16_be b' 12 g;
559559+ Bytes.set_uint16_be b' 14 h;
560560+ Bytes.unsafe_to_string b'
561561+562562+ let to_int16 s =
563563+ (* with OCaml>=4.13, use String.get_uint16_be *)
564564+ let b = Bytes.unsafe_of_string s in
565565+ ( Bytes.get_uint16_be b 0,
566566+ Bytes.get_uint16_be b 2,
567567+ Bytes.get_uint16_be b 4,
568568+ Bytes.get_uint16_be b 6,
569569+ Bytes.get_uint16_be b 8,
570570+ Bytes.get_uint16_be b 10,
571571+ Bytes.get_uint16_be b 12,
572572+ Bytes.get_uint16_be b 14 )
573573+574574+ let add_exn x y =
575575+ let b = mk_zero () in
576576+ let carry = ref 0 in
577577+ iteri_right2
578578+ (fun i x' y' ->
579579+ let sum = x' + y' + !carry in
580580+ if sum >= 256 then (
581581+ carry := 1;
582582+ Bytes.set_uint8 b i (sum - 256))
583583+ else (
584584+ carry := 0;
585585+ Bytes.set_uint8 b i sum))
586586+ x y;
587587+ if !carry <> 0 then raise Overflow else Bytes.unsafe_to_string b
588588+589589+ let add x y = try Some (add_exn x y) with Overflow -> None
590590+591591+ let pred_exn x =
592592+ if equal x zero then raise Overflow;
593593+ let b = Bytes.of_string x in
594594+ let rec go i =
595595+ Bytes.set_uint8 b i (Char.code (String.get x i) - 1);
596596+ if Char.code (String.get x i) = 0 then go (Stdlib.pred i)
597597+ in
598598+ go 15;
599599+ Bytes.unsafe_to_string b
600600+601601+ let logand x y =
602602+ let b = mk_zero () in
603603+ iteri_right2 (fun i x y -> Bytes.set_uint8 b i (x land y)) x y;
604604+ Bytes.unsafe_to_string b
605605+606606+ let logor x y =
607607+ let b = mk_zero () in
608608+ iteri_right2 (fun i x y -> Bytes.set_uint8 b i (x lor y)) x y;
609609+ Bytes.unsafe_to_string b
610610+611611+ let logxor x y =
612612+ let b = mk_zero () in
613613+ iteri_right2 (fun i x y -> Bytes.set_uint8 b i (x lxor y)) x y;
614614+ Bytes.unsafe_to_string b
615615+616616+ let lognot x =
617617+ let b = mk_zero () in
618618+ String.iteri
619619+ (fun i _ -> Bytes.set_uint8 b i (lnot (Char.code (String.get x i))))
620620+ x;
621621+ Bytes.unsafe_to_string b
622622+623623+ module Byte = struct
624624+ (* Extract the [n] least significant bits from [i] *)
625625+ let get_lsbits n i =
626626+ if n <= 0 || n > 8 then invalid_arg "out of bounds";
627627+ i land ((1 lsl n) - 1)
628628+629629+ (* Extract the [n] most significant bits from [i] *)
630630+ let get_msbits n i =
631631+ if n <= 0 || n > 8 then invalid_arg "out of bounds";
632632+ (i land (255 lsl (8 - n))) lsr (8 - n)
633633+634634+ (* Set value [x] in [i]'s [n] most significant bits *)
635635+ let set_msbits n x i =
636636+ if n < 0 || n > 8 then raise (Invalid_argument "n must be >= 0 && <= 8")
637637+ else if n = 0 then i
638638+ else if n = 8 then x
639639+ else (x lsl (8 - n)) lor i
640640+641641+ (* set bits are represented as true *)
642642+ let fold_left f a i =
643643+ let bitmask = ref 0b1000_0000 in
644644+ let a' = ref a in
645645+ for _ = 0 to 7 do
646646+ a' := f !a' (i land !bitmask > 0);
647647+ bitmask := !bitmask lsr 1
648648+ done;
649649+ !a'
650650+ end
651651+652652+ let shift_right x n =
653653+ match n with
654654+ | 0 -> x
655655+ | 128 -> zero
656656+ | n when n > 0 && n < 128 ->
657657+ let b = mk_zero () in
658658+ let shift_bytes, shift_bits = (n / 8, n mod 8) in
659659+ (if shift_bits = 0 then
660660+ Bytes.blit_string x 0 b shift_bytes (16 - shift_bytes)
661661+ else
662662+ let carry = ref 0 in
663663+ for i = 0 to 15 - shift_bytes do
664664+ let x' = Char.code (String.get x i) in
665665+ let new_carry = Byte.get_lsbits shift_bits x' in
666666+ let shifted_value = x' lsr shift_bits in
667667+ let new_value = Byte.set_msbits shift_bits !carry shifted_value in
668668+ Bytes.set_uint8 b (i + shift_bytes) new_value;
669669+ carry := new_carry
670670+ done);
671671+ Bytes.unsafe_to_string b
672672+ | _ -> raise (Invalid_argument "n must be >= 0 && <= 128")
673673+674674+ let shift_left x n =
675675+ match n with
676676+ | 0 -> x
677677+ | 128 -> zero
678678+ | n when n > 0 && n < 128 ->
679679+ let b = mk_zero () in
680680+ let shift_bytes, shift_bits = (n / 8, n mod 8) in
681681+ (if shift_bits = 0 then
682682+ Bytes.blit_string x shift_bytes b 0 (16 - shift_bytes)
683683+ else
684684+ let carry = ref 0 in
685685+ for i = 15 downto 0 + shift_bytes do
686686+ let x' = Char.code (String.get x i) in
687687+ let new_carry = Byte.get_msbits shift_bits x' in
688688+ let shifted_value = x' lsl shift_bits in
689689+ let new_value = shifted_value lor !carry in
690690+ Bytes.set_uint8 b (i - shift_bytes) new_value;
691691+ carry := new_carry
692692+ done);
693693+ Bytes.unsafe_to_string b
694694+ | _ -> raise (Invalid_argument "n must be >= 0 && <= 128")
695695+696696+ let write_octets_exn ?(off = 0) s dest =
697697+ if Bytes.length dest - off < 16 then
698698+ raise (Parse_error ("larger including offset than target bytes", s))
699699+ else Bytes.blit_string s 0 dest off (String.length s)
700700+701701+ let succ_exn x = add_exn x (of_int64 (0L, 1L))
702702+703703+ let succ x =
704704+ try Ok (succ_exn x)
705705+ with Overflow -> Error (`Msg "Ipaddr: highest address has been reached")
706706+707707+ let pred x =
708708+ try Ok (pred_exn x)
709709+ with Overflow | Invalid_argument _ ->
710710+ Error (`Msg "Ipaddr: lowest address has been reached")
711711+end
712712+713713+module V6 = struct
714714+ include S128
715715+716716+ let make a b c d e f g h = of_int16 (a, b, c, d, e, f, g, h)
717717+718718+ (* parsing *)
719719+ let parse_ipv6 s i =
720720+ let compressed = ref false in
721721+ (* :: *)
722722+ let len = String.length s in
723723+ if len < !i + 1 then raise (need_more s);
724724+ let use_bracket = s.[!i] = '[' in
725725+ if use_bracket then incr i;
726726+ if len < !i + 2 then raise (need_more s);
727727+ (* check if it starts with :: *)
728728+ let l =
729729+ if s.[!i] = ':' then (
730730+ incr i;
731731+ if s.[!i] = ':' then (
732732+ compressed := true;
733733+ incr i;
734734+ [ -1 ])
735735+ else raise (bad_char !i s))
736736+ else []
737737+ in
738738+739739+ let rec loop nb acc =
740740+ if nb >= 8 then acc
741741+ else if !i >= len then acc
742742+ else
743743+ let pos = !i in
744744+ let x = try parse_hex_int s i with _ -> -1 in
745745+ if x < 0 then acc
746746+ else if nb = 7 then x :: acc
747747+ else if !i < len && s.[!i] = ':' then (
748748+ incr i;
749749+ if !i < len then
750750+ if s.[!i] = ':' then
751751+ if !compressed then (
752752+ decr i;
753753+ x :: acc (* trailing :: *))
754754+ else (
755755+ compressed := true;
756756+ incr i;
757757+ loop (nb + 2) (-1 :: x :: acc))
758758+ else if is_number 16 (int_of_char s.[!i]) then
759759+ loop (nb + 1) (x :: acc)
760760+ else raise (bad_char !i s)
761761+ else raise (need_more s))
762762+ else if !i < len && s.[!i] = '.' then (
763763+ i := pos;
764764+ let v4 = V4.of_string_raw s i in
765765+ let hi, lo = V4.to_int16 v4 in
766766+ lo :: hi :: acc)
767767+ else x :: acc
768768+ in
769769+770770+ let res = loop (List.length l) l in
771771+ let res_len = List.length res in
772772+ if res_len > 8 then raise (Parse_error ("too many components", s))
773773+ else if res_len = 0 then raise (need_more s)
774774+ else
775775+ let a = Array.make 8 0 in
776776+ let missing =
777777+ if !compressed then 8 - (res_len - 1)
778778+ else if res_len <> 8 then
779779+ if !i < len then raise (bad_char !i s) else raise (need_more s)
780780+ else 0
781781+ in
782782+ let _ =
783783+ List.fold_left
784784+ (fun i x ->
785785+ if x = -1 then i - missing
786786+ else (
787787+ if x land 0xffff <> x then
788788+ raise
789789+ (Parse_error (Printf.sprintf "component %d out of bounds" i, s));
790790+ a.(i) <- x;
791791+ i - 1))
792792+ 7 res
793793+ in
794794+ if use_bracket then expect_char s i ']';
795795+ a
796796+797797+ (* string conversion *)
798798+799799+ let of_string_raw s offset =
800800+ let a = parse_ipv6 s offset in
801801+ make a.(0) a.(1) a.(2) a.(3) a.(4) a.(5) a.(6) a.(7)
802802+803803+ let of_string_exn s =
804804+ let o = ref 0 in
805805+ let x = of_string_raw s o in
806806+ expect_end s o;
807807+ x
808808+809809+ let of_string s = try_with_result of_string_exn s
810810+811811+ let with_port_of_string ~default s =
812812+ let len = String.length s and o = ref 0 in
813813+ try
814814+ let ipv6 = of_string_raw s o in
815815+ if !o < len && s.[!o] = ':' then (
816816+ incr o;
817817+ let port = parse_dec_int s o in
818818+ expect_end s o;
819819+ Ok (ipv6, port))
820820+ else (
821821+ expect_end s o;
822822+ Ok (ipv6, default))
823823+ with Parse_error (msg, _) -> Error (`Msg ("Ipaddr: " ^ msg))
824824+825825+ (* http://tools.ietf.org/html/rfc5952 *)
826826+ let to_buffer buf addr =
827827+ let ((a, b, c, d, e, f, g, h) as comp) = to_int16 addr in
828828+829829+ let v4 =
830830+ match comp with 0, 0, 0, 0, 0, 0xffff, _, _ -> true | _ -> false
831831+ in
832832+833833+ let rec loop elide zeros acc = function
834834+ | 0 :: xs -> loop elide (zeros - 1) acc xs
835835+ | n :: xs when zeros = 0 -> loop elide 0 (n :: acc) xs
836836+ | n :: xs -> loop (min elide zeros) 0 (n :: zeros :: acc) xs
837837+ | [] ->
838838+ let elide = min elide zeros in
839839+ ( (if elide < -1 then Some elide else None),
840840+ if zeros = 0 then acc else zeros :: acc )
841841+ in
842842+843843+ let elide, l = loop 0 0 [] [ h; g; f; e; d; c; b; a ] in
844844+ assert (match elide with Some x when x < -8 -> false | _ -> true);
845845+846846+ let rec cons_zeros l x =
847847+ if x >= 0 then l else cons_zeros (Some 0 :: l) (x + 1)
848848+ in
849849+850850+ let _, lrev =
851851+ List.fold_left
852852+ (fun (patt, l) x ->
853853+ if Some x = patt then (None, None :: l)
854854+ else if x < 0 then (patt, cons_zeros l x)
855855+ else (patt, Some x :: l))
856856+ (elide, []) l
857857+ in
858858+859859+ let rec fill = function
860860+ | [ Some hi; Some lo ] when v4 ->
861861+ let addr = V4.of_int16 (hi, lo) in
862862+ V4.to_buffer buf addr
863863+ | None :: xs ->
864864+ Buffer.add_string buf "::";
865865+ fill xs
866866+ | [ Some n ] -> Printf.bprintf buf "%x" n
867867+ | Some n :: None :: xs ->
868868+ Printf.bprintf buf "%x::" n;
869869+ fill xs
870870+ | Some n :: xs ->
871871+ Printf.bprintf buf "%x:" n;
872872+ fill xs
873873+ | [] -> ()
874874+ in
875875+ fill (List.rev lrev)
876876+877877+ let to_string l =
878878+ let buf = Buffer.create 39 in
879879+ to_buffer buf l;
880880+ Buffer.contents buf
881881+882882+ let pp ppf i = Format.fprintf ppf "%s" (to_string i)
883883+884884+ (* byte conversion *)
885885+886886+ let of_octets_exn ?(off = 0) bs =
887887+ if String.length bs - off < 16 then raise (need_more bs)
888888+ else S128.of_octets_exn (String.sub bs off 16)
889889+890890+ let of_octets ?off bs = try_with_result (of_octets_exn ?off) bs
891891+ let write_octets ?off i bs = try_with_result (write_octets_exn ?off i) bs
892892+ let to_octets = S128.to_octets
893893+894894+ (* MAC *)
895895+ (* {{:https://tools.ietf.org/html/rfc2464#section-7}RFC 2464}. *)
896896+ let multicast_to_mac s =
897897+ let macb = Bytes.make 6 (Char.chr 0x33) in
898898+ Bytes.blit_string (S128.to_octets s) 12 macb 2 4;
899899+ Macaddr.of_octets_exn (Bytes.to_string macb)
900900+901901+ (* Host *)
902902+ let to_domain_name b =
903903+ let hexstr_of_int = Printf.sprintf "%x" in
904904+ let name =
905905+ S128.fold_left
906906+ (fun acc b ->
907907+ let x = hexstr_of_int (b land ((1 lsl 4) - 1)) in
908908+ let y = hexstr_of_int (b lsr 4) in
909909+ x :: y :: acc)
910910+ [ "ip6"; "arpa" ] b
911911+ in
912912+ Domain_name.(host_exn (of_strings_exn name))
913913+914914+ let of_domain_name n =
915915+ let int_of_char_string = function
916916+ | "0" -> 0
917917+ | "1" -> 1
918918+ | "2" -> 2
919919+ | "3" -> 3
920920+ | "4" -> 4
921921+ | "5" -> 5
922922+ | "6" -> 6
923923+ | "7" -> 7
924924+ | "8" -> 8
925925+ | "9" -> 9
926926+ | "a" -> 10
927927+ | "b" -> 11
928928+ | "c" -> 12
929929+ | "d" -> 13
930930+ | "e" -> 14
931931+ | "f" -> 15
932932+ | _ -> failwith "int_of_char_string: invalid hexadecimal string"
933933+ in
934934+ let labels = Domain_name.to_array n in
935935+ if
936936+ Array.length labels = 34
937937+ && Domain_name.equal_label labels.(0) "arpa"
938938+ && Domain_name.equal_label labels.(1) "ip6"
939939+ then
940940+ let b = Bytes.create 16 in
941941+ try
942942+ for bi = 0 to 15 do
943943+ let i = 2 * Int.succ bi in
944944+ let x = int_of_char_string labels.(i) in
945945+ let y = int_of_char_string labels.(i + 1) in
946946+ Bytes.set_uint8 b bi (Int.logor (Int.shift_left x 4) y)
947947+ done;
948948+ Some (S128.of_octets_exn (Bytes.unsafe_to_string b))
949949+ with Failure _ -> None
950950+ else None
951951+952952+ (* constant *)
953953+954954+ let unspecified = make 0 0 0 0 0 0 0 0
955955+ let localhost = make 0 0 0 0 0 0 0 1
956956+ let interface_nodes = make 0xff01 0 0 0 0 0 0 1
957957+ let link_nodes = make 0xff02 0 0 0 0 0 0 1
958958+ let interface_routers = make 0xff01 0 0 0 0 0 0 2
959959+ let link_routers = make 0xff02 0 0 0 0 0 0 2
960960+ let site_routers = make 0xff05 0 0 0 0 0 0 2
961961+962962+ module Prefix = struct
963963+ type addr = t
964964+ type t = addr * int
965965+966966+ let compare (pre, sz) (pre', sz') =
967967+ let c = compare pre pre' in
968968+ if c = 0 then Stdlib.compare sz sz' else c
969969+970970+ let ip = make
971971+ let mask sz = shift_left max_int (128 - sz)
972972+ let prefix (pre, sz) = (logand pre (mask sz), sz)
973973+ let make sz pre = (pre, sz)
974974+975975+ let network_address (pre, sz) addr =
976976+ logor (logand pre (mask sz)) (logand addr (lognot (mask sz)))
977977+978978+ let _of_string_raw s i =
979979+ let v6 = of_string_raw s i in
980980+ expect_char s i '/';
981981+ let p = parse_dec_int s i in
982982+ if p > 128 || p < 0 then raise (Parse_error ("invalid prefix size", s));
983983+ (p, v6)
984984+985985+ let of_string_raw s i =
986986+ let p, v6 = _of_string_raw s i in
987987+ make p v6
988988+989989+ let _of_string_exn s =
990990+ let i = ref 0 in
991991+ let res = _of_string_raw s i in
992992+ expect_end s i;
993993+ res
994994+995995+ let of_string_exn s =
996996+ let p, v6 = _of_string_exn s in
997997+ make p v6
998998+999999+ let of_string s = try_with_result of_string_exn s
10001000+10011001+ let _of_netmask_exn ~netmask address =
10021002+ let count_bits bits is_last_bit_set i =
10031003+ S128.Byte.fold_left
10041004+ (fun (a, is_last_bit_set) e ->
10051005+ match (is_last_bit_set, e) with
10061006+ | true, false | false, false -> (a, false)
10071007+ | true, true -> (a + 1, true)
10081008+ | false, true ->
10091009+ (* netmask is not contiguous *)
10101010+ raise (Parse_error ("invalid netmask", to_string netmask)))
10111011+ (bits, is_last_bit_set) i
10121012+ in
10131013+ let nm_bits_set, _ =
10141014+ S128.fold_left
10151015+ (fun (a, is_last_bit_set) e -> count_bits a is_last_bit_set e)
10161016+ (0, true) netmask
10171017+ in
10181018+ make nm_bits_set address
10191019+10201020+ let of_netmask_exn ~netmask ~address = _of_netmask_exn ~netmask address
10211021+10221022+ let of_netmask ~netmask ~address =
10231023+ try_with_result (_of_netmask_exn ~netmask) address
10241024+10251025+ let to_buffer buf (pre, sz) = Printf.bprintf buf "%a/%d" to_buffer pre sz
10261026+10271027+ let to_string subnet =
10281028+ let buf = Buffer.create 43 in
10291029+ to_buffer buf subnet;
10301030+ Buffer.contents buf
10311031+10321032+ let pp ppf i = Format.fprintf ppf "%s" (to_string i)
10331033+10341034+ let mem ip (pre, sz) =
10351035+ let m = mask sz in
10361036+ logand ip m = logand pre m
10371037+10381038+ let subset ~subnet:(pre1, sz1) ~network:(pre2, sz2) =
10391039+ sz1 >= sz2 && mem pre1 (pre2, sz2)
10401040+10411041+ let of_addr ip = make 128 ip
10421042+ let global_unicast_001 = make 3 (ip 0x2000 0 0 0 0 0 0 0)
10431043+ let link = make 64 (ip 0xfe80 0 0 0 0 0 0 0)
10441044+ let unique_local = make 7 (ip 0xfc00 0 0 0 0 0 0 0)
10451045+ let multicast = make 8 (ip 0xff00 0 0 0 0 0 0 0)
10461046+ let ipv4_mapped = make 96 (ip 0 0 0 0 0 0xffff 0 0)
10471047+ let noneui64_interface = make 3 (ip 0x0000 0 0 0 0 0 0 0)
10481048+ let solicited_node = make 104 (ip 0xff02 0 0 0 0 1 0xff00 0)
10491049+ let network (pre, sz) = logand pre (mask sz)
10501050+ let address (addr, _) = addr
10511051+ let bits (_, sz) = sz
10521052+ let netmask subnet = mask (bits subnet)
10531053+ let hostmask cidr = S128.logxor (netmask cidr) S128.max_int
10541054+10551055+ let first ((_, sz) as cidr) =
10561056+ if sz > 126 then network cidr else network cidr |> succ |> failwith_msg
10571057+10581058+ let last ((_, sz) as cidr) =
10591059+ let ffff = S128.max_int in
10601060+ logor (network cidr) (S128.shift_right ffff sz)
10611061+10621062+ let hosts ?(usable = true) ((_, sz) as cidr) =
10631063+ let rec iter_seq start stop =
10641064+ if S128.compare start stop > 0 then Seq.Nil
10651065+ else
10661066+ match succ start with
10671067+ | Ok start_succ -> Seq.Cons (start, fun () -> iter_seq start_succ stop)
10681068+ | Error _ -> Seq.Cons (start, fun () -> Seq.Nil)
10691069+ in
10701070+ if usable && sz = 128 then fun () -> Seq.Nil
10711071+ else
10721072+ let start, stop =
10731073+ if usable then (first cidr, last cidr) else (network cidr, last cidr)
10741074+ in
10751075+ fun () -> iter_seq start stop
10761076+10771077+ let subnets n ((_, sz) as cidr) =
10781078+ let rec iter_seq start stop steps =
10791079+ if S128.compare start stop > 0 then Seq.Nil
10801080+ else
10811081+ let prefix = make n start in
10821082+ if S128.equal start stop then Seq.Cons (prefix, fun () -> Seq.Nil)
10831083+ else
10841084+ match S128.add start steps with
10851085+ | None -> Seq.Cons (prefix, fun () -> Seq.Nil)
10861086+ | Some start_succ ->
10871087+ Seq.Cons (prefix, fun () -> iter_seq start_succ stop steps)
10881088+ in
10891089+ if sz > n || n > 128 then fun () -> Seq.Nil
10901090+ else
10911091+ let start = network cidr in
10921092+ let stop = last cidr in
10931093+ let steps = S128.(succ_exn (shift_right (hostmask cidr) (n - sz))) in
10941094+ fun () -> iter_seq start stop steps
10951095+ end
10961096+10971097+ (* TODO: This could be optimized with something trie-like *)
10981098+ let scope i =
10991099+ let mem = Prefix.mem i in
11001100+ if mem Prefix.global_unicast_001 then Global
11011101+ else if
11021102+ mem Prefix.ipv4_mapped (* rfc says they are technically global but... *)
11031103+ then
11041104+ V4.scope
11051105+ (let _, _, _, v4 = to_int32 i in
11061106+ V4.of_int32 v4)
11071107+ else if mem Prefix.multicast then
11081108+ let x, _, _, _, _, _, _, _ = to_int16 i in
11091109+ match x land 0xf with
11101110+ | 0 -> Point
11111111+ | 1 -> Interface
11121112+ | 2 | 3 -> Link
11131113+ | 4 -> Admin
11141114+ | 5 | 6 | 7 -> Site
11151115+ | 8 | 9 | 10 | 11 | 12 | 13 -> Organization
11161116+ | 14 | 15 -> Global
11171117+ | _ -> assert false
11181118+ else if mem Prefix.link then Link
11191119+ else if mem Prefix.unique_local then Global
11201120+ else if i = localhost then Interface
11211121+ else if i = unspecified then Point
11221122+ else Global
11231123+11241124+ let link_address_of_mac =
11251125+ let c b i = Char.code b.[i] in
11261126+ fun mac ->
11271127+ let bmac = Macaddr.to_octets mac in
11281128+ let c_0 = c bmac 0 lxor 2 in
11291129+ let addr =
11301130+ make 0 0 0 0
11311131+ ((c_0 lsl 8) + c bmac 1)
11321132+ ((c bmac 2 lsl 8) + 0xff)
11331133+ (0xfe00 + c bmac 3)
11341134+ ((c bmac 4 lsl 8) + c bmac 5)
11351135+ in
11361136+ Prefix.(network_address link addr)
11371137+11381138+ let is_global i = scope i = Global
11391139+ let is_multicast i = Prefix.(mem i multicast)
11401140+ let is_private i = scope i <> Global
11411141+11421142+ module Set = Set.Make (struct
11431143+ type nonrec t = t
11441144+11451145+ let compare (a : t) (b : t) = compare a b
11461146+ end)
11471147+11481148+ module Map = Map.Make (struct
11491149+ type nonrec t = t
11501150+11511151+ let compare (a : t) (b : t) = compare a b
11521152+ end)
11531153+end
11541154+11551155+type ('v4, 'v6) v4v6 = V4 of 'v4 | V6 of 'v6
11561156+type t = (V4.t, V6.t) v4v6
11571157+11581158+let compare a b =
11591159+ match (a, b) with
11601160+ | V4 a, V4 b -> V4.compare a b
11611161+ | V6 a, V6 b -> V6.compare a b
11621162+ | V4 _, V6 _ -> -1
11631163+ | V6 _, V4 _ -> 1
11641164+11651165+module Set = Set.Make (struct
11661166+ type nonrec t = t
11671167+11681168+ let compare (a : t) (b : t) = compare a b
11691169+end)
11701170+11711171+module Map = Map.Make (struct
11721172+ type nonrec t = t
11731173+11741174+ let compare (a : t) (b : t) = compare a b
11751175+end)
11761176+11771177+let to_string = function V4 x -> V4.to_string x | V6 x -> V6.to_string x
11781178+11791179+let to_buffer buf = function
11801180+ | V4 x -> V4.to_buffer buf x
11811181+ | V6 x -> V6.to_buffer buf x
11821182+11831183+let pp ppf i = Format.fprintf ppf "%s" (to_string i)
11841184+11851185+let of_string_raw s offset =
11861186+ let len = String.length s in
11871187+ if len < !offset + 1 then raise (need_more s);
11881188+ match s.[0] with
11891189+ | '[' -> V6 (V6.of_string_raw s offset)
11901190+ | _ -> (
11911191+ let pos = !offset in
11921192+ try V4 (V4.of_string_raw s offset)
11931193+ with Parse_error (v4_msg, _) -> (
11941194+ offset := pos;
11951195+ try V6 (V6.of_string_raw s offset)
11961196+ with Parse_error (v6_msg, s) ->
11971197+ let msg =
11981198+ Printf.sprintf "not an IPv4 address: %s\nnot an IPv6 address: %s"
11991199+ v4_msg v6_msg
12001200+ in
12011201+ raise (Parse_error (msg, s))))
12021202+12031203+let of_string_exn s =
12041204+ let o = ref 0 in
12051205+ let x = of_string_raw s o in
12061206+ expect_end s o;
12071207+ x
12081208+12091209+let of_string s = try_with_result of_string_exn s
12101210+12111211+let with_port_of_string ~default s =
12121212+ let len = String.length s and o = ref 0 in
12131213+ try
12141214+ let ipv6 = of_string_raw s o in
12151215+ if !o < len && s.[!o] = ':' then (
12161216+ incr o;
12171217+ let port = parse_dec_int s o in
12181218+ expect_end s o;
12191219+ Ok (ipv6, port))
12201220+ else (
12211221+ expect_end s o;
12221222+ Ok (ipv6, default))
12231223+ with Parse_error (msg, _) -> Error (`Msg ("Ipaddr: " ^ msg))
12241224+12251225+let of_octets_exn bs =
12261226+ match String.length bs with
12271227+ | 4 -> V4 (V4.of_octets_exn bs)
12281228+ | 16 -> V6 (V6.of_octets_exn bs)
12291229+ | _ -> raise (Parse_error ("octets must be of length 4 or 16", bs))
12301230+12311231+let of_octets bs = try_with_result of_octets_exn bs
12321232+let to_octets i = match i with V4 p -> V4.to_octets p | V6 p -> V6.to_octets p
12331233+12341234+let v6_of_v4 v4 =
12351235+ V6.(Prefix.(network_address ipv4_mapped (of_int32 (0l, 0l, 0l, v4))))
12361236+12371237+let v4_of_v6 v6 =
12381238+ if V6.Prefix.(mem v6 ipv4_mapped) then
12391239+ let _, _, _, v4 = V6.to_int32 v6 in
12401240+ Some V4.(of_int32 v4)
12411241+ else None
12421242+12431243+let to_v4 = function V4 v4 -> Some v4 | V6 v6 -> v4_of_v6 v6
12441244+let to_v6 = function V4 v4 -> v6_of_v4 v4 | V6 v6 -> v6
12451245+let scope = function V4 v4 -> V4.scope v4 | V6 v6 -> V6.scope v6
12461246+let is_global = function V4 v4 -> V4.is_global v4 | V6 v6 -> V6.is_global v6
12471247+12481248+let is_multicast = function
12491249+ | V4 v4 -> V4.is_multicast v4
12501250+ | V6 v6 -> V6.is_multicast v6
12511251+12521252+let is_private = function
12531253+ | V4 v4 -> V4.is_private v4
12541254+ | V6 v6 -> V6.is_private v6
12551255+12561256+let multicast_to_mac = function
12571257+ | V4 v4 -> V4.multicast_to_mac v4
12581258+ | V6 v6 -> V6.multicast_to_mac v6
12591259+12601260+let to_domain_name = function
12611261+ | V4 v4 -> V4.to_domain_name v4
12621262+ | V6 v6 -> V6.to_domain_name v6
12631263+12641264+let of_domain_name n =
12651265+ match Domain_name.count_labels n with
12661266+ | 6 -> (
12671267+ match V4.of_domain_name n with None -> None | Some x -> Some (V4 x))
12681268+ | 34 -> (
12691269+ match V6.of_domain_name n with None -> None | Some x -> Some (V6 x))
12701270+ | _ -> None
12711271+12721272+let succ = function
12731273+ | V4 addr -> Result.map (fun v -> V4 v) (V4.succ addr)
12741274+ | V6 addr -> Result.map (fun v -> V6 v) (V6.succ addr)
12751275+12761276+let pred = function
12771277+ | V4 addr -> Result.map (fun v -> V4 v) (V4.pred addr)
12781278+ | V6 addr -> Result.map (fun v -> V6 v) (V6.pred addr)
12791279+12801280+module Prefix = struct
12811281+ module Addr = struct
12821282+ let to_v6 = to_v6
12831283+ end
12841284+12851285+ type addr = t
12861286+ type t = (V4.Prefix.t, V6.Prefix.t) v4v6
12871287+12881288+ let compare a b =
12891289+ match (a, b) with
12901290+ | V4 a, V4 b -> V4.Prefix.compare a b
12911291+ | V6 a, V6 b -> V6.Prefix.compare a b
12921292+ | V4 _, V6 _ -> -1
12931293+ | V6 _, V4 _ -> 1
12941294+12951295+ let of_string_raw s offset =
12961296+ let len = String.length s in
12971297+ if len < !offset + 1 then raise (need_more s);
12981298+ match s.[0] with
12991299+ | '[' -> V6 (V6.Prefix.of_string_raw s offset)
13001300+ | _ -> (
13011301+ let pos = !offset in
13021302+ try V4 (V4.Prefix.of_string_raw s offset)
13031303+ with Parse_error (v4_msg, _) -> (
13041304+ offset := pos;
13051305+ try V6 (V6.Prefix.of_string_raw s offset)
13061306+ with Parse_error (v6_msg, s) ->
13071307+ let msg =
13081308+ Printf.sprintf "not an IPv4 prefix: %s\nnot an IPv6 prefix: %s"
13091309+ v4_msg v6_msg
13101310+ in
13111311+ raise (Parse_error (msg, s))))
13121312+13131313+ let of_string_exn s =
13141314+ let o = ref 0 in
13151315+ let x = of_string_raw s o in
13161316+ expect_end s o;
13171317+ x
13181318+13191319+ let of_string s = try_with_result of_string_exn s
13201320+13211321+ let v6_of_v4 v4 =
13221322+ V6.Prefix.make (96 + V4.Prefix.bits v4) (v6_of_v4 (V4.Prefix.network v4))
13231323+13241324+ let v4_of_v6 v6 =
13251325+ match v4_of_v6 (V6.Prefix.network v6) with
13261326+ | Some v4 -> Some (V4.Prefix.make (V6.Prefix.bits v6 - 96) v4)
13271327+ | None -> None
13281328+13291329+ let to_v4 = function V4 v4 -> Some v4 | V6 v6 -> v4_of_v6 v6
13301330+ let to_v6 = function V4 v4 -> v6_of_v4 v4 | V6 v6 -> v6
13311331+ let mem ip prefix = V6.Prefix.mem (Addr.to_v6 ip) (to_v6 prefix)
13321332+13331333+ let subset ~subnet ~network =
13341334+ V6.Prefix.subset ~subnet:(to_v6 subnet) ~network:(to_v6 network)
13351335+13361336+ let of_addr = function
13371337+ | V4 p -> V4 (V4.Prefix.of_addr p)
13381338+ | V6 p -> V6 (V6.Prefix.of_addr p)
13391339+13401340+ let to_string = function
13411341+ | V4 p -> V4.Prefix.to_string p
13421342+ | V6 p -> V6.Prefix.to_string p
13431343+13441344+ let to_buffer buf = function
13451345+ | V4 p -> V4.Prefix.to_buffer buf p
13461346+ | V6 p -> V6.Prefix.to_buffer buf p
13471347+13481348+ let network = function
13491349+ | V4 p -> V4 (V4.Prefix.network p)
13501350+ | V6 p -> V6 (V6.Prefix.network p)
13511351+13521352+ let netmask = function
13531353+ | V4 p -> V4 (V4.Prefix.netmask p)
13541354+ | V6 p -> V6 (V6.Prefix.netmask p)
13551355+13561356+ let address = function
13571357+ | V4 p -> V4 (V4.Prefix.address p)
13581358+ | V6 p -> V6 (V6.Prefix.address p)
13591359+13601360+ let bits = function V4 p -> V4.Prefix.bits p | V6 p -> V6.Prefix.bits p
13611361+ let pp ppf i = Format.fprintf ppf "%s" (to_string i)
13621362+13631363+ let first = function
13641364+ | V4 p -> V4 (V4.Prefix.first p)
13651365+ | V6 p -> V6 (V6.Prefix.first p)
13661366+13671367+ let last = function
13681368+ | V4 p -> V4 (V4.Prefix.last p)
13691369+ | V6 p -> V6 (V6.Prefix.last p)
13701370+13711371+ let hosts ?(usable = true) = function
13721372+ | V4 p -> V4 (V4.Prefix.hosts ~usable p)
13731373+ | V6 p -> V6 (V6.Prefix.hosts ~usable p)
13741374+13751375+ let subnets n = function
13761376+ | V4 p -> V4 (V4.Prefix.subnets n p)
13771377+ | V6 p -> V6 (V6.Prefix.subnets n p)
13781378+end
+811
vendor/opam/ipaddr/lib/ipaddr.mli
···11+(*
22+ * Copyright (c) 2019 Anil Madhavapeddy <anil@recoil.org>
33+ * Copyright (c) 2013-2015 David Sheets <sheets@alum.mit.edu>
44+ *
55+ * Permission to use, copy, modify, and distribute this software for any
66+ * purpose with or without fee is hereby granted, provided that the above
77+ * copyright notice and this permission notice appear in all copies.
88+ *
99+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1010+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1111+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1212+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1313+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1414+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1515+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1616+ *
1717+ *)
1818+1919+(** A library for manipulation of IP address representations.
2020+2121+ {e %%VERSION%% - {{:%%PKG_HOMEPAGE%%} homepage}} *)
2222+2323+exception Parse_error of string * string
2424+(** [Parse_error (err,packet)] is raised when parsing of the IP address syntax
2525+ fails. [err] contains a human-readable error and [packet] is the original
2626+ octet list that failed to parse. *)
2727+2828+(** Type of ordered address scope classifications *)
2929+type scope = Point | Interface | Link | Admin | Site | Organization | Global
3030+3131+val string_of_scope : scope -> string
3232+(** [string_of_scope scope] returns a human-readable representation of {!scope}. *)
3333+3434+val scope_of_string : string -> (scope, [> `Msg of string ]) result
3535+(** [scope_of_string s] returns a {!scope} from a string representation of [s].
3636+ Valid string values for [s] can be obtained via {!string_of_scope}. *)
3737+3838+val pp_scope : Format.formatter -> scope -> unit
3939+[@@ocaml.toplevel_printer]
4040+(** [pp_scope fmt scope] outputs a human-readable representation of {!scope} to
4141+ the [fmt] formatter. *)
4242+4343+(** A collection of functions for IPv4 addresses. *)
4444+module V4 : sig
4545+ type t
4646+ (** Type of the internet protocol v4 address of a host *)
4747+4848+ val make : int -> int -> int -> int -> t
4949+ (** Converts the low bytes of four int values into an abstract {!V4.t}. *)
5050+5151+ (** {3 Text string conversion}
5252+5353+ These manipulate human-readable IPv4 addresses (for example
5454+ [192.168.1.2]). *)
5555+5656+ val of_string : string -> (t, [> `Msg of string ]) result
5757+ (** [of_string s] is the address {!t} represented by the human-readable IPv4
5858+ address [s]. Returns a human-readable error string if parsing failed. *)
5959+6060+ val of_string_exn : string -> t
6161+ (** [of_string_exn s] is the address {!t} represented as a human-readable IPv4
6262+ address [s]. Raises {!Parse_error} if [s] is invalid or truncated. *)
6363+6464+ val of_string_raw : string -> int ref -> t
6565+ (** [of_string_raw s off] acts as {!of_string_exn} but takes as an extra
6666+ argument the offset into the string for reading. [off] will be mutated to
6767+ an unspecified value during the function call. [s] will a {!Parse_error}
6868+ exception if it is an invalid or truncated IP address. *)
6969+7070+ val with_port_of_string :
7171+ default:int -> string -> (t * int, [> `Msg of string ]) result
7272+ (** [with_port_of_string ~default s] is the address {!t} represented by the
7373+ human-readble IPv4 address [s] with a possibly port [:<port>] (otherwise,
7474+ we take the [default] value). *)
7575+7676+ val to_string : t -> string
7777+ (** [to_string ipv4] is the dotted decimal string representation of [ipv4],
7878+ i.e. [XXX.XX.X.XXX]. *)
7979+8080+ val to_buffer : Buffer.t -> t -> unit
8181+ (** [to_buffer buf ipv4] writes the string representation of [ipv4] into the
8282+ buffer [buf]. *)
8383+8484+ val pp : Format.formatter -> t -> unit
8585+ [@@ocaml.toplevel_printer]
8686+ (** [pp f ipv4] outputs a human-readable representation of [ipv4] to the
8787+ formatter [f]. *)
8888+8989+ (** {3 Octets conversion}
9090+9191+ These manipulate IPv4 addresses represented as a sequence of four bytes.
9292+ (e.g for example [0xc0a80102] will be the representation of the
9393+ human-readable [192.168.1.2] address. *)
9494+9595+ val of_octets : ?off:int -> string -> (t, [> `Msg of string ]) result
9696+ (** [of_octets ?off s] is the IPv4 address {!t} represented by the octets in
9797+ [s] starting from offset [off] within the string. Returns a human-readable
9898+ error string if [s] is not at least [off+4] bytes long. [off] defaults to
9999+ 0. *)
100100+101101+ val of_octets_exn : ?off:int -> string -> t
102102+ (** [of_octets_exn ipv4_octets] is the IPv4 address represented by
103103+ [ipv4_octets] starting from offset [off]. Raises {!Parse_error} if
104104+ [ipv4_octets] is not at least [off+4] bytes long. [off] defaults to 0. *)
105105+106106+ val write_octets :
107107+ ?off:int -> t -> bytes -> (unit, [> `Msg of string ]) result
108108+ (** [write_octets ?off ipv4 b] writes the [ipv4] as octets to [b] starting
109109+ from offset [off]. [b] must be at least [off+4] long or an error is
110110+ returned. *)
111111+112112+ val write_octets_exn : ?off:int -> t -> bytes -> unit
113113+ (** [write_octets_exn ?off ipv4 b] writes the [ipv4] as octets to [b] starting
114114+ from offset [off]. [b] must be at least [off+4] long or a {!Parse_error}
115115+ is raised. *)
116116+117117+ val to_octets : t -> string
118118+ (** [to_octets ipv4] returns the 4 bytes representing the [ipv4] octets. *)
119119+120120+ (** {3 Int conversion} *)
121121+122122+ val of_int32 : int32 -> t
123123+ (** [of_int32 ipv4_packed] is the address represented by [ipv4_packed]. *)
124124+125125+ val to_int32 : t -> int32
126126+ (** [to_int32 ipv4] is the 32-bit packed encoding of [ipv4]. *)
127127+128128+ val of_int16 : int * int -> t
129129+ (** [of_int16 ipv4_packed] is the address represented by [ipv4_packed]. *)
130130+131131+ val to_int16 : t -> int * int
132132+ (** [to_int16 ipv4] is the 16-bit packed encoding of [ipv4]. *)
133133+134134+ (** {3 MAC conversion} *)
135135+136136+ val multicast_to_mac : t -> Macaddr.t
137137+ (** [multicast_to_mac ipv4] is the MAC address corresponding to the multicast
138138+ address [ipv4]. Described by
139139+ {{:http://tools.ietf.org/html/rfc1112#section-6.2} RFC 1112}. *)
140140+141141+ (** {3 Host conversion} *)
142142+143143+ val to_domain_name : t -> [ `host ] Domain_name.t
144144+ (** [to_domain_name ipv4] is the domain name label list for reverse lookups of
145145+ [ipv4]. This includes the [.in-addr.arpa] suffix. *)
146146+147147+ val of_domain_name : 'a Domain_name.t -> t option
148148+ (** [of_domain_name name] is [Some t] if the [name] has an [.in-addr.arpa]
149149+ suffix, and an IPv4 address prefixed. *)
150150+151151+ (** {3 Utility functions} *)
152152+153153+ val succ : t -> (t, [> `Msg of string ]) result
154154+ (** [succ ipv4] is ip address next to [ipv4]. Returns a human-readable error
155155+ string if it's already the highest address. *)
156156+157157+ val pred : t -> (t, [> `Msg of string ]) result
158158+ (** [pred ipv4] is ip address before [ipv4]. Returns a human-readable error
159159+ string if it's already the lowest address. *)
160160+161161+ (** {3 Common addresses} *)
162162+163163+ val any : t
164164+ (** [any] is 0.0.0.0. *)
165165+166166+ val unspecified : t
167167+ (** [unspecified] is 0.0.0.0. *)
168168+169169+ val broadcast : t
170170+ (** [broadcast] is 255.255.255.255. *)
171171+172172+ val nodes : t
173173+ (** [nodes] is 224.0.0.1. *)
174174+175175+ val routers : t
176176+ (** [routers] is 224.0.0.2. *)
177177+178178+ val localhost : t
179179+ (** [localhost] is 127.0.0.1. *)
180180+181181+ (** A module for manipulating IPv4 network prefixes (CIDR). *)
182182+ module Prefix : sig
183183+ type addr = t
184184+185185+ type t
186186+ (** Type of a internet protocol subnet: an address and prefix length. *)
187187+188188+ val mask : int -> addr
189189+ (** [mask n] is the pseudo-address of an [n] bit subnet mask. *)
190190+191191+ val make : int -> addr -> t
192192+ (** [make n addr] is the cidr of [addr] with [n] bits prefix. *)
193193+194194+ val prefix : t -> t
195195+ (** [prefix cidr] is the subnet prefix of [cidr] where all non-prefix bits
196196+ set to 0. *)
197197+198198+ val network_address : t -> addr -> addr
199199+ (** [network_address cidr addr] is the address with prefix [cidr] and suffix
200200+ from [addr]. See <http://tools.ietf.org/html/rfc4291#section-2.3>. *)
201201+202202+ val of_string : string -> (t, [> `Msg of string ]) result
203203+ (** [of_string cidr] is the subnet prefix represented by the CIDR string,
204204+ [cidr]. Returns a human-readable parsing error message if [cidr] is not
205205+ a valid representation of a CIDR notation routing prefix. *)
206206+207207+ val of_string_exn : string -> t
208208+ (** [of_string_exn cidr] is the subnet prefix represented by the CIDR
209209+ string, [cidr]. Raises [Parse_error] if [cidr] is not a valid
210210+ representation of a CIDR notation routing prefix. *)
211211+212212+ val of_string_raw : string -> int ref -> t
213213+ (** Same as {!of_string_exn} but takes as an extra argument the offset into
214214+ the string for reading. *)
215215+216216+ val to_string : t -> string
217217+ (** [to_string cidr] is the CIDR notation string representation of [cidr],
218218+ i.e. [XXX.XX.X.XXX/XX]. *)
219219+220220+ val pp : Format.formatter -> t -> unit
221221+ [@@ocaml.toplevel_printer]
222222+ (** [pp f cidr] outputs a human-readable representation of [cidr] to the
223223+ formatter [f]. *)
224224+225225+ val to_buffer : Buffer.t -> t -> unit
226226+ (** [to_buffer buf cidr] writes the string representation of [cidr] into the
227227+ buffer [buf]. *)
228228+229229+ val of_netmask_exn : netmask:addr -> address:addr -> t
230230+ (** [of_netmask_exn ~netmask ~address] is the subnet prefix of [address]
231231+ with netmask [netmask]. *)
232232+233233+ val of_netmask :
234234+ netmask:addr -> address:addr -> (t, [> `Msg of string ]) result
235235+ (** [of_netmask ~netmask ~address] is the cidr of [address] with netmask
236236+ [netmask]. *)
237237+238238+ val mem : addr -> t -> bool
239239+ (** [mem ip subnet] checks whether [ip] is found within [subnet]. *)
240240+241241+ val subset : subnet:t -> network:t -> bool
242242+ (** [subset ~subnet ~network] checks whether [subnet] is contained within
243243+ [network]. *)
244244+245245+ val of_addr : addr -> t
246246+ (** [of_addr ip] create a subnet composed of only one address, [ip]. It is
247247+ the same as [make 32 ip]. *)
248248+249249+ val global : t
250250+ (** The default route, all addresses in IPv4-space, 0.0.0.0/0. *)
251251+252252+ val loopback : t
253253+ (** The host loopback network, 127.0.0.0/8. *)
254254+255255+ val link : t
256256+ (** The local-link network, 169.254.0.0/16. *)
257257+258258+ val relative : t
259259+ (** The relative addressing network, 0.0.0.0/8. *)
260260+261261+ val multicast : t
262262+ (** The multicast network, 224.0.0.0/4. *)
263263+264264+ val private_10 : t
265265+ (** The private subnet with 10 as first octet, 10.0.0.0/8. *)
266266+267267+ val private_172 : t
268268+ (** The private subnet with 172 as first octet, 172.16.0.0/12. *)
269269+270270+ val private_192 : t
271271+ (** The private subnet with 192 as first octet, 192.168.0.0/16. *)
272272+273273+ val private_blocks : t list
274274+ (** The privately addressable networks: [loopback], [link], [private_10],
275275+ [private_172], [private_192]. *)
276276+277277+ val broadcast : t -> addr
278278+ (** [broadcast subnet] is the broadcast address for [subnet]. *)
279279+280280+ val network : t -> addr
281281+ (** [network subnet] is the address for [subnet]. *)
282282+283283+ val netmask : t -> addr
284284+ (** [netmask subnet] is the netmask for [subnet]. *)
285285+286286+ val address : t -> addr
287287+ (** [address cidr] is the address for [cidr]. *)
288288+289289+ val bits : t -> int
290290+ (** [bits cidr] is the bit size of the [cidr] prefix. *)
291291+292292+ val first : t -> addr
293293+ (** [first cidr] is first valid unicast address in this [cidr]. *)
294294+295295+ val last : t -> addr
296296+ (** [last cidr] is last valid unicast address in this [cidr]. *)
297297+298298+ val hosts : ?usable:bool -> t -> addr Seq.t
299299+ (** [hosts cidr] is the sequence of host addresses in this [cidr]. By
300300+ default, network and broadcast addresses are omitted. This can be
301301+ changed by setting [usable] to false. *)
302302+303303+ val subnets : int -> t -> t Seq.t
304304+ (** [subnets n cidr] is the sequence of subnets of [cidr] with a prefix
305305+ length of [n]. *)
306306+307307+ include Map.OrderedType with type t := t
308308+ end
309309+310310+ val scope : t -> scope
311311+ (** [scope ipv4] is the classification of [ipv4] by the {!scope} hierarchy. *)
312312+313313+ val is_global : t -> bool
314314+ (** [is_global ipv4] is a predicate indicating whether [ipv4] globally
315315+ addresses a node. *)
316316+317317+ val is_multicast : t -> bool
318318+ (** [is_multicast ipv4] is a predicate indicating whether [ipv4] is a
319319+ multicast address. *)
320320+321321+ val is_private : t -> bool
322322+ (** [is_private ipv4] is a predicate indicating whether [ipv4] privately
323323+ addresses a node. *)
324324+325325+ include Map.OrderedType with type t := t
326326+ module Set : Set.S with type elt := t
327327+ module Map : Map.S with type key := t
328328+end
329329+330330+(** A collection of functions for IPv6 addresses. *)
331331+module V6 : sig
332332+ type t
333333+ (** Type of the internet protocol v6 address of a host *)
334334+335335+ val make : int -> int -> int -> int -> int -> int -> int -> int -> t
336336+ (** Converts the low bytes of eight int values into an abstract {!V6.t}. *)
337337+338338+ (** {3 Text string conversion} *)
339339+340340+ val of_string : string -> (t, [> `Msg of string ]) result
341341+ (** [of_string ipv6_string] is the address represented by the human-readable
342342+ IPv6 address [ipv6_string]. Returns a human-readable error string if
343343+ parsing failed. *)
344344+345345+ val of_string_exn : string -> t
346346+ (** [of_string_exn ipv6_string] is the address represented by the
347347+ human-readable IPv6 address [ipv6_string]. Raises {!Parse_error} if
348348+ [ipv6_string] is invalid or truncated. *)
349349+350350+ val with_port_of_string :
351351+ default:int -> string -> (t * int, [> `Msg of string ]) result
352352+ (** [with_port_of_string ~default ipv6_string] is the address represented by
353353+ [ipv6_string] with a possibly [:<port>] (otherwise, we take the [default]
354354+ value). Due to the [':'] separator, the user should expand [ipv6_string]
355355+ to let us to consider the last [:<port>] as a port. In other words:
356356+357357+ - [::1:8080] returns the IPv6 [::1:8080] with the [default] port
358358+ - [0:0:0:0:0:0:0:1:8080] returns [::1] with the port [8080]. *)
359359+360360+ val of_string_raw : string -> int ref -> t
361361+ (** Same as [of_string_exn] but takes as an extra argument the offset into the
362362+ string for reading. [off] will be mutated to an unspecified value during
363363+ the function call. Raises {!Parse_error} if it is an invalid or truncated
364364+ IP address. *)
365365+366366+ val to_string : t -> string
367367+ (** [to_string ipv6] is the string representation of [ipv6], i.e.
368368+ [XXX:XX:X::XXX:XX]. *)
369369+370370+ val to_buffer : Buffer.t -> t -> unit
371371+ (** [to_buffer buf ipv6] writes the string representation of [ipv6] into the
372372+ buffer [buf]. *)
373373+374374+ val pp : Format.formatter -> t -> unit
375375+ [@@ocaml.toplevel_printer]
376376+ (** [pp f ipv6] outputs a human-readable representation of [ipv6] to the
377377+ formatter [f]. *)
378378+379379+ (** {3 Octets conversion} *)
380380+381381+ val of_octets : ?off:int -> string -> (t, [> `Msg of string ]) result
382382+ (** [of_octets ?off s] is the IPv6 address {!t} represented by the octets [s]
383383+ starting from offset [off] within the string. Returns a human-readable
384384+ error string if [s] is not at least [off+16] bytes long. [off] defaults to
385385+ 0. *)
386386+387387+ val of_octets_exn : ?off:int -> string -> t
388388+ (** [of_octets_exn ?off ipv6_octets] is the IPv6 address represented by
389389+ [ipv6_octets], starting from offset [off]. Raises {!Parse_error} if
390390+ [ipv6_octets] is not at least [off+16] bytes long. [off] defaults to 0. *)
391391+392392+ val write_octets_exn : ?off:int -> t -> bytes -> unit
393393+ (** [write_octets_exn ?off ipv6 b] writes 16 bytes that encode [ipv6] into [b]
394394+ starting from offset [off] within [b]. [b] must be at least [off+16] bytes
395395+ long or a {!Parse_error} exception will be raised. *)
396396+397397+ val write_octets :
398398+ ?off:int -> t -> bytes -> (unit, [> `Msg of string ]) result
399399+ (** [write_octets ?off ipv6 b] writes 16 bytes that encode [ipv6] into [b]
400400+ starting from offset [off] within [b]. [b] must be at least [off+16] bytes
401401+ long or an error is returned. *)
402402+403403+ val to_octets : t -> string
404404+ (** [to_octets ipv6] returns the 16 bytes representing the [ipv6] octets. *)
405405+406406+ (** {3 Int conversion} *)
407407+408408+ val of_int64 : int64 * int64 -> t
409409+ (** [of_int64 (ho, lo)] is the IPv6 address represented by two int64. *)
410410+411411+ val to_int64 : t -> int64 * int64
412412+ (** [to_int64 ipv6] is the 128-bit packed encoding of [ipv6]. *)
413413+414414+ val of_int32 : int32 * int32 * int32 * int32 -> t
415415+ (** [of_int32 (a, b, c, d)] is the IPv6 address represented by four int32. *)
416416+417417+ val to_int32 : t -> int32 * int32 * int32 * int32
418418+ (** [to_int32 ipv6] is the 128-bit packed encoding of [ipv6]. *)
419419+420420+ val of_int16 : int * int * int * int * int * int * int * int -> t
421421+ (** [of_int16 (a, b, c, d, e, f, g, h)] is the IPv6 address represented by
422422+ eight 16-bit int. *)
423423+424424+ val to_int16 : t -> int * int * int * int * int * int * int * int
425425+ (** [to_int16 ipv6] is the 128-bit packed encoding of [ipv6]. *)
426426+427427+ (** {3 MAC conversion} *)
428428+429429+ val multicast_to_mac : t -> Macaddr.t
430430+ (** [multicast_to_mac ipv6] is the MAC address corresponding to the multicast
431431+ address [ipv6]. Described by
432432+ {{:https://tools.ietf.org/html/rfc2464#section-7} RFC 2464}. *)
433433+434434+ (** {3 Host conversion} *)
435435+436436+ val to_domain_name : t -> [ `host ] Domain_name.t
437437+ (** [to_domain_name ipv6] is the domain name label list for reverse lookups of
438438+ [ipv6]. This includes the [.ip6.arpa] suffix. *)
439439+440440+ val of_domain_name : 'a Domain_name.t -> t option
441441+ (** [of_domain_name name] is [Some t] if the [name] has an [.ip6.arpa] suffix,
442442+ and an IPv6 address prefixed. *)
443443+444444+ (** {3 Utility functions} *)
445445+446446+ val succ : t -> (t, [> `Msg of string ]) result
447447+ (** [succ ipv6] is ip address next to [ipv6]. Returns a human-readable error
448448+ string if it's already the highest address. *)
449449+450450+ val pred : t -> (t, [> `Msg of string ]) result
451451+ (** [pred ipv6] is ip address before [ipv6]. Returns a human-readable error
452452+ string if it's already the lowest address. *)
453453+454454+ (** {3 Common addresses} *)
455455+456456+ val unspecified : t
457457+ (** [unspecified] is ::. *)
458458+459459+ val localhost : t
460460+ (** [localhost] is ::1. *)
461461+462462+ val interface_nodes : t
463463+ (** [interface_nodes] is ff01::01. *)
464464+465465+ val link_nodes : t
466466+ (** [link_nodes] is ff02::01. *)
467467+468468+ val interface_routers : t
469469+ (** [interface_routers] is ff01::02. *)
470470+471471+ val link_routers : t
472472+ (** [link_routers] is ff02::02. *)
473473+474474+ val site_routers : t
475475+ (** [site_routers] is ff05::02. *)
476476+477477+ (** A module for manipulating IPv6 network prefixes (CIDR). *)
478478+ module Prefix : sig
479479+ type addr = t
480480+481481+ type t
482482+ (** Type of a internet protocol subnet: an address and a prefix length. *)
483483+484484+ val mask : int -> addr
485485+ (** [mask n] is the pseudo-address of an [n] bit subnet mask. *)
486486+487487+ val make : int -> addr -> t
488488+ (** [make n addr] is the cidr of [addr] with [n] bit prefix. *)
489489+490490+ val prefix : t -> t
491491+ (** [prefix cidr] is the subnet prefix of [cidr] where all non-prefix bits
492492+ set to 0. *)
493493+494494+ val network_address : t -> addr -> addr
495495+ (** [network_address cidr addr] is the address with prefix [cidr] and suffix
496496+ from [addr]. See <http://tools.ietf.org/html/rfc4291#section-2.3>. *)
497497+498498+ val of_string_exn : string -> t
499499+ (** [of_string_exn cidr] is the subnet prefix represented by the CIDR
500500+ string, [cidr]. Raises {!Parse_error} if [cidr] is not a valid
501501+ representation of a CIDR notation routing prefix. *)
502502+503503+ val of_string : string -> (t, [> `Msg of string ]) result
504504+ (** Same as {!of_string_exn} but returns a result type instead of raising an
505505+ exception. *)
506506+507507+ val of_string_raw : string -> int ref -> t
508508+ (** Same as {!of_string_exn} but takes as an extra argument the offset into
509509+ the string for reading. *)
510510+511511+ val to_string : t -> string
512512+ (** [to_string cidr] is the CIDR notation string representation of [cidr],
513513+ i.e. XXX:XX:X::XXX/XX. *)
514514+515515+ val pp : Format.formatter -> t -> unit
516516+ [@@ocaml.toplevel_printer]
517517+ (** [pp f cidr] outputs a human-readable representation of [cidr] to the
518518+ formatter [f]. *)
519519+520520+ val to_buffer : Buffer.t -> t -> unit
521521+ (** [to_buffer buf cidr] writes the string representation of [cidr] to the
522522+ buffer [buf]. *)
523523+524524+ val of_netmask_exn : netmask:addr -> address:addr -> t
525525+ (** [of_netmask_exn ~netmask ~address] is the subnet prefix of [address]
526526+ with netmask [netmask]. *)
527527+528528+ val of_netmask :
529529+ netmask:addr -> address:addr -> (t, [> `Msg of string ]) result
530530+ (** [of_netmask ~netmask ~address] is the cidr of [address] with netmask
531531+ [netmask]. *)
532532+533533+ val mem : addr -> t -> bool
534534+ (** [mem ip subnet] checks whether [ip] is found within [subnet]. *)
535535+536536+ val subset : subnet:t -> network:t -> bool
537537+ (** [subset ~subnet ~network] checks whether [subnet] is contained within
538538+ [network]. *)
539539+540540+ val of_addr : addr -> t
541541+ (** [of_addr ip] create a subnet composed of only one address, [ip]. It is
542542+ the same as [make 128 ip]. *)
543543+544544+ val global_unicast_001 : t
545545+ (** Global Unicast 001, 2000::/3. *)
546546+547547+ val unique_local : t
548548+ (** The Unique Local Unicast (ULA), fc00::/7. *)
549549+550550+ val link : t
551551+ (** Link-Local Unicast, fe80::/64. *)
552552+553553+ val multicast : t
554554+ (** The multicast network, ff00::/8. *)
555555+556556+ val ipv4_mapped : t
557557+ (** IPv4-mapped addresses, ::ffff:0:0/96. *)
558558+559559+ val noneui64_interface : t
560560+ (** Global Unicast addresses that don't use Modified EUI64 interface
561561+ identifiers, ::/3. *)
562562+563563+ val solicited_node : t
564564+ (** Solicited-Node multicast addresses *)
565565+566566+ val network : t -> addr
567567+ (** [network subnet] is the address for [subnet]. *)
568568+569569+ val netmask : t -> addr
570570+ (** [netmask subnet] is the netmask for [subnet]. *)
571571+572572+ val address : t -> addr
573573+ (** [address cidr] is the address for [cidr]. *)
574574+575575+ val bits : t -> int
576576+ (** [bits subnet] is the bit size of the [subnet] prefix. *)
577577+578578+ val first : t -> addr
579579+ (** [first subnet] is first valid unicast address in this [subnet]. *)
580580+581581+ val last : t -> addr
582582+ (** [last subnet] is last valid unicast address in this [subnet]. *)
583583+584584+ val hosts : ?usable:bool -> t -> addr Seq.t
585585+ (** [hosts subnet] is the sequence of host addresses in this [subnet]. By
586586+ default the Subnet-Router anycast address is omitted. This can be
587587+ changed by setting [usable] to false. *)
588588+589589+ val subnets : int -> t -> t Seq.t
590590+ (** [subnets n subnet] is the sequence of subnets of [subnet] with a prefix
591591+ length of [n]. *)
592592+593593+ include Map.OrderedType with type t := t
594594+ end
595595+596596+ val scope : t -> scope
597597+ (** [scope ipv6] is the classification of [ipv6] by the {!scope} hierarchy. *)
598598+599599+ val link_address_of_mac : Macaddr.t -> t
600600+ (** [link_address_of_mac mac] is the link-local address for an Ethernet
601601+ interface derived by the IEEE MAC -> EUI-64 map with the Universal/Local
602602+ bit complemented for IPv6.
603603+604604+ @see <https://tools.ietf.org/html/rfc2464#section-4> RFC 2464 *)
605605+606606+ val is_global : t -> bool
607607+ (** [is_global ipv6] is a predicate indicating whether [ipv6] globally
608608+ addresses a node. *)
609609+610610+ val is_multicast : t -> bool
611611+ (** [is_multicast ipv6] is a predicate indicating whether [ipv6] is a
612612+ multicast address. *)
613613+614614+ val is_private : t -> bool
615615+ (** [is_private ipv6] is a predicate indicating whether [ipv6] privately
616616+ addresses a node. *)
617617+618618+ include Map.OrderedType with type t := t
619619+ module Set : Set.S with type elt := t
620620+ module Map : Map.S with type key := t
621621+end
622622+623623+(** Type of either an IPv4 value or an IPv6 value *)
624624+type ('v4, 'v6) v4v6 = V4 of 'v4 | V6 of 'v6
625625+626626+type t = (V4.t, V6.t) v4v6
627627+(** Type of any IP address *)
628628+629629+val to_string : t -> string
630630+(** [to_string addr] is the text string representation of [addr]. *)
631631+632632+val to_buffer : Buffer.t -> t -> unit
633633+(** [to_buffer buf addr] writes the text string representation of [addr] into
634634+ [buf]. *)
635635+636636+val pp : Format.formatter -> t -> unit
637637+[@@ocaml.toplevel_printer]
638638+(** [pp f ip] outputs a human-readable representation of [ip] to the formatter
639639+ [f]. *)
640640+641641+val of_string_exn : string -> t
642642+(** [of_string_exn s] parses [s] as an IPv4 or IPv6 address. Raises
643643+ {!Parse_error} if [s] is not a valid string representation of an IP address. *)
644644+645645+val of_string : string -> (t, [> `Msg of string ]) result
646646+(** Same as {!of_string_exn} but returns a result type instead of raising an
647647+ exception. *)
648648+649649+val of_string_raw : string -> int ref -> t
650650+(** Same as [of_string_exn] but takes as an extra argument the offset into the
651651+ string for reading. *)
652652+653653+val with_port_of_string :
654654+ default:int -> string -> (t * int, [> `Msg of string ]) result
655655+(** [with_port_of_string ~default s] parses [s] as an IPv4 or IPv6 address with
656656+ a possible port seperated by a [':'] (if not, we use [default]). For IPv6,
657657+ due to the [':'] separator, only a full expansion of the IPv6 plus the port
658658+ lets us to interpret the last [:<int>] as the port. In other words:
659659+660660+ - [::1:8080] returns the IPv6 [::1:8080] with the [default] port
661661+ - [0:0:0:0:0:0:0:1:8080] returns [::1] with the port [8080]. *)
662662+663663+val of_octets_exn : string -> t
664664+(** [of_octets_exn octets] is the address {!t} represented by [octets]. The
665665+ [octets] must be 4 bytes long for a {!V4} or 16 if a {!V6}. Raises
666666+ {!Parse_error} if [octets] is not a valid representation of an address. *)
667667+668668+val of_octets : string -> (t, [> `Msg of string ]) result
669669+(** Same as {!of_octets_exn} but returns a result type instead of raising an
670670+ exception. *)
671671+672672+val to_octets : t -> string
673673+(** [to_octets addr] returns the bytes representing the [addr] octets, which
674674+ will be 4 bytes long if addr is a {!V4} or 16 if a {!V6}. *)
675675+676676+val v4_of_v6 : V6.t -> V4.t option
677677+(** [v4_of_v6 ipv6] is the IPv4 representation of the IPv6 address [ipv6]. If
678678+ [ipv6] is not an IPv4-mapped address, None is returned. *)
679679+680680+val to_v4 : t -> V4.t option
681681+(** [to_v4 addr] is the IPv4 representation of [addr]. *)
682682+683683+val v6_of_v4 : V4.t -> V6.t
684684+(** [v6_of_v4 ipv4] is the IPv6 representation of the IPv4 address [ipv4]. *)
685685+686686+val to_v6 : t -> V6.t
687687+(** [to_v6 addr] is the IPv6 representation of [addr]. *)
688688+689689+val scope : t -> scope
690690+(** [scope addr] is the classification of [addr] by the {!scope} hierarchy. *)
691691+692692+val is_global : t -> bool
693693+(** [is_global addr] is a predicate indicating whether [addr] globally addresses
694694+ a node. *)
695695+696696+val is_multicast : t -> bool
697697+(** [is_multicast addr] is a predicate indicating whether [addr] is a multicast
698698+ address. *)
699699+700700+val is_private : t -> bool
701701+(** [is_private addr] is a predicate indicating whether [addr] privately
702702+ addresses a node. *)
703703+704704+val multicast_to_mac : t -> Macaddr.t
705705+(** [multicast_to_mac addr] is the MAC address corresponding to the multicast
706706+ address [addr]. See {!V4.multicast_to_mac} and {!V6.multicast_to_mac}.*)
707707+708708+val to_domain_name : t -> [ `host ] Domain_name.t
709709+(** [to_domain_name addr] is the domain name label list for reverse lookups of
710710+ [addr]. This includes the [.in-addr.arpa] or [.ip6.arpa] suffix. *)
711711+712712+val of_domain_name : 'a Domain_name.t -> t option
713713+(** [of_domain_name name] is [Some t] if the [name] has an [.in-addr.arpa] or
714714+ [ip6.arpa] suffix, and an IP address prefixed. *)
715715+716716+val succ : t -> (t, [> `Msg of string ]) result
717717+(** [succ addr] is ip address next to [addr]. Returns a human-readable error
718718+ string if it's already the highest address. *)
719719+720720+val pred : t -> (t, [> `Msg of string ]) result
721721+(** [pred addr] is ip address before [addr]. Returns a human-readable error
722722+ string if it's already the lowest address. *)
723723+724724+module Prefix : sig
725725+ type addr = t
726726+727727+ type t = (V4.Prefix.t, V6.Prefix.t) v4v6
728728+ (** Type of a internet protocol subnet *)
729729+730730+ val to_string : t -> string
731731+ (** [to_string subnet] is the text string representation of [subnet]. *)
732732+733733+ val to_buffer : Buffer.t -> t -> unit
734734+ (** [to_buffer buf subnet] writes the text string representation of [subnet]
735735+ into [buf]. *)
736736+737737+ val pp : Format.formatter -> t -> unit
738738+ [@@ocaml.toplevel_printer]
739739+ (** [pp f subnet] outputs a human-readable representation of [subnet] to the
740740+ formatter [f]. *)
741741+742742+ val of_string_exn : string -> t
743743+ (** [of_string_exn cidr] is the subnet prefix represented by the CIDR string,
744744+ [cidr]. Raises {!Parse_error} if [cidr] is not a valid representation of a
745745+ CIDR notation routing prefix. *)
746746+747747+ val of_string : string -> (t, [> `Msg of string ]) result
748748+ (** Same as {!of_string_exn} but returns a result type instead of raising an
749749+ exception. *)
750750+751751+ val of_string_raw : string -> int ref -> t
752752+ (** Same as {!of_string_exn} but takes as an extra argument the offset into
753753+ the string for reading. *)
754754+755755+ val v4_of_v6 : V6.Prefix.t -> V4.Prefix.t option
756756+ (** [v4_of_v6 ipv6] is the IPv4 representation of the IPv6 subnet [ipv6]. If
757757+ [ipv6] is not an IPv4-mapped subnet, None is returned. *)
758758+759759+ val to_v4 : t -> V4.Prefix.t option
760760+ (** [to_v4 subnet] is the IPv4 representation of [subnet]. *)
761761+762762+ val v6_of_v4 : V4.Prefix.t -> V6.Prefix.t
763763+ (** [v6_of_v4 ipv4] is the IPv6 representation of the IPv4 subnet [ipv4]. *)
764764+765765+ val to_v6 : t -> V6.Prefix.t
766766+ (** [to_v6 subnet] is the IPv6 representation of [subnet]. *)
767767+768768+ val mem : addr -> t -> bool
769769+ (** [mem ip subnet] checks whether [ip] is found within [subnet]. *)
770770+771771+ val subset : subnet:t -> network:t -> bool
772772+ (** [subset ~subnet ~network] checks whether [subnet] is contained within
773773+ [network]. *)
774774+775775+ val of_addr : addr -> t
776776+ (** [of_addr ip] create a subnet composed of only one address, [ip].*)
777777+778778+ val network : t -> addr
779779+ (** [network subnet] is the address for [subnet]. *)
780780+781781+ val netmask : t -> addr
782782+ (** [netmask subnet] is the netmask for [subnet]. *)
783783+784784+ val address : t -> addr
785785+ (** [address cidr] is the address for [cidr]. *)
786786+787787+ val bits : t -> int
788788+ (** [bits cidr] is the bit size of the [cidr] prefix. *)
789789+790790+ val first : t -> addr
791791+ (** [first subnet] is first valid unicast address in this [subnet]. *)
792792+793793+ val last : t -> addr
794794+ (** [last subnet] is last valid unicast address in this [subnet]. *)
795795+796796+ val hosts : ?usable:bool -> t -> (V4.t Seq.t, V6.t Seq.t) v4v6
797797+ (** [hosts cidr] is the sequence of host addresses in this [cidr]. By default,
798798+ the network and broadcast addresses are omitted for IPv4. In the case of
799799+ IPv6, the Subnet-Router anycast address is omitted by default. This can be
800800+ changed by setting [usable] to false. *)
801801+802802+ val subnets : int -> t -> (V4.Prefix.t Seq.t, V6.Prefix.t Seq.t) v4v6
803803+ (** [subnets n cidr] is the sequence of subnets of [cidr] with a prefix length
804804+ of [n]. *)
805805+806806+ include Map.OrderedType with type t := t
807807+end
808808+809809+include Map.OrderedType with type t := t
810810+module Set : Set.S with type elt := t
811811+module Map : Map.S with type key := t
+63
vendor/opam/ipaddr/lib/ipaddr_cstruct.ml
···11+(*
22+ * Copyright (c) 2019 Anil Madhavapeddy
33+ * Copyright (c) 2014 Nicolás Ojeda Bär
44+ *
55+ * Permission to use, copy, modify, and distribute this software for any
66+ * purpose with or without fee is hereby granted, provided that the above
77+ * copyright notice and this permission notice appear in all copies.
88+ *
99+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1010+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1111+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1212+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1313+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1414+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1515+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1616+ *
1717+ *)
1818+1919+let need_more x = Ipaddr.Parse_error ("not enough data", x)
2020+2121+let try_with_result fn a =
2222+ try Ok (fn a)
2323+ with Ipaddr.Parse_error (msg, _) -> Error (`Msg ("Ipaddr: " ^ msg))
2424+2525+module V4 = struct
2626+ let of_cstruct_exn cs =
2727+ let len = Cstruct.length cs in
2828+ if len < 4 then raise (need_more (Cstruct.to_string cs));
2929+ Ipaddr.V4.of_int32 (Cstruct.BE.get_uint32 cs 0)
3030+3131+ let of_cstruct cs = try_with_result of_cstruct_exn cs
3232+3333+ let write_cstruct_exn i cs =
3434+ let len = Cstruct.length cs in
3535+ if len < 4 then raise (need_more (Cstruct.to_string cs));
3636+ Cstruct.BE.set_uint32 cs 0 (Ipaddr.V4.to_int32 i)
3737+3838+ let to_cstruct ?(allocator = Cstruct.create) i =
3939+ let cs = allocator 4 in
4040+ write_cstruct_exn i cs;
4141+ cs
4242+end
4343+4444+module V6 = struct
4545+ open Ipaddr.V6
4646+4747+ let of_cstruct_exn cs =
4848+ let len = Cstruct.length cs in
4949+ if len < 16 then raise (need_more (Cstruct.to_string cs));
5050+ of_octets_exn (Cstruct.to_string ~len:16 cs)
5151+5252+ let of_cstruct cs = try_with_result of_cstruct_exn cs
5353+5454+ let write_cstruct_exn i cs =
5555+ let len = Cstruct.length cs in
5656+ if len < 16 then raise (need_more (Cstruct.to_string cs));
5757+ Cstruct.blit_from_string (to_octets i) 0 cs 0 16
5858+5959+ let to_cstruct ?(allocator = Cstruct.create) i =
6060+ let cs = allocator 16 in
6161+ write_cstruct_exn i cs;
6262+ cs
6363+end
+59
vendor/opam/ipaddr/lib/ipaddr_cstruct.mli
···11+(*
22+ * Copyright (c) 2019 Anil Madhavapeddy
33+ * Copyright (c) 2014 Nicolás Ojeda Bär
44+ *
55+ * Permission to use, copy, modify, and distribute this software for any
66+ * purpose with or without fee is hereby granted, provided that the above
77+ * copyright notice and this permission notice appear in all copies.
88+ *
99+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1010+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1111+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1212+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1313+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1414+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1515+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1616+ *
1717+ *)
1818+1919+(** Convert to and from Cstructs and IP addresses *)
2020+2121+(** Ipv4 address conversions *)
2222+module V4 : sig
2323+ val of_cstruct : Cstruct.t -> (Ipaddr.V4.t, [> `Msg of string ]) result
2424+ (** [of_cstruct c] parses the first 4 octets of [c] into an IPv4 address. *)
2525+2626+ val of_cstruct_exn : Cstruct.t -> Ipaddr.V4.t
2727+ (** [of_cstruct_exn] parses the first 4 octets of [c] into an IPv4 address.
2828+ Raises {!Ipaddr.Parse_failure} on error. *)
2929+3030+ val to_cstruct : ?allocator:(int -> Cstruct.t) -> Ipaddr.V4.t -> Cstruct.t
3131+ (** [to_cstruct ipv4] is a cstruct of length 4 encoding [ipv4]. The cstruct is
3232+ allocated using [allocator]. If [allocator] is not provided,
3333+ [Cstruct.create] is used. *)
3434+3535+ val write_cstruct_exn : Ipaddr.V4.t -> Cstruct.t -> unit
3636+ (** [write_cstruct_exn ipv4 cs] writes 4 bytes into [cs] representing the
3737+ [ipv4] address octets. Raises {!Ipaddr.Parse_error} if [cs] is not at
3838+ least 4 bytes long. *)
3939+end
4040+4141+(** Ipv6 address conversions *)
4242+module V6 : sig
4343+ val of_cstruct : Cstruct.t -> (Ipaddr.V6.t, [> `Msg of string ]) result
4444+ (** [of_cstruct c] parses the first 16 octets of [c] into an IPv6 address. *)
4545+4646+ val of_cstruct_exn : Cstruct.t -> Ipaddr.V6.t
4747+ (** [of_cstruct_exn] parses the first 16 octets of [c] into an IPv6 address.
4848+ Raises {!Ipaddr.Parse_failure} on error. *)
4949+5050+ val to_cstruct : ?allocator:(int -> Cstruct.t) -> Ipaddr.V6.t -> Cstruct.t
5151+ (** [to_cstruct ipv6] is a cstruct of length 16 encoding [ipv6]. The cstruct
5252+ is allocated using [allocator]. If [allocator] is not provided,
5353+ [Cstruct.create] is used. *)
5454+5555+ val write_cstruct_exn : Ipaddr.V6.t -> Cstruct.t -> unit
5656+ (** [write_cstruct_exn ipv6 cs] writes 16 bytes into [cs] representing the
5757+ [ipv6] address octets. Raises {!Ipaddr.Parse_error} if [cs] is not at
5858+ least 16 bytes long. *)
5959+end
+91
vendor/opam/ipaddr/lib/ipaddr_sexp.ml
···11+(*
22+ * Copyright (c) 2018 Anil Madhavapeddy <anil@recoil.org>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ *
1616+ *)
1717+1818+open Sexplib0
1919+2020+let of_sexp fn = function
2121+ | Sexp.List _ -> failwith "expecting sexp atom"
2222+ | Sexp.Atom s -> (
2323+ match fn s with Ok r -> r | Error (`Msg msg) -> failwith msg)
2424+2525+let to_sexp fn t = Sexp.Atom (fn t)
2626+2727+module V4 = struct
2828+ module I = Ipaddr.V4
2929+3030+ type t = I.t
3131+3232+ let sexp_of_t = to_sexp I.to_string
3333+ let t_of_sexp = of_sexp I.of_string
3434+ let compare = I.compare
3535+3636+ module Prefix = struct
3737+ module I = Ipaddr.V4.Prefix
3838+3939+ type addr = I.addr
4040+ type t = I.t
4141+4242+ let sexp_of_t = to_sexp I.to_string
4343+ let t_of_sexp = of_sexp I.of_string
4444+ let compare = I.compare
4545+ end
4646+end
4747+4848+module V6 = struct
4949+ module I = Ipaddr.V6
5050+5151+ type t = I.t
5252+5353+ let sexp_of_t = to_sexp I.to_string
5454+ let t_of_sexp = of_sexp I.of_string
5555+ let compare = I.compare
5656+5757+ module Prefix = struct
5858+ module I = Ipaddr.V6.Prefix
5959+6060+ type addr = I.addr
6161+ type t = I.t
6262+6363+ let sexp_of_t = to_sexp I.to_string
6464+ let t_of_sexp = of_sexp I.of_string
6565+ let compare = I.compare
6666+ end
6767+end
6868+6969+module I = Ipaddr
7070+7171+type t = I.t
7272+7373+let sexp_of_t = to_sexp I.to_string
7474+let t_of_sexp = of_sexp I.of_string
7575+let compare = I.compare
7676+7777+type scope = I.scope
7878+7979+let sexp_of_scope = to_sexp I.string_of_scope
8080+let scope_of_sexp = of_sexp I.scope_of_string
8181+8282+module Prefix = struct
8383+ module I = Ipaddr.Prefix
8484+8585+ type addr = I.addr
8686+ type t = I.t
8787+8888+ let sexp_of_t = to_sexp I.to_string
8989+ let t_of_sexp = of_sexp I.of_string
9090+ let compare = I.compare
9191+end
+92
vendor/opam/ipaddr/lib/ipaddr_sexp.mli
···11+(*
22+ * Copyright (c) 2018 Anil Madhavapeddy <anil@recoil.org>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ *
1616+ *)
1717+1818+(** serialisers to and from {!Ipaddr} and s-expression {!Sexplib0} format
1919+2020+ To use these with ppx-based derivers, simply replace the reference to the
2121+ {!Ipaddr} type definition with {!Ipaddr_sexp} instead. That will import the
2222+ sexp-conversion functions, and the actual type definitions are simply
2323+ aliases to the corresponding type within {!Ipaddr}. For example, you might
2424+ do:
2525+2626+ {[
2727+ type t = { ip : Ipaddr_sexp.t; mac : Macaddr_sexp.t } [@@deriving sexp]
2828+ ]}
2929+3030+ The actual types of the records will be aliases to the main library types,
3131+ and there will be two new functions available as converters.
3232+3333+ {[
3434+ type t = { ip : Ipaddr.t; mac : Macaddr.t }
3535+3636+ val sexp_of_t : t -> Sexplib0.t
3737+ val t_of_sexp : Sexplib0.t -> t
3838+ ]} *)
3939+4040+type t = Ipaddr.t
4141+4242+val sexp_of_t : Ipaddr.t -> Sexplib0.Sexp.t
4343+val t_of_sexp : Sexplib0.Sexp.t -> Ipaddr.t
4444+val compare : Ipaddr.t -> Ipaddr.t -> int
4545+4646+type scope = Ipaddr.scope
4747+4848+val sexp_of_scope : Ipaddr.scope -> Sexplib0.Sexp.t
4949+val scope_of_sexp : Sexplib0.Sexp.t -> Ipaddr.scope
5050+5151+module V4 : sig
5252+ type t = Ipaddr.V4.t
5353+5454+ val sexp_of_t : Ipaddr.V4.t -> Sexplib0.Sexp.t
5555+ val t_of_sexp : Sexplib0.Sexp.t -> Ipaddr.V4.t
5656+ val compare : Ipaddr.V4.t -> Ipaddr.V4.t -> int
5757+5858+ module Prefix : sig
5959+ type addr = Ipaddr.V4.Prefix.addr
6060+ type t = Ipaddr.V4.Prefix.t
6161+6262+ val sexp_of_t : Ipaddr.V4.Prefix.t -> Sexplib0.Sexp.t
6363+ val t_of_sexp : Sexplib0.Sexp.t -> Ipaddr.V4.Prefix.t
6464+ val compare : Ipaddr.V4.Prefix.t -> Ipaddr.V4.Prefix.t -> int
6565+ end
6666+end
6767+6868+module V6 : sig
6969+ type t = Ipaddr.V6.t
7070+7171+ val sexp_of_t : Ipaddr.V6.t -> Sexplib0.Sexp.t
7272+ val t_of_sexp : Sexplib0.Sexp.t -> Ipaddr.V6.t
7373+ val compare : Ipaddr.V6.t -> Ipaddr.V6.t -> int
7474+7575+ module Prefix : sig
7676+ type addr = Ipaddr.V6.Prefix.addr
7777+ type t = Ipaddr.V6.Prefix.t
7878+7979+ val sexp_of_t : Ipaddr.V6.Prefix.t -> Sexplib0.Sexp.t
8080+ val t_of_sexp : Sexplib0.Sexp.t -> Ipaddr.V6.Prefix.t
8181+ val compare : Ipaddr.V6.Prefix.t -> Ipaddr.V6.Prefix.t -> int
8282+ end
8383+end
8484+8585+module Prefix : sig
8686+ type addr = Ipaddr.Prefix.addr
8787+ type t = Ipaddr.Prefix.t
8888+8989+ val sexp_of_t : Ipaddr.Prefix.t -> Sexplib0.Sexp.t
9090+ val t_of_sexp : Sexplib0.Sexp.t -> Ipaddr.Prefix.t
9191+ val compare : Ipaddr.Prefix.t -> Ipaddr.Prefix.t -> int
9292+end
+26
vendor/opam/ipaddr/lib/ipaddr_top.ml
···11+let printers =
22+ [
33+ "Ipaddr.pp";
44+ "Ipaddr.Prefix.pp";
55+ "Ipaddr.V4.pp";
66+ "Ipaddr.V4.Prefix.pp";
77+ "Ipaddr.V6.pp";
88+ "Ipaddr.V6.Prefix.pp";
99+ "Macaddr.pp";
1010+ ]
1111+1212+let eval_string ?(print_outcome = false) ?(err_formatter = Format.err_formatter)
1313+ str =
1414+ let lexbuf = Lexing.from_string str in
1515+ let phrase = !Toploop.parse_toplevel_phrase lexbuf in
1616+ Toploop.execute_phrase print_outcome err_formatter phrase
1717+1818+let rec install_printers = function
1919+ | [] -> true
2020+ | printer :: printers ->
2121+ let cmd = Printf.sprintf "#install_printer %s;;" printer in
2222+ eval_string cmd && install_printers printers
2323+2424+let () =
2525+ if not (install_printers printers) then
2626+ Format.eprintf "Problem installing Ipaddr-printers@."
···11+(*
22+ * Copyright (c) 2014 Anil Madhavapeddy <anil@recoil.org>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ *
1616+ *)
1717+1818+let to_inet_addr t = Unix.inet_addr_of_string (Ipaddr.to_string t)
1919+let of_inet_addr t = Ipaddr.of_string_exn (Unix.string_of_inet_addr t)
2020+2121+module V4 = struct
2222+ let to_inet_addr t = Unix.inet_addr_of_string (Ipaddr.V4.to_string t)
2323+ let of_inet_addr_exn t = Ipaddr.V4.of_string_exn (Unix.string_of_inet_addr t)
2424+ let of_inet_addr t = try Some (of_inet_addr_exn t) with _ -> None
2525+end
2626+2727+module V6 = struct
2828+ let to_inet_addr t = Unix.inet_addr_of_string (Ipaddr.V6.to_string t)
2929+ let of_inet_addr_exn t = Ipaddr.V6.of_string_exn (Unix.string_of_inet_addr t)
3030+ let of_inet_addr t = try Some (of_inet_addr_exn t) with _ -> None
3131+end
+58
vendor/opam/ipaddr/lib/ipaddr_unix.mli
···11+(*
22+ * Copyright (c) 2014 Anil Madhavapeddy <anil@recoil.org>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ *
1616+ *)
1717+1818+(** Convert to and from [Unix] to [Ipaddr] representations
1919+2020+ {e %%VERSION%% - {{:%%PKG_HOMEPAGE%%} homepage}} *)
2121+2222+val to_inet_addr : Ipaddr.t -> Unix.inet_addr
2323+(** [to_inet_addr ip] is the {!Unix.inet_addr} equivalent of the IPv4 or IPv6
2424+ address [ip]. *)
2525+2626+val of_inet_addr : Unix.inet_addr -> Ipaddr.t
2727+(** [of_inet_addr ip] is the {!Ipaddr.t} equivalent of the {!Unix.inet_addr}
2828+ [ip]. *)
2929+3030+module V4 : sig
3131+ val to_inet_addr : Ipaddr.V4.t -> Unix.inet_addr
3232+ (** [to_inet_addr ip] is the {!Unix.inet_addr} equivalent of the IPv4 address
3333+ [ip]. *)
3434+3535+ val of_inet_addr_exn : Unix.inet_addr -> Ipaddr.V4.t
3636+ (** [of_inet_addr_exn ip] is the {!Ipaddr.t} equivalent of the
3737+ {!Unix.inet_addr} [ip] IPv4 address. Raises {!Ipaddr.Parse_error} if [ip]
3838+ is not a valid representation of an IPv4 address. *)
3939+4040+ val of_inet_addr : Unix.inet_addr -> Ipaddr.V4.t option
4141+ (** Same as [of_inet_addr_exn] but returns an option type instead of raising
4242+ an exception. *)
4343+end
4444+4545+module V6 : sig
4646+ val to_inet_addr : Ipaddr.V6.t -> Unix.inet_addr
4747+ (** [to_inet_addr ip] is the {!Unix.inet_addr} equivalent of the IPv6 address
4848+ [ip]. *)
4949+5050+ val of_inet_addr_exn : Unix.inet_addr -> Ipaddr.V6.t
5151+ (** [of_inet_addr_exn ip] is the {!Ipaddr.t} equivalent of the
5252+ {!Unix.inet_addr} [ip] IPv6 address. Raises {!Ipaddr.Parse_error} if [ip]
5353+ is not a valid representation of an IPv6 address. *)
5454+5555+ val of_inet_addr : Unix.inet_addr -> Ipaddr.V6.t option
5656+ (** Same as [of_inet_addr_exn] but returns an option type instead of raising
5757+ an exception. *)
5858+end
+98
vendor/opam/ipaddr/lib/macaddr.ml
···11+(*
22+ * Copyright (c) 2010 Anil Madhavapeddy <anil@recoil.org>
33+ * Copyright (c) 2014 David Sheets <sheets@alum.mit.edu>
44+ *
55+ * Permission to use, copy, modify, and distribute this software for any
66+ * purpose with or without fee is hereby granted, provided that the above
77+ * copyright notice and this permission notice appear in all copies.
88+ *
99+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1010+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1111+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1212+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1313+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1414+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1515+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1616+ *)
1717+1818+exception Parse_error of string * string
1919+2020+let need_more x = Parse_error ("not enough data", x)
2121+2222+let try_with_result fn a =
2323+ try Ok (fn a) with Parse_error (msg, _) -> Error (`Msg ("Macaddr: " ^ msg))
2424+2525+type t = string (* length 6 only *)
2626+2727+let compare = String.compare
2828+2929+(* Raw MAC address off the wire (network endian) *)
3030+let of_octets_exn x =
3131+ if String.length x <> 6 then raise (Parse_error ("MAC is exactly 6 bytes", x))
3232+ else x
3333+3434+let of_octets x = try_with_result of_octets_exn x
3535+3636+exception Invalid_hex_digit of char
3737+3838+let hex_digit c =
3939+ match Char.uppercase_ascii c with
4040+ | '0' .. '9' as c -> Char.code c - 48
4141+ | 'A' .. 'F' as c -> Char.code c - 55
4242+ | c -> raise_notrace (Invalid_hex_digit c)
4343+4444+let hex_byte x i =
4545+ (hex_digit (String.get x i) lsl 4) + hex_digit (String.get x (succ i))
4646+4747+(* Read a MAC address colon-separated string *)
4848+let of_string_exn x =
4949+ if String.length x < (2 * 6) + 5 then raise (need_more x);
5050+ if String.length x <> (2 * 6) + 5 then
5151+ raise (Parse_error ("macaddr string is too long", x));
5252+ let m = Bytes.create 6 in
5353+ try
5454+ for i = 0 to 5 do
5555+ Bytes.set_uint8 m i (hex_byte x (3 * i))
5656+ done;
5757+ let sep = x.[2] in
5858+ (match sep with
5959+ | ':' | '-' -> ()
6060+ | _ ->
6161+ raise
6262+ (Parse_error (Printf.sprintf "Invalid macaddr separator: %C" sep, x)));
6363+ for i = 1 to 4 do
6464+ if x.[(3 * i) + 2] <> sep then
6565+ raise
6666+ (Parse_error
6767+ ( Printf.sprintf "Invalid macaddr separator, first was %C, now %C"
6868+ sep
6969+ x.[(3 * i) + 2],
7070+ x ))
7171+ done;
7272+ Bytes.unsafe_to_string m
7373+ with Invalid_hex_digit c ->
7474+ raise (Parse_error (Printf.sprintf "Invalid macaddr hex digit: %C" c, x))
7575+7676+let of_string x = try_with_result of_string_exn x
7777+let chri x i = Char.code x.[i]
7878+7979+let to_string ?(sep = ':') x =
8080+ Printf.sprintf "%02x%c%02x%c%02x%c%02x%c%02x%c%02x" (chri x 0) sep (chri x 1)
8181+ sep (chri x 2) sep (chri x 3) sep (chri x 4) sep (chri x 5)
8282+8383+let to_octets x = x
8484+let pp ppf i = Format.fprintf ppf "%s" (to_string i)
8585+let broadcast = String.make 6 '\255'
8686+8787+let make_local bytegenf =
8888+ let x = Bytes.create 6 in
8989+ (* set locally administered and unicast bits *)
9090+ Bytes.set x 0 (Char.chr (((bytegenf 0 lor 2) lsr 1) lsl 1));
9191+ for i = 1 to 5 do
9292+ Bytes.set x i (Char.chr (bytegenf i))
9393+ done;
9494+ Bytes.unsafe_to_string x
9595+9696+let get_oui x = (chri x 0 lsl 16) lor (chri x 1 lsl 8) lor chri x 2
9797+let is_local x = (chri x 0 lsr 1) land 1 = 1
9898+let is_unicast x = chri x 0 land 1 = 0
+78
vendor/opam/ipaddr/lib/macaddr.mli
···11+(*
22+ * Copyright (c) 2010-2011 Anil Madhavapeddy <anil@recoil.org>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ *)
1616+1717+(** A library for manipulation of MAC address representations.
1818+1919+ {e %%VERSION%% - {{:%%PKG_HOMEPAGE%%} homepage}} *)
2020+2121+exception Parse_error of string * string
2222+(** [Parse_error (err,packet)] is raised when parsing of the MAC address syntax
2323+ fails. [err] contains a human-readable error and [packet] is the original
2424+ octet list that failed to parse. *)
2525+2626+type t
2727+(** Type of the hardware address (MAC) of an ethernet interface. *)
2828+2929+(** {2 Functions converting MAC addresses to/from octets/string} *)
3030+3131+val of_octets_exn : string -> t
3232+(** [of_octets_exn buf] is the hardware address extracted from [buf]. Raises
3333+ [Parse_error] if [buf] has not length 6. *)
3434+3535+val of_octets : string -> (t, [> `Msg of string ]) result
3636+(** Same as {!of_octets_exn} but returns a result type instead of raising an
3737+ exception. *)
3838+3939+val of_string_exn : string -> t
4040+(** [of_string_exn mac_string] is the human-readable hardware address
4141+ represented by [mac_string]. Raises {!Parse_error} if [mac_string] is not a
4242+ valid representation of a MAC address. *)
4343+4444+val of_string : string -> (t, [> `Msg of string ]) result
4545+(** Same as {!of_string_exn} but returns a result type instead of raising an
4646+ exception. *)
4747+4848+val to_octets : t -> string
4949+(** [to_octets mac_addr] is a string of size 6 encoding [mac_addr] as a sequence
5050+ of bytes. *)
5151+5252+val to_string : ?sep:char -> t -> string
5353+(** [to_string ?(sep=':') mac_addr] is the [sep]-separated string representation
5454+ of [mac_addr], i.e. [xx:xx:xx:xx:xx:xx]. *)
5555+5656+val pp : Format.formatter -> t -> unit
5757+[@@ocaml.toplevel_printer]
5858+(** [pp f mac_addr] outputs a human-readable representation of [mac_addr] to the
5959+ formatter [f]. *)
6060+6161+val broadcast : t
6262+(** [broadcast] is [ff:ff:ff:ff:ff:ff]. *)
6363+6464+val make_local : (int -> int) -> t
6565+(** [make_local bytegen] creates a unicast, locally administered MAC address
6666+ given a function mapping octet offset to octet value. *)
6767+6868+val get_oui : t -> int
6969+(** [get_oui macaddr] is the integer organization identifier for [macaddr]. *)
7070+7171+val is_local : t -> bool
7272+(** [is_local macaddr] is the predicate on the locally administered bit of
7373+ [macaddr]. *)
7474+7575+val is_unicast : t -> bool
7676+(** [is_unicast macaddr] the is the predicate on the unicast bit of [macaddr]. *)
7777+7878+include Map.OrderedType with type t := t
+39
vendor/opam/ipaddr/lib/macaddr_cstruct.ml
···11+(*
22+ * Copyright (c) 2019 Anil Madhavapeddy
33+ * Copyright (c) 2014 Nicolás Ojeda Bär
44+ *
55+ * Permission to use, copy, modify, and distribute this software for any
66+ * purpose with or without fee is hereby granted, provided that the above
77+ * copyright notice and this permission notice appear in all copies.
88+ *
99+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1010+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1111+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1212+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1313+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1414+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1515+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1616+ *
1717+ *)
1818+1919+let try_with_result fn a =
2020+ try Ok (fn a)
2121+ with Macaddr.Parse_error (msg, _) -> Error (`Msg ("Macaddr: " ^ msg))
2222+2323+let of_cstruct_exn cs =
2424+ if Cstruct.length cs <> 6 then
2525+ raise (Macaddr.Parse_error ("MAC is exactly 6 bytes", Cstruct.to_string cs))
2626+ else Cstruct.to_string cs |> Macaddr.of_octets_exn
2727+2828+let of_cstruct cs = try_with_result of_cstruct_exn cs
2929+3030+let write_cstruct_exn (mac : Macaddr.t) cs =
3131+ let len = Cstruct.length cs in
3232+ let mac = Macaddr.to_octets mac in
3333+ if len <> 6 then raise (Macaddr.Parse_error ("MAC is exactly 6 bytes", mac));
3434+ Cstruct.blit_from_string mac 0 cs 0 6
3535+3636+let to_cstruct ?(allocator = Cstruct.create) mac =
3737+ let cs = allocator 6 in
3838+ write_cstruct_exn mac cs;
3939+ cs
+35
vendor/opam/ipaddr/lib/macaddr_cstruct.mli
···11+(*
22+ * Copyright (c) 2019 Anil Madhavapeddy
33+ * Copyright (c) 2014 Nicolás Ojeda Bär
44+ *
55+ * Permission to use, copy, modify, and distribute this software for any
66+ * purpose with or without fee is hereby granted, provided that the above
77+ * copyright notice and this permission notice appear in all copies.
88+ *
99+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1010+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1111+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1212+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1313+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1414+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1515+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1616+ *
1717+ *)
1818+1919+(** Convert to and from Cstructs and MAC address. *)
2020+2121+val of_cstruct : Cstruct.t -> (Macaddr.t, [> `Msg of string ]) result
2222+(** [of_cstruct c] parses the 6 octets of [c] into a MAC address. *)
2323+2424+val of_cstruct_exn : Cstruct.t -> Macaddr.t
2525+(** [of_cstruct_exn] parses the 6 octets of [c] into a MAC address. Raises
2626+ {!Macaddr.Parse_failure} on error. *)
2727+2828+val to_cstruct : ?allocator:(int -> Cstruct.t) -> Macaddr.t -> Cstruct.t
2929+(** [to_cstruct mac] is a cstruct of length 4 encoding [ipv4]. The cstruct is
3030+ allocated using [allocator]. If [allocator] is not provided,
3131+ [Cstruct.create] is used. *)
3232+3333+val write_cstruct_exn : Macaddr.t -> Cstruct.t -> unit
3434+(** [write_cstruct_exn mac cs] writes 6 bytes into [cs] representing the [mac]
3535+ address octets. Raises {!Macaddr.Parse_error} if [cs] is not 6 bytes long. *)
+31
vendor/opam/ipaddr/lib/macaddr_sexp.ml
···11+(*
22+ * Copyright (c) 2018 Anil Madhavapeddy <anil@recoil.org>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ *
1616+ *)
1717+1818+open Sexplib0
1919+2020+let of_sexp fn = function
2121+ | Sexp.List _ -> failwith "expecting sexp atom"
2222+ | Sexp.Atom s -> (
2323+ match fn s with Ok r -> r | Error (`Msg msg) -> failwith msg)
2424+2525+let to_sexp fn t = Sexp.Atom (fn t)
2626+2727+type t = Macaddr.t
2828+2929+let sexp_of_t = to_sexp Macaddr.to_string
3030+let t_of_sexp = of_sexp Macaddr.of_string
3131+let compare = Macaddr.compare
+44
vendor/opam/ipaddr/lib/macaddr_sexp.mli
···11+(*
22+ * Copyright (c) 2018 Anil Madhavapeddy <anil@recoil.org>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ *
1616+ *)
1717+1818+(** serialisers to and from {!Macaddr} and s-expression {!Sexplib0} format
1919+2020+ To use these with ppx-based derivers, simply replace the reference to the
2121+ {!Macaddr} type definition with {!Macaddr_sexp} instead. That will import
2222+ the sexp-conversion functions, and the actual type definitions are simply
2323+ aliases to the corresponding type within {!Ipaddr}. For example, you might
2424+ do:
2525+2626+ {[
2727+ type t = { ip : Ipaddr_sexp.t; mac : Macaddr_sexp.t } [@@deriving sexp]
2828+ ]}
2929+3030+ The actual types of the records will be aliases to the main library types,
3131+ and there will be two new functions available as converters.
3232+3333+ {[
3434+ type t = { ip : Ipaddr.t; mac : Macaddr.t }
3535+3636+ val sexp_of_t : t -> Sexplib0.t
3737+ val t_of_sexp : Sexplib0.t -> t
3838+ ]} *)
3939+4040+type t = Macaddr.t
4141+4242+val sexp_of_t : Macaddr.t -> Sexplib0.Sexp.t
4343+val t_of_sexp : Sexplib0.Sexp.t -> Macaddr.t
4444+val compare : Macaddr.t -> Macaddr.t -> int
+17
vendor/opam/ipaddr/lib/macaddr_top.ml
···11+let printers = [ "Macaddr.pp" ]
22+33+let eval_string ?(print_outcome = false) ?(err_formatter = Format.err_formatter)
44+ str =
55+ let lexbuf = Lexing.from_string str in
66+ let phrase = !Toploop.parse_toplevel_phrase lexbuf in
77+ Toploop.execute_phrase print_outcome err_formatter phrase
88+99+let rec install_printers = function
1010+ | [] -> true
1111+ | printer :: printers ->
1212+ let cmd = Printf.sprintf "#install_printer %s;;" printer in
1313+ eval_string cmd && install_printers printers
1414+1515+let () =
1616+ if not (install_printers printers) then
1717+ Format.eprintf "Problem installing Macaddr-printers@."
···11+(*
22+ * Copyright (c) 2013-2014 David Sheets <sheets@alum.mit.edu>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ *
1616+ *)
1717+1818+open OUnit
1919+open Ipaddr
2020+2121+let error s msg = (s, Parse_error (msg, s))
2222+let need_more s = error s "not enough data"
2323+2424+let bad_char i s =
2525+ error s (Printf.sprintf "invalid character '%c' at %d" s.[i] i)
2626+2727+let string_of_list f l = "[" ^ (List.map f l |> String.concat "; ") ^ "]"
2828+let ( >>= ) v f = match v with Ok v -> f v | Error _ as e -> e
2929+3030+let assert_raises ~msg exn test_fn =
3131+ assert_raises ~msg exn (fun () ->
3232+ try test_fn ()
3333+ with rtexn ->
3434+ if exn <> rtexn then (
3535+ Printf.eprintf "Stacktrace for '%s':\n%!" msg;
3636+ Printexc.print_backtrace stderr);
3737+ raise rtexn)
3838+3939+module Test_v4 = struct
4040+ let test_string_rt () =
4141+ let addrs = [ ("192.168.0.1", "192.168.0.1") ] in
4242+ List.iter
4343+ (fun (addr, rt) ->
4444+ let os = V4.of_string_exn addr in
4545+ let ts = V4.to_string os in
4646+ assert_equal ~msg:addr ts rt;
4747+ let os = Ipaddr_sexp.(V4.t_of_sexp (V4.sexp_of_t os)) in
4848+ let ts = V4.to_string os in
4949+ assert_equal ~msg:addr ts rt)
5050+ addrs
5151+5252+ let test_string_rt_bad () =
5353+ let addrs =
5454+ [
5555+ need_more "192.168.0";
5656+ bad_char 11 "192.168.0.1.1";
5757+ error "192.268.2.1" "second octet out of bounds";
5858+ bad_char 4 "192. 168.1.1";
5959+ bad_char 4 "192..0.1";
6060+ bad_char 3 "192,168.0.1";
6161+ ]
6262+ in
6363+ List.iter
6464+ (fun (addr, exn) ->
6565+ assert_raises ~msg:addr exn (fun () -> V4.of_string_exn addr))
6666+ addrs
6767+6868+ let test_string_raw_rt () =
6969+ let addrs =
7070+ [
7171+ (("IP: 192.168.0.1!!!", 4), ("192.168.0.1", 15));
7272+ (("IP: 192.168.0.1.1!!!", 4), ("192.168.0.1", 15));
7373+ ]
7474+ in
7575+ List.iter
7676+ (fun ((addr, off), result) ->
7777+ let c = ref off in
7878+ let os = V4.of_string_raw addr c in
7979+ let ts = V4.to_string os in
8080+ assert_equal ~msg:addr (ts, !c) result)
8181+ addrs
8282+8383+ let test_string_raw_rt_bad () =
8484+ let addrs =
8585+ [
8686+ (let s = "IP: 192.168.0!!!" in
8787+ ((s, 4), (Parse_error ("invalid character '!' at 13", s), 13)));
8888+ ]
8989+ in
9090+ List.iter
9191+ (fun ((addr, off), (exn, cursor)) ->
9292+ let c = ref off in
9393+ assert_raises ~msg:addr exn (fun () -> V4.of_string_raw addr c);
9494+ assert_equal
9595+ ~msg:(Printf.sprintf "%s cursor <> %d (%d)" addr cursor !c)
9696+ !c cursor)
9797+ addrs
9898+9999+ let test_bytes_rt () =
100100+ let addr = "\254\099\003\128" in
101101+ assert_equal ~msg:(String.escaped addr)
102102+ V4.(to_octets (of_octets_exn addr))
103103+ addr
104104+105105+ let test_bytes_rt_bad () =
106106+ let addrs = [ need_more "\254\099\003" ] in
107107+ List.iter
108108+ (fun (addr, exn) ->
109109+ assert_raises ~msg:(String.escaped addr) exn (fun () ->
110110+ V4.of_octets_exn addr))
111111+ addrs
112112+113113+ let test_int32_rt () =
114114+ let addr = 0x0_F0_AB_00_01_l in
115115+ assert_equal
116116+ ~msg:(Printf.sprintf "%08lX" addr)
117117+ V4.(to_int32 (of_int32 addr))
118118+ addr
119119+120120+ let test_prefix_string_rt () =
121121+ let subnets =
122122+ [
123123+ ("192.168.0.0/24", "192.168.0.0/24");
124124+ ("0.0.0.0/0", "0.0.0.0/0");
125125+ ("192.168.0.1/24", "192.168.0.0/24");
126126+ ("192.168.0.0/0", "0.0.0.0/0");
127127+ ]
128128+ in
129129+ List.iter
130130+ (fun (subnet, rt) ->
131131+ let os = V4.Prefix.of_string_exn subnet |> V4.Prefix.prefix in
132132+ let ts = V4.Prefix.to_string os in
133133+ assert_equal ~msg:subnet ts rt;
134134+ let os = Ipaddr_sexp.(V4.Prefix.(t_of_sexp (sexp_of_t os))) in
135135+ let ts = V4.Prefix.to_string os in
136136+ assert_equal ~msg:subnet ts rt)
137137+ subnets
138138+139139+ let test_prefix_string_rt_bad () =
140140+ let subnets =
141141+ [
142142+ bad_char 9 "192.168.0/24";
143143+ bad_char 10 "192.168.0./24";
144144+ error "192.168.0.0/33" "invalid prefix size";
145145+ bad_char 14 "192.168.0.0/30/1";
146146+ bad_char 12 "192.168.0.0/-1";
147147+ ]
148148+ in
149149+ List.iter
150150+ (fun (subnet, exn) ->
151151+ assert_raises ~msg:subnet exn (fun () -> V4.Prefix.of_string_exn subnet))
152152+ subnets
153153+154154+ let test_network_address_rt () =
155155+ let netaddrs = [ ("192.168.0.1/24", "192.168.0.0/24", "192.168.0.1") ] in
156156+ List.iter
157157+ (fun (netaddr, net, addr) ->
158158+ let netv4 = V4.Prefix.of_string_exn net in
159159+ let addrv4 = V4.of_string_exn addr in
160160+ let cidr = V4.Prefix.of_string_exn netaddr in
161161+ let prefix = V4.Prefix.prefix cidr and v4 = V4.Prefix.address cidr in
162162+ assert_equal
163163+ ~msg:(net ^ " <> " ^ V4.Prefix.to_string prefix)
164164+ netv4 prefix;
165165+ assert_equal ~msg:(addr ^ " <> " ^ V4.to_string v4) addrv4 v4;
166166+ let addrstr = V4.Prefix.to_string cidr in
167167+ assert_equal ~msg:(netaddr ^ " <> " ^ addrstr) netaddr addrstr)
168168+ netaddrs
169169+170170+ let test_prefix_broadcast () =
171171+ let pairs =
172172+ [
173173+ ("192.168.0.0/16", "192.168.255.255");
174174+ ("192.168.0.0/24", "192.168.0.255");
175175+ ("192.168.1.1/24", "192.168.1.255");
176176+ ("192.168.0.128/29", "192.168.0.135");
177177+ ("192.168.0.0/31", "192.168.0.1");
178178+ ("192.168.0.0/32", "192.168.0.0");
179179+ ("0.0.0.0/0", "255.255.255.255");
180180+ ]
181181+ in
182182+ List.iter
183183+ (fun (subnet, bcast) ->
184184+ let r = V4.(to_string Prefix.(broadcast (of_string_exn subnet))) in
185185+ assert_equal ~msg:(subnet ^ " <> " ^ r) r bcast)
186186+ pairs
187187+188188+ let test_prefix_bits () =
189189+ let pairs =
190190+ V4.Prefix.
191191+ [
192192+ (global, 0);
193193+ (loopback, 8);
194194+ (link, 16);
195195+ (relative, 8);
196196+ (multicast, 4);
197197+ (private_10, 8);
198198+ (private_172, 12);
199199+ (private_192, 16);
200200+ ]
201201+ in
202202+ List.iter
203203+ (fun (subnet, bits) ->
204204+ let msg = V4.Prefix.to_string subnet ^ " <> " ^ string_of_int bits in
205205+ assert_equal ~msg (V4.Prefix.bits subnet) bits)
206206+ pairs
207207+208208+ let test_prefix_netmask () =
209209+ let nets =
210210+ [
211211+ ("192.168.0.1/32", "255.255.255.255");
212212+ ("192.168.0.1/31", "255.255.255.254");
213213+ ("192.168.0.1/1", "128.0.0.0");
214214+ ("192.168.0.1/0", "0.0.0.0");
215215+ ]
216216+ in
217217+ List.iter
218218+ (fun (net_str, nm_str) ->
219219+ let cidr = V4.Prefix.of_string_exn net_str in
220220+ let prefix = V4.Prefix.prefix cidr
221221+ and address = V4.Prefix.address cidr in
222222+ let netmask = V4.Prefix.netmask prefix in
223223+ let nnm_str = V4.to_string netmask in
224224+ let msg = Printf.sprintf "netmask %s <> %s" nnm_str nm_str in
225225+ assert_equal ~msg nnm_str nm_str;
226226+ let prefix = V4.Prefix.of_netmask_exn ~netmask ~address in
227227+ let nns = V4.Prefix.to_string prefix in
228228+ let msg = Printf.sprintf "%s is %s under netmask iso" net_str nns in
229229+ assert_equal ~msg net_str nns)
230230+ nets
231231+232232+ let test_prefix_netmask_bad () =
233233+ let bad_masks =
234234+ [
235235+ error "127.255.255.255" "invalid netmask";
236236+ error "255.255.254.128" "invalid netmask";
237237+ ]
238238+ in
239239+ List.iter
240240+ (fun (nm_str, exn) ->
241241+ let netmask = V4.of_string_exn nm_str in
242242+ let address = V4.of_string_exn "192.168.0.1" in
243243+ assert_raises ~msg:nm_str exn (fun () ->
244244+ V4.Prefix.of_netmask_exn ~netmask ~address))
245245+ bad_masks
246246+247247+ let test_scope () =
248248+ let ip = V4.of_string_exn in
249249+ (*let is subnet addr = V4.Prefix.(mem addr subnet) in*)
250250+ let is_scope scop addr = scop = V4.scope addr in
251251+ let ships =
252252+ V4.
253253+ [
254254+ (unspecified, "global", is_global, false);
255255+ (unspecified, "multicast", is_multicast, false);
256256+ (unspecified, "point", is_scope Point, true);
257257+ (localhost, "global", is_global, false);
258258+ (localhost, "multicast", is_multicast, false);
259259+ (localhost, "interface", is_scope Interface, true);
260260+ (broadcast, "global", is_global, false);
261261+ (broadcast, "multicast", is_multicast, false);
262262+ (broadcast, "admin", is_scope Admin, true);
263263+ (nodes, "global", is_global, false);
264264+ (nodes, "multicast", is_multicast, true);
265265+ (nodes, "interface", is_scope Link, true);
266266+ (routers, "global", is_global, false);
267267+ (routers, "multicast", is_multicast, true);
268268+ (routers, "link", is_scope Link, true);
269269+ (ip "192.168.0.1", "private", is_private, true);
270270+ (ip "10.3.21.155", "private", is_private, true);
271271+ (ip "172.16.0.0", "private", is_private, true);
272272+ (ip "172.31.255.255", "private", is_private, true);
273273+ (ip "172.15.255.255", "private", is_private, false);
274274+ (ip "172.32.0.0", "private", is_private, false);
275275+ ]
276276+ in
277277+ List.iter
278278+ (fun (addr, lbl, pred, is_mem) ->
279279+ let mems = if is_mem then "" else " not" in
280280+ let msg = V4.to_string addr ^ " is" ^ mems ^ " in " ^ lbl in
281281+ assert_equal ~msg (pred addr) is_mem)
282282+ ships
283283+284284+ let test_map () =
285285+ let m = V4.Map.add (V4.of_string_exn "1.0.0.1") "min" V4.Map.empty in
286286+ let m =
287287+ V4.Map.add (V4.of_string_exn "254.254.254.254") "the greatest host" m
288288+ in
289289+ let m = V4.Map.add (V4.of_string_exn "1.0.0.1") "the least host" m in
290290+ assert_equal ~msg:"size" (V4.Map.cardinal m) 2;
291291+ let min_key, min_val = V4.Map.min_binding m in
292292+ assert_equal
293293+ ~msg:("min is '" ^ min_val ^ "'")
294294+ (min_key, min_val)
295295+ (V4.of_string_exn "1.0.0.1", "the least host");
296296+ assert_equal ~msg:"max" (V4.Map.max_binding m)
297297+ (V4.of_string_exn "254.254.254.254", "the greatest host")
298298+299299+ let test_prefix_map () =
300300+ let module M = Stdlib.Map.Make (V4.Prefix) in
301301+ let of_string s = s |> V4.Prefix.of_string_exn |> V4.Prefix.prefix in
302302+ let m = M.add (of_string "0.0.0.0/0") "everyone" M.empty in
303303+ let m = M.add (of_string "192.0.0.0/1") "weirdos" m in
304304+ let m = M.add (of_string "128.0.0.0/1") "high-bitters" m in
305305+ let m = M.add (of_string "254.0.0.0/8") "top-end" m in
306306+ let m = M.add (of_string "0.0.0.0/0") "iana" m in
307307+ assert_equal ~msg:"size" (M.cardinal m) 3;
308308+ assert_equal ~msg:"min" (M.min_binding m)
309309+ (V4.Prefix.of_string_exn "0.0.0.0/0", "iana");
310310+ assert_equal ~msg:"max" (M.max_binding m)
311311+ (V4.Prefix.of_string_exn "254.0.0.0/8", "top-end");
312312+ assert_equal ~msg:"third"
313313+ (M.find (V4.Prefix.of_string_exn "128.0.0.0/1") m)
314314+ "high-bitters"
315315+316316+ let test_special_addr () =
317317+ assert_equal ~msg:"broadcast" V4.broadcast V4.Prefix.(broadcast global);
318318+ assert_equal ~msg:"any" V4.any V4.Prefix.(network global);
319319+ assert_equal ~msg:"localhost" true V4.(Prefix.(mem localhost loopback))
320320+321321+ let test_multicast_mac () =
322322+ let ip = V4.of_octets_exn "\xff\xbf\x9f\x8f" in
323323+ let multicast = V4.Prefix.(network_address multicast ip) in
324324+ let unicast_mac_str = Macaddr.to_string (V4.multicast_to_mac ip) in
325325+ let multicast_mac_str = Macaddr.to_string (V4.multicast_to_mac multicast) in
326326+ let mac_str = "01:00:5e:3f:9f:8f" in
327327+ assert_equal
328328+ ~msg:("unicast_mac " ^ unicast_mac_str ^ " <> " ^ mac_str)
329329+ unicast_mac_str mac_str;
330330+ assert_equal
331331+ ~msg:("multicast_mac " ^ multicast_mac_str ^ " <> " ^ mac_str)
332332+ multicast_mac_str mac_str
333333+334334+ let test_domain_name () =
335335+ let ip = V4.of_string_exn "128.64.32.16" in
336336+ let name =
337337+ Domain_name.(host_exn (of_string_exn "16.32.64.128.in-addr.arpa"))
338338+ in
339339+ assert_equal ~cmp:Domain_name.equal ~msg:"to_domain_name"
340340+ (V4.to_domain_name ip) name;
341341+ assert_equal ~msg:"of_domain_name" (V4.of_domain_name name) (Some ip)
342342+343343+ let test_cstruct_rt () =
344344+ let addr = "\254\099\003\128" in
345345+ assert_equal ~msg:(String.escaped addr)
346346+ (Cstruct.to_string
347347+ Ipaddr_cstruct.V4.(
348348+ to_cstruct (of_cstruct_exn (Cstruct.of_string addr))))
349349+ addr
350350+351351+ let test_cstruct_rt_bad () =
352352+ let addrs = [ need_more "\254\099\003" ] in
353353+ List.iter
354354+ (fun (addr, exn) ->
355355+ assert_raises ~msg:(String.escaped addr) exn (fun () ->
356356+ Ipaddr_cstruct.V4.of_cstruct_exn (Cstruct.of_string addr)))
357357+ addrs
358358+359359+ let test_prefix_mem () =
360360+ let ip = V4.of_string_exn in
361361+ let prefix = V4.Prefix.of_string_exn in
362362+ let ships =
363363+ [
364364+ (ip "10.0.0.7", prefix "10.0.0.0/29", true);
365365+ (ip "172.16.255.254", prefix "172.16.255.254/31", true);
366366+ (ip "192.168.0.1", prefix "0.0.0.0/0", true);
367367+ (ip "192.168.0.1", V4.Prefix.private_192, true);
368368+ (ip "255.255.255.255", prefix "255.255.255.255/32", true);
369369+ (ip "192.0.2.1", prefix "192.0.2.0/32", false);
370370+ (ip "192.0.2.1", prefix "192.0.0.0/23", false);
371371+ (ip "255.255.255.255", prefix "0.0.0.0/1", false);
372372+ ]
373373+ in
374374+ List.iter
375375+ (fun (addr, subnet, is_mem) ->
376376+ let msg =
377377+ Printf.sprintf "%s is%s in %s" (V4.to_string addr)
378378+ (if is_mem then "" else " not")
379379+ (V4.Prefix.to_string subnet)
380380+ in
381381+ assert_equal ~msg (V4.Prefix.mem addr subnet) is_mem)
382382+ ships
383383+384384+ let test_succ_pred () =
385385+ let open V4 in
386386+ let printer = function
387387+ | Ok v -> Printf.sprintf "Ok %s" (to_string v)
388388+ | Error (`Msg e) -> Printf.sprintf "Error `Msg \"%s\"" e
389389+ in
390390+ let assert_equal = assert_equal ~printer in
391391+ let ip1 = of_string_exn "0.0.0.0" in
392392+ let ip2 = of_string_exn "255.255.255.255" in
393393+ assert_equal ~msg:"succ 0.0.0.0" (of_string "0.0.0.1") (succ ip1);
394394+ assert_equal ~msg:"succ 255.255.255.255"
395395+ (Error (`Msg "Ipaddr: highest address has been reached"))
396396+ (succ ip2);
397397+ assert_equal ~msg:"succ (succ 255.255.255.255)"
398398+ (Error (`Msg "Ipaddr: highest address has been reached"))
399399+ (succ ip2 >>= succ);
400400+ assert_equal ~msg:"pred 0.0.0.0"
401401+ (Error (`Msg "Ipaddr: lowest address has been reached"))
402402+ (pred ip1);
403403+ ()
404404+405405+ let test_prefix_first_last () =
406406+ let open V4.Prefix in
407407+ let assert_equal = assert_equal ~printer:V4.to_string in
408408+ assert_equal ~msg:"first 192.168.1.0/24"
409409+ (V4.of_string_exn "192.168.1.1")
410410+ (first (of_string_exn "192.168.1.0/24"));
411411+ assert_equal ~msg:"first 169.254.169.254/31"
412412+ (Ipaddr.V4.of_string_exn "169.254.169.254")
413413+ (first (of_string_exn "169.254.169.254/31"));
414414+ assert_equal ~msg:"first 169.254.169.254/32"
415415+ (Ipaddr.V4.of_string_exn "169.254.169.254")
416416+ (first (of_string_exn "169.254.169.254/32"));
417417+ assert_equal ~msg:"last 192.168.1.0/24"
418418+ (Ipaddr.V4.of_string_exn "192.168.1.254")
419419+ (last (of_string_exn "192.168.1.0/24"));
420420+ assert_equal ~msg:"last 169.254.169.254/31"
421421+ (Ipaddr.V4.of_string_exn "169.254.169.255")
422422+ (last (of_string_exn "169.254.169.254/31"));
423423+ assert_equal ~msg:"last 169.254.169.254/32"
424424+ (Ipaddr.V4.of_string_exn "169.254.169.254")
425425+ (last (of_string_exn "169.254.169.254/32"))
426426+427427+ let test_reject_octal () =
428428+ let bad_addrs =
429429+ [
430430+ error "010.8.8.8" "octal notation disallowed";
431431+ error "8.010.8.8" "octal notation disallowed";
432432+ error "8.8.010.8" "octal notation disallowed";
433433+ error "8.8.8.010" "octal notation disallowed";
434434+ ]
435435+ in
436436+ List.iter
437437+ (fun (addr, exn) ->
438438+ assert_raises ~msg:addr exn (fun () -> V4.of_string_exn addr))
439439+ bad_addrs
440440+441441+ let test_reject_prefix_octal () =
442442+ let bad_addrs =
443443+ [
444444+ error "010.8.8.8/32" "octal notation disallowed";
445445+ error "8.010.8.8/32" "octal notation disallowed";
446446+ error "8.8.010.8/32" "octal notation disallowed";
447447+ error "8.8.8.010/32" "octal notation disallowed";
448448+ ]
449449+ in
450450+ List.iter
451451+ (fun (addr, exn) ->
452452+ assert_raises ~msg:addr exn (fun () -> V4.Prefix.of_string_exn addr))
453453+ bad_addrs
454454+455455+ let test_hosts () =
456456+ let nets =
457457+ [
458458+ ("255.255.255.255/32", [ "255.255.255.255" ], false);
459459+ ("255.255.255.255/32", [], true);
460460+ ("255.255.255.254/31", [ "255.255.255.254"; "255.255.255.255" ], true);
461461+ ("255.255.255.254/31", [ "255.255.255.254"; "255.255.255.255" ], false);
462462+ ("255.255.255.252/30", [ "255.255.255.253"; "255.255.255.254" ], true);
463463+ ( "255.255.255.252/30",
464464+ [
465465+ "255.255.255.252";
466466+ "255.255.255.253";
467467+ "255.255.255.254";
468468+ "255.255.255.255";
469469+ ],
470470+ false );
471471+ ( "192.0.2.0/29",
472472+ [
473473+ "192.0.2.0";
474474+ "192.0.2.1";
475475+ "192.0.2.2";
476476+ "192.0.2.3";
477477+ "192.0.2.4";
478478+ "192.0.2.5";
479479+ "192.0.2.6";
480480+ "192.0.2.7";
481481+ ],
482482+ false );
483483+ ( "192.0.2.0/29",
484484+ [
485485+ "192.0.2.1";
486486+ "192.0.2.2";
487487+ "192.0.2.3";
488488+ "192.0.2.4";
489489+ "192.0.2.5";
490490+ "192.0.2.6";
491491+ ],
492492+ true );
493493+ ]
494494+ in
495495+ List.iter
496496+ (fun (net, hosts, usable_flag) ->
497497+ let hosts = List.map V4.of_string_exn hosts in
498498+ let hosts_list =
499499+ List.of_seq
500500+ (V4.Prefix.hosts ~usable:usable_flag (V4.Prefix.of_string_exn net))
501501+ in
502502+ let msg =
503503+ Printf.sprintf
504504+ "incorrect sequence of hosts for %s (usable_flag: %b): %s" net
505505+ usable_flag
506506+ (string_of_list V4.to_string hosts_list)
507507+ in
508508+ assert_equal ~msg hosts_list hosts)
509509+ nets
510510+511511+ let test_subnets () =
512512+ let nets =
513513+ [
514514+ ("255.255.255.255/32", [], 24);
515515+ ("192.0.2.0/24", [], 23);
516516+ ("255.255.255.255/32", [ "255.255.255.255/32" ], 32);
517517+ ( "255.255.255.254/31",
518518+ [ "255.255.255.254/32"; "255.255.255.255/32" ],
519519+ 32 );
520520+ ( "255.255.255.252/30",
521521+ [ "255.255.255.252/31"; "255.255.255.254/31" ],
522522+ 31 );
523523+ ("192.0.2.0/29", [ "192.0.2.0/30"; "192.0.2.4/30" ], 30);
524524+ ("192.0.2.0/24", [ "192.0.2.0/25"; "192.0.2.128/25" ], 25);
525525+ ("192.0.2.0/24", [ "192.0.2.0/24" ], 24);
526526+ ("10.0.0.0/8", [ "10.0.0.0/9"; "10.128.0.0/9" ], 9);
527527+ ]
528528+ in
529529+ List.iter
530530+ (fun (net, subnets, sz) ->
531531+ let subnets = List.map V4.Prefix.of_string_exn subnets in
532532+ let subnets_list =
533533+ List.of_seq (V4.Prefix.subnets sz (V4.Prefix.of_string_exn net))
534534+ in
535535+ let msg =
536536+ Printf.sprintf
537537+ "incorrect sequence of subnets for %s (prefix length: %i): %s" net
538538+ sz
539539+ (string_of_list V4.Prefix.to_string subnets_list)
540540+ in
541541+ assert_equal ~msg subnets_list subnets)
542542+ nets
543543+544544+ let suite =
545545+ "Test V4"
546546+ >::: [
547547+ "string_rt" >:: test_string_rt;
548548+ "string_rt_bad" >:: test_string_rt_bad;
549549+ "string_raw_rt" >:: test_string_raw_rt;
550550+ "string_raw_rt_bad" >:: test_string_raw_rt_bad;
551551+ "bytes_rt" >:: test_bytes_rt;
552552+ "bytes_rt_bad" >:: test_bytes_rt_bad;
553553+ "cstruct_rt" >:: test_cstruct_rt;
554554+ "cstruct_rt_bad" >:: test_cstruct_rt_bad;
555555+ "int32_rt" >:: test_int32_rt;
556556+ "prefix_string_rt" >:: test_prefix_string_rt;
557557+ "prefix_string_rt_bad" >:: test_prefix_string_rt_bad;
558558+ "network_address_rt" >:: test_network_address_rt;
559559+ "prefix_broadcast" >:: test_prefix_broadcast;
560560+ "prefix_bits" >:: test_prefix_bits;
561561+ "prefix_netmask" >:: test_prefix_netmask;
562562+ "prefix_netmask_bad" >:: test_prefix_netmask_bad;
563563+ "scope" >:: test_scope;
564564+ "map" >:: test_map;
565565+ "prefix_map" >:: test_prefix_map;
566566+ "special_addr" >:: test_special_addr;
567567+ "multicast_mac" >:: test_multicast_mac;
568568+ "domain_name" >:: test_domain_name;
569569+ "prefix_mem" >:: test_prefix_mem;
570570+ "succ_pred" >:: test_succ_pred;
571571+ "prefix_first_last" >:: test_prefix_first_last;
572572+ "reject_octal" >:: test_reject_octal;
573573+ "reject_prefix_octal" >:: test_reject_prefix_octal;
574574+ "hosts" >:: test_hosts;
575575+ "subnets" >:: test_subnets;
576576+ ]
577577+end
578578+579579+module Test_v6 = struct
580580+ let test_string_rt () =
581581+ let addrs =
582582+ [
583583+ ("2001:db8::ff00:42:8329", "2001:db8::ff00:42:8329");
584584+ ("::ffff:192.168.1.1", "::ffff:192.168.1.1");
585585+ ("::", "::");
586586+ ("[::]", "::");
587587+ ("1:1:1:1::1:1:1", "1:1:1:1:0:1:1:1");
588588+ ("0:0:0:1:1:0:0:0", "::1:1:0:0:0");
589589+ ("0:0:0:1:1::", "::1:1:0:0:0");
590590+ ("::1:0:0:0:0", "0:0:0:1::");
591591+ ("FE80::", "fe80::");
592592+ ("::192.168.0.1", "::c0a8:1");
593593+ ]
594594+ in
595595+ List.iter
596596+ (fun (addr, rt) ->
597597+ let os = V6.of_string_exn addr in
598598+ let ts = V6.to_string os in
599599+ assert_equal ~msg:(addr ^ " <> " ^ rt ^ " (" ^ ts ^ ")") ts rt;
600600+ let os = Ipaddr_sexp.(V6.t_of_sexp (V6.sexp_of_t os)) in
601601+ let ts = V6.to_string os in
602602+ assert_equal ~msg:(addr ^ " <> " ^ rt ^ " (" ^ ts ^ ")") ts rt)
603603+ addrs
604604+605605+ let test_string_rt_bad () =
606606+ let addrs =
607607+ [
608608+ need_more "[";
609609+ need_more "[:";
610610+ need_more "[]";
611611+ (* ? *)
612612+ need_more ":";
613613+ need_more "[::";
614614+ bad_char 4 "::1:g:f";
615615+ bad_char 3 "::1::";
616616+ bad_char 4 "1::2::3";
617617+ need_more "1:2:3:4:5:6:7";
618618+ bad_char 15 "1:2:3:4:5:6:7:8:9";
619619+ bad_char 15 "1:2:3:4:5:6:7:8::";
620620+ error "12345::12:2" "component 0 out of bounds";
621621+ bad_char 1 ":1";
622622+ ]
623623+ in
624624+ List.iter
625625+ (fun (addr, exn) ->
626626+ assert_raises ~msg:addr exn (fun () -> V6.of_string_exn addr))
627627+ addrs
628628+629629+ let test_string_raw_rt () =
630630+ let addrs =
631631+ [
632632+ (("IP: 2001:db8::ff00:42:8329!", 4), ("2001:db8::ff00:42:8329", 26));
633633+ (("IP: ::ffff:192.168.1.1 ", 4), ("::ffff:192.168.1.1", 22));
634634+ (("IP: :::", 4), ("::", 6));
635635+ (("IP: [::]:", 4), ("::", 8));
636636+ (("IP: 1:1:1:1::1:1:1:1", 4), ("1:1:1:1:0:1:1:1", 18));
637637+ (("IP: ::1:1:0:0:0::g", 4), ("::1:1:0:0:0", 15));
638638+ ]
639639+ in
640640+ List.iter
641641+ (fun ((addr, off), (result, cursor)) ->
642642+ let c = ref off in
643643+ let os = V6.of_string_raw addr c in
644644+ let ts = V6.to_string os in
645645+ let msg =
646646+ Printf.sprintf "%s at %d: %s at %d <> %s at %d" addr off result cursor
647647+ ts !c
648648+ in
649649+ assert_equal ~msg (ts, !c) (result, cursor))
650650+ addrs
651651+652652+ let test_string_raw_rt_bad () =
653653+ let error (s, c) msg c' = ((s, c), (Parse_error (msg, s), c')) in
654654+ let need_more loc = error loc "not enough data" in
655655+ let bad_char i (s, c) =
656656+ error (s, c) (Printf.sprintf "invalid character '%c' at %d" s.[i] i) i
657657+ in
658658+ let addrs =
659659+ [
660660+ need_more ("IP: [] ", 4) 5;
661661+ bad_char 5 ("IP: : ", 4);
662662+ bad_char 7 ("IP: [:: ", 4);
663663+ bad_char 17 ("IP: 1:2:3:4:5:6:7 ", 4);
664664+ error ("IP: 12345::12:2 ", 4) "component 0 out of bounds" 15;
665665+ bad_char 5 ("IP: :1 ", 4);
666666+ need_more ("IP: ::1:1:0:0:0:", 4) 16;
667667+ bad_char 8 ("IP: ::1:g:f ", 4);
668668+ ]
669669+ in
670670+ List.iter
671671+ (fun ((addr, off), (exn, cursor)) ->
672672+ let c = ref off in
673673+ assert_raises ~msg:addr exn (fun () -> V6.of_string_raw addr c);
674674+ assert_equal
675675+ ~msg:(Printf.sprintf "%s cursor <> %d (%d)" addr cursor !c)
676676+ !c cursor)
677677+ addrs
678678+679679+ let test_bytes_rt () =
680680+ let addr =
681681+ "\000\000\000\000\000\000\000\000\000\000\255\255\192\168\000\001"
682682+ in
683683+ let v6 = V6.of_octets_exn addr in
684684+ assert_equal ~printer:String.escaped ~msg:(String.escaped addr)
685685+ V6.(to_octets v6)
686686+ addr
687687+688688+ let test_bytes_rt_bad () =
689689+ let addrs =
690690+ [
691691+ need_more "\000\000\000\000\000\000\000\000\000\000\255\255\192\168\001";
692692+ ]
693693+ in
694694+ List.iter
695695+ (fun (addr, exn) ->
696696+ assert_raises ~msg:(String.escaped addr) exn (fun () ->
697697+ V6.of_octets_exn addr))
698698+ addrs
699699+700700+ let test_cstruct_rt () =
701701+ let addr =
702702+ "\000\000\000\000\000\000\000\000\000\000\255\255\192\168\000\001"
703703+ in
704704+ let v6 = Ipaddr_cstruct.V6.of_cstruct_exn (Cstruct.of_string addr) in
705705+ assert_equal ~msg:(String.escaped addr)
706706+ (Cstruct.to_string Ipaddr_cstruct.V6.(to_cstruct v6))
707707+ addr
708708+709709+ let test_cstruct_rt_bad () =
710710+ let addrs =
711711+ [
712712+ need_more "\000\000\000\000\000\000\000\000\000\000\255\255\192\168\001";
713713+ ]
714714+ in
715715+ List.iter
716716+ (fun (addr, exn) ->
717717+ assert_raises ~msg:(String.escaped addr) exn (fun () ->
718718+ Ipaddr_cstruct.V6.of_cstruct_exn (Cstruct.of_string addr)))
719719+ addrs
720720+721721+ let test_int32_rt () =
722722+ let ((a, b, c, d) as addr) =
723723+ (0x2001_0665_l, 0x0000_0000_l, 0xff00_00ff_l, 0xfe00_0001_l)
724724+ in
725725+ assert_equal
726726+ ~msg:(Printf.sprintf "%08lx %08lx %08lx %08lx" a b c d)
727727+ V6.(to_int32 (of_int32 addr))
728728+ addr
729729+730730+ let test_int64_rt () =
731731+ let tests =
732732+ [
733733+ (0x2a01_04f9_c011_87adL, 0x0_0_0_0L);
734734+ (0x0000_0000_8000_0000L, 0x0_0_0_0L);
735735+ ]
736736+ in
737737+ List.iter
738738+ (fun ((a, b) as addr) ->
739739+ assert_equal
740740+ ~msg:(Printf.sprintf "%016Lx %016Lx" a b)
741741+ V6.(to_int64 (of_int64 addr))
742742+ addr)
743743+ tests
744744+745745+ let test_prefix_string_rt () =
746746+ let subnets =
747747+ [
748748+ ("2000::/3", "2000::/3");
749749+ ("c012::/2", "c000::/2");
750750+ ("ffff:ffff:ffff::ffff/0", "::/0");
751751+ ("::/0", "::/0");
752752+ ("::/128", "::/128");
753753+ ("::1/128", "::1/128");
754754+ ("::/64", "::/64");
755755+ ("[::]/64", "::/64");
756756+ ]
757757+ in
758758+ List.iter
759759+ (fun (subnet, rt) ->
760760+ let os = V6.Prefix.of_string_exn subnet |> V6.Prefix.prefix in
761761+ let ts = V6.Prefix.to_string os in
762762+ assert_equal ~msg:subnet ts rt;
763763+ let os = Ipaddr_sexp.(V6.Prefix.(t_of_sexp (sexp_of_t os))) in
764764+ let ts = V6.Prefix.to_string os in
765765+ assert_equal ~msg:subnet ts rt)
766766+ subnets
767767+768768+ let test_prefix_string_rt_bad () =
769769+ let subnets =
770770+ [
771771+ need_more "/24";
772772+ need_more "::";
773773+ error "::/130" "invalid prefix size";
774774+ bad_char 5 "::/30/1";
775775+ bad_char 7 "2000::/-1";
776776+ bad_char 5 "1::3:/4";
777777+ ]
778778+ in
779779+ List.iter
780780+ (fun (subnet, exn) ->
781781+ assert_raises ~msg:subnet exn (fun () -> V6.Prefix.of_string_exn subnet))
782782+ subnets
783783+784784+ let test_network_address_rt () =
785785+ let netaddrs = [ ("::1/24", "::/24", "::1") ] in
786786+ List.iter
787787+ (fun (netaddr, net, addr) ->
788788+ let netv4 = V6.Prefix.of_string_exn net in
789789+ let addrv4 = V6.of_string_exn addr in
790790+ let cidr = V6.Prefix.of_string_exn netaddr in
791791+ let prefix = V6.Prefix.prefix cidr and v4 = V6.Prefix.address cidr in
792792+ let prefix = V6.Prefix.prefix prefix in
793793+ assert_equal
794794+ ~msg:(net ^ " <> " ^ V6.Prefix.to_string prefix)
795795+ netv4 prefix;
796796+ assert_equal ~msg:(addr ^ " <> " ^ V6.to_string v4) addrv4 v4;
797797+ let addrstr = V6.Prefix.to_string cidr in
798798+ assert_equal ~msg:(netaddr ^ " <> " ^ addrstr) netaddr addrstr)
799799+ netaddrs
800800+801801+ let test_prefix_bits () =
802802+ let pairs =
803803+ V6.Prefix.
804804+ [
805805+ (global_unicast_001, 3);
806806+ (link, 64);
807807+ (unique_local, 7);
808808+ (multicast, 8);
809809+ (ipv4_mapped, 96);
810810+ (noneui64_interface, 3);
811811+ ]
812812+ in
813813+ List.iter
814814+ (fun (subnet, bits) ->
815815+ let msg =
816816+ V6.Prefix.to_string subnet ^ " <> bits " ^ string_of_int bits
817817+ in
818818+ assert_equal ~msg (V6.Prefix.bits subnet) bits)
819819+ pairs
820820+821821+ let test_prefix_netmask () =
822822+ let nets =
823823+ [
824824+ ("8::1/128", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
825825+ ("8::1/127", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe");
826826+ ("8::1/96", "ffff:ffff:ffff:ffff:ffff:ffff::");
827827+ ("8::1/64", "ffff:ffff:ffff:ffff::");
828828+ ("8::1/32", "ffff:ffff::");
829829+ ("8::1/1", "8000::");
830830+ ("8::1/0", "::");
831831+ ]
832832+ in
833833+ List.iter
834834+ (fun (net_str, nm_str) ->
835835+ let cidr = V6.Prefix.of_string_exn net_str in
836836+ let prefix = V6.Prefix.prefix cidr
837837+ and address = V6.Prefix.address cidr in
838838+ let netmask = V6.Prefix.netmask prefix in
839839+ let nnm_str = V6.to_string netmask in
840840+ let msg = Printf.sprintf "netmask %s <> %s" nnm_str nm_str in
841841+ assert_equal ~msg nnm_str nm_str;
842842+ let prefix = V6.Prefix.of_netmask_exn ~netmask ~address in
843843+ let nns = V6.Prefix.to_string prefix in
844844+ let msg = Printf.sprintf "%s is %s under netmask iso" net_str nns in
845845+ assert_equal ~msg net_str nns)
846846+ nets
847847+848848+ let test_prefix_netmask_bad () =
849849+ let bad_masks =
850850+ [
851851+ error "7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" "invalid netmask";
852852+ error "ffff:ffff:ffff:ffff:ffff:fffe:8000:0" "invalid netmask";
853853+ error "ffff:ffff:ffff:fffe:8000::" "invalid netmask";
854854+ error "ffff:fffe:8000::" "invalid netmask";
855855+ ]
856856+ in
857857+ List.iter
858858+ (fun (nm_str, exn) ->
859859+ let netmask = V6.of_string_exn nm_str in
860860+ let address = V6.of_string_exn "::" in
861861+ assert_raises ~msg:nm_str exn (fun () ->
862862+ V6.Prefix.of_netmask_exn ~netmask ~address))
863863+ bad_masks
864864+865865+ let test_scope () =
866866+ let localhost_v4 = V6.of_string_exn "::ffff:127.0.0.1" in
867867+ let is subnet addr = V6.Prefix.(mem addr subnet) in
868868+ let is_scope scop addr = scop = V6.scope addr in
869869+ let ships =
870870+ V6.
871871+ [
872872+ (unspecified, "global", is_global, false);
873873+ (unspecified, "multicast", is_multicast, false);
874874+ (unspecified, "point", is_scope Point, true);
875875+ (localhost, "global", is_global, false);
876876+ (localhost, "multicast", is_multicast, false);
877877+ (localhost, "interface", is_scope Interface, true);
878878+ (interface_nodes, "global", is_global, false);
879879+ (interface_nodes, "multicast", is_multicast, true);
880880+ (interface_nodes, "interface", is_scope Interface, true);
881881+ (link_nodes, "global", is_global, false);
882882+ (link_nodes, "multicast", is_multicast, true);
883883+ (link_nodes, "link", is_scope Link, true);
884884+ (link_routers, "global", is_global, false);
885885+ (link_routers, "multicast", is_multicast, true);
886886+ (link_routers, "link", is_scope Link, true);
887887+ (localhost_v4, "global", is_global, false);
888888+ (localhost_v4, "multicast", is_multicast, false);
889889+ (localhost_v4, "ipv4", is Prefix.ipv4_mapped, true);
890890+ (localhost_v4, "noneui64", is Prefix.noneui64_interface, true);
891891+ (localhost_v4, "global_001", is Prefix.global_unicast_001, false);
892892+ (localhost_v4, "interface", is_scope Interface, true);
893893+ ]
894894+ in
895895+ List.iter
896896+ (fun (addr, lbl, pred, is_mem) ->
897897+ let mems = if is_mem then "" else " not" in
898898+ let msg = V6.to_string addr ^ " is" ^ mems ^ " in " ^ lbl in
899899+ assert_equal ~msg (pred addr) is_mem)
900900+ ships
901901+902902+ let test_map () =
903903+ let maxs = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" in
904904+ let m = V6.Map.add (V6.of_string_exn "::0:0") "min" V6.Map.empty in
905905+ let m = V6.Map.add (V6.of_string_exn maxs) "the greatest host" m in
906906+ let m = V6.Map.add (V6.of_string_exn "::") "the least host" m in
907907+ assert_equal ~msg:"size" (V6.Map.cardinal m) 2;
908908+ let min_key, min_val = V6.Map.min_binding m in
909909+ assert_equal
910910+ ~msg:("min is '" ^ min_val ^ "'")
911911+ (min_key, min_val)
912912+ (V6.of_string_exn "::0:0:0", "the least host");
913913+ assert_equal ~msg:"max" (V6.Map.max_binding m)
914914+ (V6.of_string_exn maxs, "the greatest host")
915915+916916+ let test_prefix_map () =
917917+ let module M = Stdlib.Map.Make (V6.Prefix) in
918918+ let of_string s = s |> V6.Prefix.of_string_exn |> V6.Prefix.prefix in
919919+ let m = M.add (of_string "::ffff:0.0.0.0/0") "everyone" M.empty in
920920+ let m = M.add (of_string "::ffff:192.0.0.0/1") "weirdos" m in
921921+ let m = M.add (of_string "::ffff:128.0.0.0/1") "high-bitters" m in
922922+ let m = M.add (of_string "::ffff:254.0.0.0/8") "top-end" m in
923923+ let m = M.add (of_string "::ffff:0.0.0.0/0") "iana" m in
924924+ assert_equal ~msg:"size" (M.cardinal m) 3;
925925+ assert_equal ~msg:"min" (M.min_binding m)
926926+ (of_string "::ffff:0.0.0.0/0", "iana");
927927+ assert_equal ~msg:"max" (M.max_binding m)
928928+ (of_string "::ffff:254.0.0.0/8", "top-end");
929929+ assert_equal ~msg:"third"
930930+ (M.find (of_string "::ffff:128.0.0.0/1") m)
931931+ "high-bitters"
932932+933933+ let test_multicast_mac () =
934934+ let on = 0xFFFF in
935935+ let ip = V6.make on on on on on 0xFFFF 0xFEFE 0xFDFD in
936936+ let unicast = V6.Prefix.(network_address global_unicast_001 ip) in
937937+ let multicast = V6.Prefix.(network_address multicast ip) in
938938+ let unicast_mac_str = Macaddr.to_string (V6.multicast_to_mac unicast) in
939939+ let multicast_mac_str = Macaddr.to_string (V6.multicast_to_mac multicast) in
940940+ let mac_str = "33:33:fe:fe:fd:fd" in
941941+ assert_equal
942942+ ~msg:("unicast_mac " ^ unicast_mac_str ^ " <> " ^ mac_str)
943943+ unicast_mac_str mac_str;
944944+ assert_equal
945945+ ~msg:("multicast_mac " ^ multicast_mac_str ^ " <> " ^ mac_str)
946946+ multicast_mac_str mac_str
947947+948948+ let test_domain_name () =
949949+ let ip = V6.of_string_exn "2a00:1450:4009:800::200e" in
950950+ let name =
951951+ "e.0.0.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.0.9.0.0.4.0.5.4.1.0.0.a.2.ip6.arpa"
952952+ in
953953+ let name = Domain_name.(host_exn (of_string_exn name)) in
954954+ assert_equal ~cmp:Domain_name.equal ~msg:"to_domain_name"
955955+ (V6.to_domain_name ip) name;
956956+ assert_equal ~msg:"of_domain_name" (V6.of_domain_name name) (Some ip)
957957+958958+ let test_link_address_of_mac () =
959959+ let mac = Macaddr.of_string_exn "34-56-78-9A-BC-DE" in
960960+ let ip_str = V6.(to_string (link_address_of_mac mac)) in
961961+ let expected = "fe80::3656:78ff:fe9a:bcde" in
962962+ assert_equal
963963+ ~msg:("link_address_of_mac " ^ ip_str ^ " <> " ^ expected)
964964+ ip_str expected
965965+966966+ let test_succ_pred () =
967967+ let open V6 in
968968+ let printer = function
969969+ | Ok v -> Printf.sprintf "Ok %s" (V6.to_string v)
970970+ | Error (`Msg e) -> Printf.sprintf "Error `Msg \"%s\"" e
971971+ in
972972+ let assert_equal = assert_equal ~printer in
973973+ let ip1 = of_string_exn "::" in
974974+ let ip2 = of_string_exn "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" in
975975+ let ip3 = of_string_exn "::2" in
976976+ assert_equal ~msg:"succ ::" (of_string "::1") (succ ip1);
977977+ assert_equal ~msg:"succ (succ ::)" (of_string "::2") (succ ip1 >>= succ);
978978+ assert_equal ~msg:"succ ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
979979+ (Error (`Msg "Ipaddr: highest address has been reached"))
980980+ (succ ip2);
981981+ assert_equal ~msg:"pred ::2" (of_string "::1") (pred ip3);
982982+ assert_equal ~msg:"pred ::ffff:ffff" (of_string "::ffff:fffd")
983983+ (of_string "::ffff:ffff" >>= pred >>= pred);
984984+ assert_equal ~msg:"pred ::"
985985+ (Error (`Msg "Ipaddr: lowest address has been reached"))
986986+ (pred ip1);
987987+ assert_equal ~msg:"pred (succ ::2)" (Ok ip3) (succ ip3 >>= pred)
988988+989989+ let test_first_last () =
990990+ let open V6 in
991991+ let open Prefix in
992992+ let ip_of_string = V6.of_string_exn in
993993+ let assert_equal = assert_equal ~printer:V6.to_string in
994994+ assert_equal ~msg:"first ::/64" (ip_of_string "::1")
995995+ (first @@ of_string_exn "::/64");
996996+ assert_equal ~msg:"first ::ff00/120" (ip_of_string "::ff01")
997997+ (first @@ of_string_exn "::ff00/120");
998998+ assert_equal ~msg:"first ::aaa0/127" (ip_of_string "::aaa0")
999999+ (first @@ of_string_exn "::aaa0/127");
10001000+ assert_equal ~msg:"first ::aaa0/128" (ip_of_string "::aaa0")
10011001+ (first @@ of_string_exn "::aaa0/128");
10021002+ assert_equal ~msg:"last ::/64"
10031003+ (ip_of_string "::ffff:ffff:ffff:ffff")
10041004+ (last @@ of_string_exn "::/64");
10051005+ assert_equal ~msg:"last ::/120" (ip_of_string "::ff")
10061006+ (last @@ of_string_exn "::/120");
10071007+ assert_equal ~msg:"last ::/112" (ip_of_string "::ffff")
10081008+ (last @@ of_string_exn "::/112");
10091009+ assert_equal ~msg:"last ::bbbb:eeee:0000:0000/64"
10101010+ (ip_of_string "::ffff:ffff:ffff:ffff")
10111011+ (last @@ of_string_exn "::bbbb:eeee:0000:0000/64");
10121012+ assert_equal ~msg:"last ::aaa0/127" (ip_of_string "::aaa1")
10131013+ (last @@ of_string_exn "::aaa0/127");
10141014+ assert_equal ~msg:"last ::aaa0/128" (ip_of_string "::aaa0")
10151015+ (last @@ of_string_exn "::aaa0/128")
10161016+10171017+ let test_hosts () =
10181018+ let nets =
10191019+ [
10201020+ ("2001:db8:0:ffff::/128", [ "2001:db8:0:ffff::" ], false);
10211021+ ("2001:db8:0:ffff::/128", [], true);
10221022+ ( "2001:db8:0:ffff::/127",
10231023+ [ "2001:db8:0:ffff::"; "2001:db8:0:ffff::1" ],
10241024+ false );
10251025+ ( "2001:db8:0:ffff::/127",
10261026+ [ "2001:db8:0:ffff::"; "2001:db8:0:ffff::1" ],
10271027+ true );
10281028+ ( "2001:db8:0:ffff::/126",
10291029+ [
10301030+ "2001:db8:0:ffff::";
10311031+ "2001:db8:0:ffff::1";
10321032+ "2001:db8:0:ffff::2";
10331033+ "2001:db8:0:ffff::3";
10341034+ ],
10351035+ false );
10361036+ ( "2001:db8:0:ffff::/126",
10371037+ [ "2001:db8:0:ffff::1"; "2001:db8:0:ffff::2"; "2001:db8:0:ffff::3" ],
10381038+ true );
10391039+ ]
10401040+ in
10411041+ List.iter
10421042+ (fun (net, hosts, usable_flag) ->
10431043+ let hosts = List.map V6.of_string_exn hosts in
10441044+ let hosts_list =
10451045+ List.of_seq
10461046+ (V6.Prefix.hosts ~usable:usable_flag (V6.Prefix.of_string_exn net))
10471047+ in
10481048+ let msg =
10491049+ Printf.sprintf
10501050+ "incorrect sequence of hosts for %s (usable_flag: %b): %s" net
10511051+ usable_flag
10521052+ (string_of_list V6.to_string hosts_list)
10531053+ in
10541054+ assert_equal ~msg hosts_list hosts)
10551055+ nets
10561056+10571057+ let test_subnets () =
10581058+ let nets =
10591059+ [
10601060+ ("2001:db8:0:ffff::/128", [], 127);
10611061+ ("2001:db8:0:ffff::/64", [], 63);
10621062+ ("2001:db8:0:ffff::/128", [ "2001:db8:0:ffff::/128" ], 128);
10631063+ ( "2001:db8:0:ffff::/127",
10641064+ [ "2001:db8:0:ffff::/128"; "2001:db8:0:ffff::1/128" ],
10651065+ 128 );
10661066+ ("::/0", [ "::/1"; "8000::/1" ], 1);
10671067+ ("::/0", [ "::/2"; "4000::/2"; "8000::/2"; "c000::/2" ], 2);
10681068+ ( "2001:db8:0:ffff::/126",
10691069+ [ "2001:db8:0:ffff::/127"; "2001:db8:0:ffff::2/127" ],
10701070+ 127 );
10711071+ ( "2001:db8:0:fff0::/60",
10721072+ [
10731073+ "2001:db8:0:fff0::/64";
10741074+ "2001:db8:0:fff1::/64";
10751075+ "2001:db8:0:fff2::/64";
10761076+ "2001:db8:0:fff3::/64";
10771077+ "2001:db8:0:fff4::/64";
10781078+ "2001:db8:0:fff5::/64";
10791079+ "2001:db8:0:fff6::/64";
10801080+ "2001:db8:0:fff7::/64";
10811081+ "2001:db8:0:fff8::/64";
10821082+ "2001:db8:0:fff9::/64";
10831083+ "2001:db8:0:fffa::/64";
10841084+ "2001:db8:0:fffb::/64";
10851085+ "2001:db8:0:fffc::/64";
10861086+ "2001:db8:0:fffd::/64";
10871087+ "2001:db8:0:fffe::/64";
10881088+ "2001:db8:0:ffff::/64";
10891089+ ],
10901090+ 64 );
10911091+ ]
10921092+ in
10931093+ List.iter
10941094+ (fun (net, subnets, sz) ->
10951095+ let subnets = List.map V6.Prefix.of_string_exn subnets in
10961096+ let subnets_list =
10971097+ List.of_seq (V6.Prefix.subnets sz (V6.Prefix.of_string_exn net))
10981098+ in
10991099+ let msg =
11001100+ Printf.sprintf
11011101+ "incorrect sequence of subnets for %s (prefix length: %i): %s" net
11021102+ sz
11031103+ (string_of_list V6.Prefix.to_string subnets_list)
11041104+ in
11051105+ assert_equal ~msg subnets_list subnets)
11061106+ nets
11071107+11081108+ let suite =
11091109+ "Test V6"
11101110+ >::: [
11111111+ "string_rt" >:: test_string_rt;
11121112+ "string_rt_bad" >:: test_string_rt_bad;
11131113+ "string_raw_rt" >:: test_string_raw_rt;
11141114+ "string_raw_rt_bad" >:: test_string_raw_rt_bad;
11151115+ "bytes_rt" >:: test_bytes_rt;
11161116+ "bytes_rt_bad" >:: test_bytes_rt_bad;
11171117+ "cstruct_rt" >:: test_cstruct_rt;
11181118+ "cstruct_rt_bad" >:: test_cstruct_rt_bad;
11191119+ "int32_rt" >:: test_int32_rt;
11201120+ "int64_rt" >:: test_int64_rt;
11211121+ "prefix_string_rt" >:: test_prefix_string_rt;
11221122+ "prefix_string_rt_bad" >:: test_prefix_string_rt_bad;
11231123+ "network_address_rt" >:: test_network_address_rt;
11241124+ "prefix_bits" >:: test_prefix_bits;
11251125+ "prefix_netmask" >:: test_prefix_netmask;
11261126+ "prefix_netmask_bad" >:: test_prefix_netmask_bad;
11271127+ "scope" >:: test_scope;
11281128+ "map" >:: test_map;
11291129+ "prefix_map" >:: test_prefix_map;
11301130+ "multicast_mac" >:: test_multicast_mac;
11311131+ "domain_name" >:: test_domain_name;
11321132+ "link_address_of_mac" >:: test_link_address_of_mac;
11331133+ "succ_pred" >:: test_succ_pred;
11341134+ "first_last" >:: test_first_last;
11351135+ "hosts" >:: test_hosts;
11361136+ "subnets" >:: test_subnets;
11371137+ ]
11381138+end
11391139+11401140+let test_string_raw_rt () =
11411141+ let addrs =
11421142+ [
11431143+ (("IP: 192.168.0.0!!", 4), ("192.168.0.0", 15));
11441144+ (("IP: 192:168:0::!!", 4), ("192:168::", 15));
11451145+ (("IP: [192:168::]!!", 4), ("192:168::", 15));
11461146+ ]
11471147+ in
11481148+ List.iter
11491149+ (fun ((addr, off), (result, cursor)) ->
11501150+ let c = ref off in
11511151+ let os = of_string_raw addr c in
11521152+ let ts = to_string os in
11531153+ let msg =
11541154+ Printf.sprintf "%s at %d: %s at %d <> %s at %d" addr off result cursor
11551155+ ts !c
11561156+ in
11571157+ assert_equal ~msg (ts, !c) (result, cursor))
11581158+ addrs
11591159+11601160+let test_with_port_of_string () =
11611161+ let default = 8080 in
11621162+ let addrs =
11631163+ [
11641164+ ("127.0.0.1", (Ipaddr.(V4 V4.localhost), default));
11651165+ ("127.0.0.1:8080", (Ipaddr.(V4 V4.localhost), 8080));
11661166+ ("127.0.0.1:4343", (Ipaddr.(V4 V4.localhost), 4343));
11671167+ ("::1", (Ipaddr.(V6 V6.localhost), default));
11681168+ ("0:0:0:0:0:0:0:1:8080", (Ipaddr.(V6 V6.localhost), 8080));
11691169+ ("0:0:0:0:0:0:0:1:4343", (Ipaddr.(V6 V6.localhost), 4343));
11701170+ ]
11711171+ in
11721172+ List.iter
11731173+ (fun (inet_addr, result) ->
11741174+ match Ipaddr.with_port_of_string ~default inet_addr with
11751175+ | Ok ((V4 ipv4, port) as result') ->
11761176+ let result'' = V4.with_port_of_string ~default inet_addr in
11771177+ let msg =
11781178+ Format.asprintf "%s <> %a:%d" inet_addr Ipaddr.V4.pp ipv4 port
11791179+ in
11801180+ assert_equal ~msg result result';
11811181+ assert_equal ~msg (Ok (ipv4, port)) result''
11821182+ | Ok ((V6 ipv6, port) as result') ->
11831183+ let result'' = V6.with_port_of_string ~default inet_addr in
11841184+ let msg =
11851185+ Format.asprintf "%s <> %a:%d" inet_addr Ipaddr.V6.pp ipv6 port
11861186+ in
11871187+ assert_equal ~msg result result';
11881188+ assert_equal ~msg (Ok (ipv6, port)) result''
11891189+ | Error (`Msg err) ->
11901190+ assert_failure (Format.asprintf "%s: %s" inet_addr err))
11911191+ addrs
11921192+11931193+let test_invalid_with_port_of_string () =
11941194+ let default = 8080 in
11951195+ let addrs =
11961196+ [
11971197+ "127.0.0.1:"; "127.0.0.1!8080"; "0:0:0:0:0:0:0:1!8080"; "0:0:0:0:0:0:0:1:";
11981198+ ]
11991199+ in
12001200+ List.iter
12011201+ (fun inet_addr ->
12021202+ match
12031203+ ( Ipaddr.with_port_of_string ~default inet_addr,
12041204+ Ipaddr.V4.with_port_of_string ~default inet_addr,
12051205+ Ipaddr.V4.with_port_of_string ~default inet_addr )
12061206+ with
12071207+ | Error _, Error _, Error _ -> ()
12081208+ | _ ->
12091209+ assert_failure
12101210+ (Format.asprintf "Unexpected valid inet_addr: %S" inet_addr))
12111211+ addrs
12121212+12131213+let test_string_raw_rt_bad () =
12141214+ let error (s, c) msg c' = ((s, c), (Parse_error (msg, s), c')) in
12151215+ let addrs =
12161216+ [
12171217+ error ("IP: ::192.168 ", 4)
12181218+ "not an IPv4 address: invalid character ':' at 4\n\
12191219+ not an IPv6 address: invalid character ' ' at 13" 13;
12201220+ error ("IP: [::192.168] ", 4)
12211221+ "not an IPv4 address: invalid character '[' at 4\n\
12221222+ not an IPv6 address: invalid character ']' at 14" 14;
12231223+ (* ? *)
12241224+ error ("IP: 192:168::3.5 ", 4)
12251225+ "not an IPv4 address: invalid character ':' at 7\n\
12261226+ not an IPv6 address: invalid character ' ' at 16" 16;
12271227+ ]
12281228+ in
12291229+ List.iter
12301230+ (fun ((addr, off), (exn, cursor)) ->
12311231+ let c = ref off in
12321232+ assert_raises ~msg:addr exn (fun () -> of_string_raw addr c);
12331233+ assert_equal
12341234+ ~msg:(Printf.sprintf "%s cursor <> %d (%d)" addr cursor !c)
12351235+ !c cursor)
12361236+ addrs
12371237+12381238+let test_map () =
12391239+ let maxv6 = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" in
12401240+ let maxv4 = "254.254.254.254" in
12411241+ let m = Map.add (of_string_exn maxv4) "the greatest host v4" Map.empty in
12421242+ let m = Map.add (of_string_exn "::0:0") "minv6" m in
12431243+ let m = Map.add (of_string_exn maxv6) "the greatest host v6" m in
12441244+ let m = Map.add (of_string_exn "::") "the least host v6" m in
12451245+ let m = Map.add (of_string_exn "1.0.0.1") "minv4" m in
12461246+ let m = Map.add (of_string_exn "1.0.0.1") "the least host v4" m in
12471247+ assert_equal ~msg:"size" (Map.cardinal m) 4;
12481248+ let min_key, min_val = Map.min_binding m in
12491249+ assert_equal
12501250+ ~msg:("min is '" ^ min_val ^ "'")
12511251+ (min_key, min_val)
12521252+ (of_string_exn "1.0.0.1", "the least host v4");
12531253+ assert_equal ~msg:"max" (Map.max_binding m)
12541254+ (of_string_exn maxv6, "the greatest host v6")
12551255+12561256+let test_prefix_mem () =
12571257+ let ip = of_string_exn in
12581258+ let ships =
12591259+ [
12601260+ (ip "192.168.0.1", V4 V4.Prefix.private_192, true);
12611261+ (ip "192.168.0.1", Prefix.of_string_exn "::ffff:0:0/96", true);
12621262+ (ip "192.168.0.1", Prefix.of_string_exn "::ffff:0:0/95", true);
12631263+ (ip "192.168.0.1", Prefix.of_string_exn "::ffff:0:0/97", false);
12641264+ (ip "192.168.0.1", Prefix.of_string_exn "::ffff:128.0.0.0/97", true);
12651265+ (ip "::ffff:10.0.0.1", V4 V4.Prefix.private_10, true);
12661266+ (ip "::fffe:10.0.0.1", V4 V4.Prefix.private_10, false);
12671267+ ]
12681268+ in
12691269+ List.iter
12701270+ (fun (addr, subnet, is_mem) ->
12711271+ let msg =
12721272+ Printf.sprintf "%s is%s in %s" (to_string addr)
12731273+ (if is_mem then "" else " not")
12741274+ (Prefix.to_string subnet)
12751275+ in
12761276+ assert_equal ~msg (Prefix.mem addr subnet) is_mem)
12771277+ ships
12781278+12791279+let test_prefix_subset () =
12801280+ let pre = Prefix.of_string_exn in
12811281+ let ships =
12821282+ [
12831283+ (pre "10.0.0.1/32", pre "10.0.0.1/32", true);
12841284+ (pre "10.0.0.1/32", pre "10.0.0.2/32", false);
12851285+ (pre "10.0.0.3/32", pre "10.0.0.2/31", true);
12861286+ (pre "10.0.0.2/31", pre "10.0.0.3/32", false);
12871287+ (pre "10.0.10.0/24", V4 V4.Prefix.private_10, true);
12881288+ (V4 V4.Prefix.private_10, pre "10.0.10.0/24", false);
12891289+ ]
12901290+ in
12911291+ List.iter
12921292+ (fun (subnet1, subnet2, is_subset) ->
12931293+ let msg =
12941294+ Printf.sprintf "%s is%s subset of %s" (Prefix.to_string subnet1)
12951295+ (if is_subset then "" else " not")
12961296+ (Prefix.to_string subnet2)
12971297+ in
12981298+ assert_equal ~msg
12991299+ (Prefix.subset ~subnet:subnet1 ~network:subnet2)
13001300+ is_subset)
13011301+ ships
13021302+13031303+let suite =
13041304+ "Test Generic Addresses"
13051305+ >::: [
13061306+ "string_raw_rt" >:: test_string_raw_rt;
13071307+ "string_raw_rt_bad" >:: test_string_raw_rt_bad;
13081308+ "map" >:: test_map;
13091309+ "prefix_mem" >:: test_prefix_mem;
13101310+ "prefix_subset" >:: test_prefix_subset;
13111311+ "with_port" >:: test_with_port_of_string;
13121312+ "invalid_with_port" >:: test_invalid_with_port_of_string;
13131313+ ]
13141314+;;
13151315+13161316+let _results = run_test_tt_main Test_v4.suite in
13171317+let _results = run_test_tt_main Test_v6.suite in
13181318+let _results = run_test_tt_main suite in
13191319+()
+199
vendor/opam/ipaddr/lib_test/test_ipaddr_b128.ml
···11+(*
22+ * Copyright (c) 2013-2014 David Sheets <sheets@alum.mit.edu>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ *
1616+ *)
1717+1818+open OUnit
1919+module B128 = Ipaddr_internal.S128
2020+2121+(* copied from test_ipaddr.ml *)
2222+let assert_raises ~msg exn test_fn =
2323+ assert_raises ~msg exn (fun () ->
2424+ try test_fn ()
2525+ with rtexn ->
2626+ if exn <> rtexn then (
2727+ Printf.eprintf "Stacktrace for '%s':\n%!" msg;
2828+ Printexc.print_backtrace stderr);
2929+ raise rtexn)
3030+3131+let int_of_hex_char c =
3232+ match c with
3333+ | '0' .. '9' -> Char.code c - 48
3434+ | 'a' .. 'f' -> Char.code c - 87
3535+ | 'A' .. 'F' -> Char.code c - 55
3636+ | _ -> invalid_arg "char is not a valid hex digit"
3737+3838+let to_string (s : Ipaddr_internal.S128.t) =
3939+ let s : string = Obj.magic s in
4040+ List.init 16 (fun i -> Printf.sprintf "%.2x" (Char.code (String.get s i)))
4141+ |> String.concat ""
4242+4343+let of_string_exn s : B128.t =
4444+ if String.length s <> 32 then invalid_arg "not 32 chars long";
4545+ Bytes.init 16 (fun bi ->
4646+ let i = bi * 2 in
4747+ let x = int_of_hex_char s.[i + 1] and y = int_of_hex_char s.[i] in
4848+ char_of_int ((y lsl 4) + x))
4949+ |> Bytes.unsafe_to_string
5050+ |> Obj.magic
5151+5252+let assert_equal = assert_equal ~printer:to_string
5353+5454+let test_addition () =
5555+ (* simple addition *)
5656+ let d1 = B128.zero in
5757+ let d2 = of_string_exn "00000000000000000000000000000001" in
5858+ assert_equal ~msg:"adding one to zero is one" d2 (B128.add_exn d1 d2);
5959+6060+ (* addition carry *)
6161+ let d1 = of_string_exn "000000000000000000ff000000000000" in
6262+ let d2 = of_string_exn "00000000000000000001000000000000" in
6363+ let d3 = of_string_exn "00000000000000000100000000000000" in
6464+ assert_equal ~msg:"test addition carry over" d3 (B128.add_exn d1 d2);
6565+6666+ (* adding one to max_int overflows *)
6767+ let d1 = B128.max_int in
6868+ let d2 = of_string_exn "00000000000000000000000000000001" in
6969+ assert_raises ~msg:"adding one to max_int overflows" B128.Overflow (fun () ->
7070+ B128.add_exn d1 d2)
7171+7272+let test_pred () =
7373+ (* simple subtraction *)
7474+ let d1 = of_string_exn "00000000000000000000000000000001" in
7575+ let d2 = B128.zero in
7676+ assert_equal ~msg:"subtracting one from one is zero" d2 (B128.pred_exn d1);
7777+7878+ (* subtract carry *)
7979+ let d1 = of_string_exn "00000000000000000000000000000300" in
8080+ let d2 = of_string_exn "000000000000000000000000000002ff" in
8181+ assert_equal ~msg:"test subtraction carry over" d2 (B128.pred_exn d1);
8282+8383+ (* subtracting one from zero overflows *)
8484+ assert_raises ~msg:"subtracting one from min_int overflows" B128.Overflow
8585+ (fun () -> B128.pred_exn B128.zero)
8686+8787+let test_of_to_string () =
8888+ let s = "ff000000000000004200000000000001" in
8989+ OUnit.assert_equal ~msg:"input of of_string is equal to output of to_string" s
9090+ (of_string_exn s |> to_string)
9191+9292+let test_lognot () =
9393+ let d1 = of_string_exn "00000000000000000000000000000001" in
9494+ let d2 = of_string_exn "fffffffffffffffffffffffffffffffe" in
9595+ assert_equal ~msg:"lognot inverts bits" d2 (B128.lognot d1)
9696+9797+let test_shift_left () =
9898+ (* bit shift count, input, expected output *)
9999+ let test_shifts =
100100+ [
101101+ (1, "f0000000000000000000000000000000", "e0000000000000000000000000000000");
102102+ (1, "0000000000000000000000000000000f", "0000000000000000000000000000001e");
103103+ (1, "00000000000000000000000000000001", "00000000000000000000000000000002");
104104+ (2, "f0000000000000000000000000000000", "c0000000000000000000000000000000");
105105+ (2, "0000000000000000000000000000ffff", "0000000000000000000000000003fffc");
106106+ (8, "00000000000000000000000000000100", "00000000000000000000000000010000");
107107+ (9, "f0000000000000000000000000000000", "00000000000000000000000000000000");
108108+ ( 64,
109109+ "00000000000000000000000000000001",
110110+ "00000000000000010000000000000000" );
111111+ ( 127,
112112+ "00000000000000000000000000000001",
113113+ "80000000000000000000000000000000" );
114114+ ( 128,
115115+ "00000000000000000000000000000001",
116116+ "00000000000000000000000000000000" );
117117+ ]
118118+ in
119119+ List.iter
120120+ (fun (bits, input_value, expected_output) ->
121121+ assert_equal
122122+ ~msg:(Printf.sprintf "shift left by %i" bits)
123123+ (of_string_exn expected_output)
124124+ (B128.shift_left (of_string_exn input_value) bits))
125125+ test_shifts
126126+127127+let test_shift_right () =
128128+ (* (bit shift count, input, expected output) *)
129129+ let test_shifts =
130130+ [
131131+ (1, "f0000000000000000000000000000000", "78000000000000000000000000000000");
132132+ (2, "f0000000000000000000000000000000", "3c000000000000000000000000000000");
133133+ (2, "0000000000000000000000000000ffff", "00000000000000000000000000003fff");
134134+ (2, "000000000000000000000000000ffff0", "0000000000000000000000000003fffc");
135135+ (8, "00000000000000000000000000000100", "00000000000000000000000000000001");
136136+ (9, "f0000000000000000000000000000000", "00780000000000000000000000000000");
137137+ ( 32,
138138+ "000000000000000000000000ffffffff",
139139+ "00000000000000000000000000000000" );
140140+ ( 32,
141141+ "0000000000000000aaaabbbbffffffff",
142142+ "000000000000000000000000aaaabbbb" );
143143+ ( 40,
144144+ "0000000000000000aaaabbbbffffffff",
145145+ "00000000000000000000000000aaaabb" );
146146+ ( 64,
147147+ "01000000000000000000000000000000",
148148+ "00000000000000000100000000000000" );
149149+ ( 120,
150150+ "aaaabbbbccccdddd0000000000000000",
151151+ "000000000000000000000000000000aa" );
152152+ ( 127,
153153+ "80000000000000000000000000000000",
154154+ "00000000000000000000000000000001" );
155155+ ( 128,
156156+ "ffff0000000000000000000000000000",
157157+ "00000000000000000000000000000000" );
158158+ ]
159159+ in
160160+ List.iter
161161+ (fun (bits, input_value, expected_output) ->
162162+ assert_equal
163163+ ~msg:(Printf.sprintf "shift right by %i" bits)
164164+ (of_string_exn expected_output)
165165+ (B128.shift_right (of_string_exn input_value) bits))
166166+ test_shifts
167167+168168+let test_byte_module () =
169169+ let assert_equal = OUnit2.assert_equal ~printer:(Printf.sprintf "0x%x") in
170170+ assert_equal ~msg:"get 3 lsb" 0x00 (B128.Byte.get_lsbits 3 0x00);
171171+ assert_equal ~msg:"get 4 lsb" 0x0f (B128.Byte.get_lsbits 4 0xff);
172172+ assert_equal ~msg:"get 5 lsb" 0x10 (B128.Byte.get_lsbits 5 0x10);
173173+ assert_equal ~msg:"get 8 lsb" 0xff (B128.Byte.get_lsbits 8 0xff);
174174+175175+ assert_equal ~msg:"get 3 msb" 0x0 (B128.Byte.get_msbits 3 0x00);
176176+ assert_equal ~msg:"get 4 msb" 0xf (B128.Byte.get_msbits 4 0xff);
177177+ assert_equal ~msg:"get 5 msb" 0x2 (B128.Byte.get_msbits 5 0x10);
178178+ assert_equal ~msg:"get 8 msb" 0xff (B128.Byte.get_msbits 8 0xff);
179179+180180+ assert_equal ~msg:"set 3 msb" 0x20 (B128.Byte.set_msbits 3 0x1 0x00);
181181+ assert_equal ~msg:"set 4 msb" 0xa0 (B128.Byte.set_msbits 4 0xa 0x00);
182182+ assert_equal ~msg:"set 5 msb" 0x98 (B128.Byte.set_msbits 5 0x13 0x00);
183183+ assert_equal ~msg:"set 8 msb" 0xff (B128.Byte.set_msbits 8 0xff 0x00)
184184+185185+let suite =
186186+ "Test B128 module"
187187+ >::: [
188188+ "addition" >:: test_addition;
189189+ "pred" >:: test_pred;
190190+ "of_to_string" >:: test_of_to_string;
191191+ "lognot" >:: test_lognot;
192192+ "shift_left" >:: test_shift_left;
193193+ "shift_right" >:: test_shift_right;
194194+ "byte_module" >:: test_byte_module;
195195+ ]
196196+;;
197197+198198+let _results = run_test_tt_main suite in
199199+()
+114
vendor/opam/ipaddr/lib_test/test_macaddr.ml
···11+(*
22+ * Copyright (c) 2013-2014 David Sheets <sheets@alum.mit.edu>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ *
1616+ *)
1717+1818+open OUnit
1919+open Macaddr
2020+2121+let test_string_rt () =
2222+ let addrs = [ ("ca:fe:ba:be:ee:ee", ':'); ("ca-fe-ba-be-ee-ee", '-') ] in
2323+ List.iter
2424+ (fun (addr, sep) ->
2525+ let os = of_string_exn addr in
2626+ let ts = to_string ~sep os in
2727+ assert_equal ~msg:(addr ^ " <> " ^ ts) ts addr;
2828+ let os = Macaddr_sexp.(t_of_sexp (sexp_of_t os)) in
2929+ let ts = to_string ~sep os in
3030+ assert_equal ~msg:(addr ^ " <> " ^ ts) ts addr)
3131+ addrs
3232+3333+let assert_result_failure ~msg a =
3434+ match a with Ok _ -> assert_failure msg | Error (`Msg _) -> ()
3535+3636+let test_string_rt_bad () =
3737+ let addrs =
3838+ [
3939+ "ca:fe:ba:be:ee:e";
4040+ "ca:fe:ba:be:ee:eee";
4141+ "ca:fe:ba:be:eeee";
4242+ "ca:fe:ba:be:ee::ee";
4343+ "ca:fe:ba:be:e:eee";
4444+ "ca:fe:ba:be:ee-ee";
4545+ ]
4646+ in
4747+ List.iter (fun addr -> assert_result_failure ~msg:addr (of_string addr)) addrs
4848+4949+let test_bytes_rt () =
5050+ let addr = "\254\099\003\128\000\000" in
5151+ assert_equal ~msg:(String.escaped addr) (to_octets (of_octets_exn addr)) addr
5252+5353+let test_bytes_rt_bad () =
5454+ let addrs = [ "\254\099\003\128\000"; "\254\099\003\128\000\000\233" ] in
5555+ List.iter
5656+ (fun addr ->
5757+ assert_result_failure ~msg:(String.escaped addr) (of_octets addr))
5858+ addrs
5959+6060+let test_cstruct_rt () =
6161+ let open Macaddr_cstruct in
6262+ let addr = "\254\099\003\128\000\000" in
6363+ assert_equal ~msg:(String.escaped addr)
6464+ (Cstruct.to_string (to_cstruct (of_cstruct_exn (Cstruct.of_string addr))))
6565+ addr
6666+6767+let error s = (s, Parse_error ("MAC is exactly 6 bytes", s))
6868+6969+let test_cstruct_rt_bad () =
7070+ let open Macaddr_cstruct in
7171+ let addrs =
7272+ [ error "\254\099\003\128\000"; error "\254\099\003\128\000\000\233" ]
7373+ in
7474+ List.iter
7575+ (fun (addr, exn) ->
7676+ assert_raises ~msg:(String.escaped addr) exn (fun () ->
7777+ of_cstruct_exn (Cstruct.of_string addr)))
7878+ addrs
7979+8080+let test_make_local () =
8181+ let () = Random.self_init () in
8282+ let bytegen i = if i = 0 then 253 else 255 - i in
8383+ let local_addr = make_local bytegen in
8484+ assert_equal ~msg:"is_local" (is_local local_addr) true;
8585+ assert_equal ~msg:"is_unicast" (is_unicast local_addr) true;
8686+ assert_equal ~msg:"localize" (to_octets local_addr).[0] (Char.chr 254);
8787+ for i = 1 to 5 do
8888+ assert_equal
8989+ ~msg:("addr.[" ^ string_of_int i ^ "]")
9090+ (to_octets local_addr).[i]
9191+ (Char.chr (bytegen i))
9292+ done;
9393+ assert_equal ~msg:"get_oui" (get_oui local_addr)
9494+ ((254 lsl 16) + (254 lsl 8) + 253)
9595+9696+let test_bad_sep_mix () =
9797+ let s = "00:11-22:33-44:55" in
9898+ assert_result_failure ~msg:s (of_string s)
9999+100100+let suite =
101101+ "Test"
102102+ >::: [
103103+ "string_rt" >:: test_string_rt;
104104+ "string_rt_bad" >:: test_string_rt_bad;
105105+ "bytes_rt" >:: test_bytes_rt;
106106+ "bytes_rt_bad" >:: test_bytes_rt_bad;
107107+ "cstruct_rt" >:: test_cstruct_rt;
108108+ "cstruct_rt_bad" >:: test_cstruct_rt_bad;
109109+ "make_local" >:: test_make_local;
110110+ "bad_sep_mix" >:: test_bad_sep_mix;
111111+ ]
112112+;;
113113+114114+run_test_tt_main suite
+28
vendor/opam/ipaddr/lib_test/test_ppx.ml
···11+(*
22+ * Copyright (c) 2018 Anil Madhavapeddy <anil@recoil.org>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ *
1616+ *)
1717+1818+type t = {
1919+ ip : Ipaddr_sexp.t;
2020+ ipv6 : Ipaddr_sexp.V6.t;
2121+ ipv6p : Ipaddr_sexp.V6.Prefix.t;
2222+ ipv4 : Ipaddr_sexp.V4.t;
2323+ ipv4p : Ipaddr_sexp.V4.Prefix.t;
2424+ scope : Ipaddr_sexp.scope;
2525+ mac : Macaddr_sexp.t;
2626+ ipp : Ipaddr_sexp.Prefix.t;
2727+}
2828+[@@deriving sexp]