Codebase list ocaml-ipaddr / a03d5e8
New upstream version 5.0.1 Stephane Glondu 3 years ago
34 changed file(s) with 2051 addition(s) and 1967 deletion(s). Raw diff Collapse all Expand all
+0
-4
.gitignore less more
0 _build
1 *.install
2 **/*.merlin
3 .*.swp
+0
-18
.travis.yml less more
0 language: c
1 sudo: false
2 services:
3 - docker
4 install: wget https://raw.githubusercontent.com/ocaml/ocaml-travisci-skeleton/master/.travis-docker.sh
5 script: bash ./.travis-docker.sh
6 env:
7 global:
8 - PACKAGE="ipaddr"
9 - PINS="ipaddr:. macaddr:. ipaddr-sexp:. macaddr-sexp:. ipaddr-cstruct:. macaddr-cstruct:."
10 matrix:
11 - DISTRO=debian-stable OCAML_VERSION=4.04
12 - DISTRO=ubuntu OCAML_VERSION=4.05
13 - DISTRO=alpine OCAML_VERSION=4.06
14 - DISTRO=fedora OCAML_VERSION=4.07
15 - DISTRO=alpine OCAML_VERSION=4.08
16 - DISTRO=alpine OCAML_VERSION=4.09
17 - DISTRO=alpine OCAML_VERSION=4.10
0 ## v5.0.0
0 ## v5.0.1 (2020-09-30)
1
2 * Fix V4.Prefix.broadcast and last with /32 prefixes (#102 @verbosemode)
3
4 ## v5.0.0 (2020-06-16)
15
26 * Do not zero out the non-prefix-length part of the address in
37 `{V4,V6}.Prefix.t` (#99 @hannesm)
4141 - `ipaddr-sexp`: S-expression converters for Ipaddr.
4242 - `macaddr-sexp`: S-expression converters for Macaddr.
4343
44 ## Installation and development
45
46 The packages are released to the opam-repository. An `opam install ipaddr`
47 (or any other above mentioned package) will install it. If you want to install
48 the latest development commit, `opam pin add ipaddr --dev` will do this.
49
50 A local build, after a `git clone` can be done with `dune build`, a
51 `dune runtest` compiles and executes the testsuite. If dependencies are missing,
52 `opam install (-t) --deps-only .` in the cloned directory will install them.
53
54 The auto-formatter [`ocamlformat`](https://github.com/ocaml-ppx/ocamlformat) is
55 used, please execute `dune build @fmt --auto-promote` before submitting a pull
56 request.
57
4458 ## Contact
4559
4660 - Issues: <https://github.com/mirage/ocaml-ipaddr/issues>
00 (lang dune 1.9)
11 (name ipaddr)
2 (version v5.0.1)
23 (allow_approximate_merlin)
4 (using fmt 1.1)
0 version: "5.0.1"
01 opam-version: "2.0"
12 maintainer: "anil@recoil.org"
23 authors: ["David Sheets" "Anil Madhavapeddy" "Hugo Heuzard"]
89 bug-reports: "https://github.com/mirage/ocaml-ipaddr/issues"
910 depends: [
1011 "ocaml" {>= "4.04.0"}
11 "dune"
12 "ipaddr" {=version}
12 "dune" {>= "1.9.0"}
13 "ipaddr" {= version}
1314 "cstruct"
1415 ]
1516 build: [
2021 dev-repo: "git+https://github.com/mirage/ocaml-ipaddr.git"
2122 description: """
2223 Cstruct convertions for macaddr
23 """
24 """
0 version: "5.0.1"
01 opam-version: "2.0"
12 maintainer: "anil@recoil.org"
23 authors: ["David Sheets" "Anil Madhavapeddy" "Hugo Heuzard"]
1213 bug-reports: "https://github.com/mirage/ocaml-ipaddr/issues"
1314 depends: [
1415 "ocaml" {>= "4.04.0"}
15 "dune"
16 "ipaddr"
17 "ipaddr-cstruct" {with-test}
16 "dune" {>= "1.9.0"}
17 "ipaddr" {= version}
18 "ipaddr-cstruct" {with-test & = version}
1819 "ounit" {with-test}
1920 "ppx_sexp_conv" {>= "v0.9.0"}
2021 ]
2324 ["dune" "build" "-p" name "-j" jobs]
2425 ["dune" "runtest" "-p" name "-j" jobs] {with-test}
2526 ]
26 dev-repo: "git+https://github.com/mirage/ocaml-ipaddr.git"
27 dev-repo: "git+https://github.com/mirage/ocaml-ipaddr.git"
0 version: "5.0.1"
01 opam-version: "2.0"
12 maintainer: "anil@recoil.org"
23 authors: ["David Sheets" "Anil Madhavapeddy" "Hugo Heuzard"]
2728 bug-reports: "https://github.com/mirage/ocaml-ipaddr/issues"
2829 depends: [
2930 "ocaml" {>= "4.04.0"}
30 "dune"
31 "macaddr" {=version}
31 "dune" {>= "1.9.0"}
32 "macaddr" {= version}
3233 "stdlib-shims"
3334 "domain-name" {>= "0.3.0"}
3435 "ounit" {with-test}
3940 ["dune" "build" "-p" name "-j" jobs]
4041 ["dune" "runtest" "-p" name "-j" jobs] {with-test}
4142 ]
42 dev-repo: "git+https://github.com/mirage/ocaml-ipaddr.git"
43 dev-repo: "git+https://github.com/mirage/ocaml-ipaddr.git"
00 (library
1 (name ipaddr)
1 (name ipaddr)
22 (public_name ipaddr)
33 (modules ipaddr)
44 (libraries macaddr domain-name stdlib-shims))
55
66 (library
7 (name macaddr)
7 (name macaddr)
88 (public_name macaddr)
99 (modules macaddr))
1010
1111 (library
12 (name ipaddr_sexp)
12 (name ipaddr_sexp)
1313 (public_name ipaddr-sexp)
1414 (modules ipaddr_sexp)
15 (preprocess (pps ppx_sexp_conv))
15 (preprocess
16 (pps ppx_sexp_conv))
1617 (libraries ipaddr sexplib0))
1718
1819 (library
19 (name macaddr_sexp)
20 (name macaddr_sexp)
2021 (public_name macaddr-sexp)
2122 (modules macaddr_sexp)
22 (preprocess (pps ppx_sexp_conv))
23 (preprocess
24 (pps ppx_sexp_conv))
2325 (libraries macaddr sexplib0))
2426
2527 (library
26 (name ipaddr_unix)
28 (name ipaddr_unix)
2729 (public_name ipaddr.unix)
2830 (modules ipaddr_unix)
2931 (libraries unix ipaddr))
3032
3133 (library
32 (name ipaddr_cstruct)
34 (name ipaddr_cstruct)
3335 (public_name ipaddr-cstruct)
3436 (modules ipaddr_cstruct)
3537 (libraries ipaddr cstruct))
3638
3739 (library
38 (name macaddr_cstruct)
40 (name macaddr_cstruct)
3941 (public_name macaddr-cstruct)
4042 (modules macaddr_cstruct)
4143 (libraries macaddr cstruct))
4244
4345 (library
44 (name ipaddr_top)
46 (name ipaddr_top)
4547 (public_name ipaddr.top)
4648 (modules ipaddr_top)
4749 (libraries macaddr.top ipaddr compiler-libs))
4850
4951 (library
50 (name macaddr_top)
52 (name macaddr_top)
5153 (public_name macaddr.top)
5254 (modules macaddr_top)
5355 (libraries macaddr compiler-libs))
1616
1717 exception Parse_error of string * string
1818
19 type scope =
20 | Point
21 | Interface
22 | Link
23 | Admin
24 | Site
25 | Organization
26 | Global
19 type scope = Point | Interface | Link | Admin | Site | Organization | Global
2720
2821 let try_with_result fn a =
29 try Ok (fn a)
30 with Parse_error (msg, _) -> Error (`Msg ("Ipaddr: " ^ msg))
31
32 let failwith_msg = function
33 | Ok x -> x
34 | Error (`Msg m) -> failwith m
22 try Ok (fn a) with Parse_error (msg, _) -> Error (`Msg ("Ipaddr: " ^ msg))
23
24 let failwith_msg = function Ok x -> x | Error (`Msg m) -> failwith m
3525
3626 let map_result v f = match v with Ok v -> Ok (f v) | Error _ as e -> e
3727
3828 let string_of_scope = function
39 | Point -> "point"
40 | Interface -> "interface"
41 | Link -> "link"
42 | Admin -> "admin"
43 | Site -> "site"
44 | Organization -> "organization"
45 | Global -> "global"
29 | Point -> "point"
30 | Interface -> "interface"
31 | Link -> "link"
32 | Admin -> "admin"
33 | Site -> "site"
34 | Organization -> "organization"
35 | Global -> "global"
4636
4737 let scope_of_string = function
48 | "point" -> Ok Point
49 | "interface" -> Ok Interface
50 | "link" -> Ok Link
51 | "admin" -> Ok Admin
52 | "site" -> Ok Site
53 | "organization" -> Ok Organization
54 | "global" -> Ok Global
55 | s -> Error (`Msg ("unknown scope: " ^ s))
56
57 let pp_scope fmt s =
58 Format.pp_print_string fmt (string_of_scope s)
59
60 let (~|) = Int32.of_int
61 let (|~) = Int32.to_int
62 let (&&&) x y = Int32.logand x y
63 let (|||) x y = Int32.logor x y
64 let (<|<) x y = Int32.shift_left x y
65 let (>|>) x y = Int32.shift_right_logical x y
66 let (>!) x y = (x >|> y) &&& 0xFF_l
67 let (<!) x y = (x &&& 0xFF_l) <|< y
38 | "point" -> Ok Point
39 | "interface" -> Ok Interface
40 | "link" -> Ok Link
41 | "admin" -> Ok Admin
42 | "site" -> Ok Site
43 | "organization" -> Ok Organization
44 | "global" -> Ok Global
45 | s -> Error (`Msg ("unknown scope: " ^ s))
46
47 let pp_scope fmt s = Format.pp_print_string fmt (string_of_scope s)
48
49 let ( ~| ) = Int32.of_int
50
51 let ( |~ ) = Int32.to_int
52
53 let ( &&& ) x y = Int32.logand x y
54
55 let ( ||| ) x y = Int32.logor x y
56
57 let ( <|< ) x y = Int32.shift_left x y
58
59 let ( >|> ) x y = Int32.shift_right_logical x y
60
61 let ( >! ) x y = x >|> y &&& 0xFF_l
62
63 let ( <! ) x y = x &&& 0xFF_l <|< y
6864
6965 let need_more x = Parse_error ("not enough data", x)
7066
7167 let char_0 = int_of_char '0'
68
7269 let char_a = int_of_char 'a'
70
7371 let char_A = int_of_char 'A'
7472
75 let int_of_char c = match c with
76 | '0'..'9' -> Stdlib.int_of_char c - char_0
77 | 'a'..'f' -> 10 + Stdlib.int_of_char c - char_a
78 | 'A'..'F' -> 10 + Stdlib.int_of_char c - char_A
73 let int_of_char c =
74 match c with
75 | '0' .. '9' -> Stdlib.int_of_char c - char_0
76 | 'a' .. 'f' -> 10 + Stdlib.int_of_char c - char_a
77 | 'A' .. 'F' -> 10 + Stdlib.int_of_char c - char_A
7978 | _ -> -1
8079
8180 let bad_char i s =
82 let msg = Printf.sprintf "invalid character '%c' at %d" s.[i] i
83 in Parse_error (msg, s)
84
85 let is_number base n = n >=0 && n < base
81 let msg = Printf.sprintf "invalid character '%c' at %d" s.[i] i in
82 Parse_error (msg, s)
83
84 let is_number base n = n >= 0 && n < base
8685
8786 let parse_int base s i =
8887 let len = String.length s in
8988 let rec next prev =
9089 let j = !i in
9190 if j >= len then prev
92 else let c = s.[j] in
93 let k = int_of_char c in
94 if is_number base k
95 then (incr i; next (prev*base + k))
96 else prev
91 else
92 let c = s.[j] in
93 let k = int_of_char c in
94 if is_number base k then (
95 incr i;
96 next ((prev * base) + k))
97 else prev
9798 in
9899 let i = !i in
99 if i < len
100 then if is_number base (int_of_char s.[i])
101 then next 0
102 else raise (bad_char i s)
100 if i < len then
101 if is_number base (int_of_char s.[i]) then next 0 else raise (bad_char i s)
103102 else raise (need_more s)
104103
105104 let parse_dec_int s i = parse_int 10 s i
105
106106 let parse_hex_int s i = parse_int 16 s i
107
107108 let expect_char s i c =
108 if !i < String.length s
109 then if s.[!i] <> c then raise (bad_char !i s) else incr i
109 if !i < String.length s then
110 if s.[!i] <> c then raise (bad_char !i s) else incr i
110111 else raise (need_more s)
111 let expect_end s i =
112 if String.length s <= !i
113 then ()
114 else raise (bad_char !i s)
112
113 let expect_end s i = if String.length s <= !i then () else raise (bad_char !i s)
115114
116115 let hex_char_of_int = function
117 | 0 -> '0'
118 | 1 -> '1'
119 | 2 -> '2'
120 | 3 -> '3'
121 | 4 -> '4'
122 | 5 -> '5'
123 | 6 -> '6'
124 | 7 -> '7'
125 | 8 -> '8'
126 | 9 -> '9'
116 | 0 -> '0'
117 | 1 -> '1'
118 | 2 -> '2'
119 | 3 -> '3'
120 | 4 -> '4'
121 | 5 -> '5'
122 | 6 -> '6'
123 | 7 -> '7'
124 | 8 -> '8'
125 | 9 -> '9'
127126 | 10 -> 'a'
128127 | 11 -> 'b'
129128 | 12 -> 'c'
130129 | 13 -> 'd'
131130 | 14 -> 'e'
132131 | 15 -> 'f'
133 | _ -> raise (Invalid_argument "not a hex int")
132 | _ -> raise (Invalid_argument "not a hex int")
134133
135134 let hex_string_of_int32 i = String.make 1 (hex_char_of_int (Int32.to_int i))
136135
137136 module V4 = struct
138137 type t = int32
139138
140 let compare a b = (* ignore the sign *)
139 let compare a b =
140 (* ignore the sign *)
141141 let c = Int32.compare (a >|> 1) (b >|> 1) in
142142 if c = 0 then Int32.compare (a &&& 1l) (b &&& 1l) else c
143143
144 let make a b c d =
145 ((~| a <! 24) ||| (~| b <! 16)) ||| ((~| c <! 8) ||| (~| d <! 0))
144 let make a b c d = ~|a <! 24 ||| (~|b <! 16) ||| (~|c <! 8 ||| (~|d <! 0))
146145
147146 (* parsing *)
148147
155154 expect_char s i '.';
156155 let d = parse_dec_int s i in
157156 let valid a = a land 0xff <> a in
158 if valid a
159 then raise (Parse_error ("first octet out of bounds", s))
160 else if valid b
161 then raise (Parse_error ("second octet out of bounds", s))
162 else if valid c
163 then raise (Parse_error ("third octet out of bounds", s))
164 else if valid d
165 then raise (Parse_error ("fourth octet out of bounds", s))
157 if valid a then raise (Parse_error ("first octet out of bounds", s))
158 else if valid b then raise (Parse_error ("second octet out of bounds", s))
159 else if valid c then raise (Parse_error ("third octet out of bounds", s))
160 else if valid d then raise (Parse_error ("fourth octet out of bounds", s))
166161 else make a b c d
167162
168163 (* string conversion *)
185180 to_buffer b i;
186181 Buffer.contents b
187182
188 let pp ppf i =
189 Format.fprintf ppf "%s" (to_string i)
183 let pp ppf i = Format.fprintf ppf "%s" (to_string i)
190184
191185 (* Octets conversion *)
192186
193 let of_octets_exn ?(off=0) bs =
187 let of_octets_exn ?(off = 0) bs =
194188 try
195189 make
196 (Char.code bs.[0 + off])
197 (Char.code bs.[1 + off])
198 (Char.code bs.[2 + off])
199 (Char.code bs.[3 + off])
190 (Char.code bs.[0 + off])
191 (Char.code bs.[1 + off])
192 (Char.code bs.[2 + off])
193 (Char.code bs.[3 + off])
200194 with _ -> raise (need_more bs)
201195
202196 let of_octets ?off bs = try_with_result (of_octets_exn ?off) bs
203197
204 let write_octets_exn ?(off=0) i b =
198 let write_octets_exn ?(off = 0) i b =
205199 try
206 Bytes.set b (0 + off) (Char.chr ((|~) (i >! 24)));
207 Bytes.set b (1 + off) (Char.chr ((|~) (i >! 16)));
208 Bytes.set b (2 + off) (Char.chr ((|~) (i >! 8)));
209 Bytes.set b (3 + off) (Char.chr ((|~) (i >! 0)))
200 Bytes.set b (0 + off) (Char.chr (( |~ ) (i >! 24)));
201 Bytes.set b (1 + off) (Char.chr (( |~ ) (i >! 16)));
202 Bytes.set b (2 + off) (Char.chr (( |~ ) (i >! 8)));
203 Bytes.set b (3 + off) (Char.chr (( |~ ) (i >! 0)))
210204 with _ -> raise (need_more (Bytes.to_string b))
211205
212206 let write_octets ?off i bs = try_with_result (write_octets_exn ?off i) bs
213207
214208 let to_octets i =
215209 String.init 4 (function
216 | 0 -> Char.chr ((|~) (i >! 24))
217 | 1 -> Char.chr ((|~) (i >! 16))
218 | 2 -> Char.chr ((|~) (i >! 8))
219 | 3 -> Char.chr ((|~) (i >! 0))
210 | 0 -> Char.chr (( |~ ) (i >! 24))
211 | 1 -> Char.chr (( |~ ) (i >! 16))
212 | 2 -> Char.chr (( |~ ) (i >! 8))
213 | 3 -> Char.chr (( |~ ) (i >! 0))
220214 | _ -> assert false)
221215
222216 (* Int32 *)
223217 let of_int32 i = i
218
224219 let to_int32 i = i
225220
226221 (* Int16 *)
227 let of_int16 (a,b) = (~| a <|< 16) ||| (~| b)
228 let to_int16 a = ((|~) (a >|> 16), (|~) (a &&& 0xFF_FF_l))
222 let of_int16 (a, b) = ~|a <|< 16 ||| ~|b
223
224 let to_int16 a = (( |~ ) (a >|> 16), ( |~ ) (a &&& 0xFF_FF_l))
229225
230226 (* MAC *)
231227 (* {{:http://tools.ietf.org/html/rfc1112#section-6.2}RFC 1112}. *)
234230 Bytes.set macb 0 (Char.chr 0x01);
235231 Bytes.set macb 1 (Char.chr 0x00);
236232 Bytes.set macb 2 (Char.chr 0x5E);
237 Bytes.set macb 3 (Char.chr ((|~) (i >|> 16 &&& 0x7F_l)));
238 Bytes.set macb 4 (Char.chr ((|~) (i >! 8)));
239 Bytes.set macb 5 (Char.chr ((|~) (i >! 0)));
233 Bytes.set macb 3 (Char.chr (( |~ ) (i >|> 16 &&& 0x7F_l)));
234 Bytes.set macb 4 (Char.chr (( |~ ) (i >! 8)));
235 Bytes.set macb 5 (Char.chr (( |~ ) (i >! 0)));
240236 Macaddr.of_octets_exn (Bytes.to_string macb)
241237
242238 (* Host *)
243239 let to_domain_name i =
244 let name = [
245 Int32.to_string (i >! 0);
246 Int32.to_string (i >! 8);
247 Int32.to_string (i >! 16);
248 Int32.to_string (i >! 24);
249 "in-addr";
250 "arpa" ]
240 let name =
241 [
242 Int32.to_string (i >! 0);
243 Int32.to_string (i >! 8);
244 Int32.to_string (i >! 16);
245 Int32.to_string (i >! 24);
246 "in-addr";
247 "arpa";
248 ]
251249 in
252250 Domain_name.(host_exn (of_strings_exn name))
253251
254252 let of_domain_name n =
255253 match Domain_name.to_strings n with
256 | [ a ; b ; c ; d ; in_addr ; arpa ] when
257 Domain_name.(equal_label arpa "arpa" && equal_label in_addr "in-addr") ->
258 begin
254 | [ a; b; c; d; in_addr; arpa ]
255 when Domain_name.(
256 equal_label arpa "arpa" && equal_label in_addr "in-addr") -> (
259257 let conv bits data =
260258 let i = Int32.of_int (parse_dec_int data (ref 0)) in
261259 if i > 0xFFl then
262260 raise (Parse_error ("label with a too big number", data))
263 else
264 i <! bits
261 else i <! bits
265262 in
266263 try
267264 let ( + ) = Int32.add in
268 Some ((conv 0 a) + (conv 8 b) + (conv 16 c) + (conv 24 d))
269 with
270 | Parse_error _ -> None
271 end
265 Some (conv 0 a + conv 8 b + conv 16 c + conv 24 d)
266 with Parse_error _ -> None)
272267 | _ -> None
273268
274269 let succ t =
275270 if Int32.equal t 0xFF_FF_FF_FFl then
276271 Error (`Msg "Ipaddr: highest address has been reached")
277 else
278 Ok (Int32.succ t)
272 else Ok (Int32.succ t)
279273
280274 let pred t =
281275 if Int32.equal t 0x00_00_00_00l then
282276 Error (`Msg "Ipaddr: lowest address has been reached")
283 else
284 Ok (Int32.pred t)
277 else Ok (Int32.pred t)
285278
286279 (* constant *)
287280
288 let any = make 0 0 0 0
289 let unspecified = make 0 0 0 0
290 let broadcast = make 255 255 255 255
291 let localhost = make 127 0 0 1
292 let nodes = make 224 0 0 1
293 let routers = make 224 0 0 2
281 let any = make 0 0 0 0
282
283 let unspecified = make 0 0 0 0
284
285 let broadcast = make 255 255 255 255
286
287 let localhost = make 127 0 0 1
288
289 let nodes = make 224 0 0 1
290
291 let routers = make 224 0 0 2
294292
295293 module Prefix = struct
296294 type addr = t
295
297296 type t = addr * int
298297
299 let compare (pre,sz) (pre',sz') =
298 let compare (pre, sz) (pre', sz') =
300299 let c = compare pre pre' in
301300 if c = 0 then Stdlib.compare sz sz' else c
302301
305304 let mask sz =
306305 if sz <= 0 then 0_l
307306 else if sz >= 32 then 0x0_FF_FF_FF_FF_l
308 else 0x0_FF_FF_FF_FF_l <|< (32 - sz)
309
310 let prefix (pre,sz) = (pre &&& (mask sz), sz)
311
312 let make sz pre = (pre,sz)
313
314 let network_address (pre,sz) addr =
315 (pre &&& (mask sz)) ||| (addr &&& Int32.lognot (mask sz))
307 else 0x0_FF_FF_FF_FF_l <|< 32 - sz
308
309 let prefix (pre, sz) = (pre &&& mask sz, sz)
310
311 let make sz pre = (pre, sz)
312
313 let network_address (pre, sz) addr =
314 pre &&& mask sz ||| (addr &&& Int32.lognot (mask sz))
316315
317316 (* string conversion *)
318317
320319 let quad = of_string_raw s i in
321320 expect_char s i '/';
322321 let p = parse_dec_int s i in
323 if p > 32 || p < 0
324 then raise (Parse_error ("invalid prefix size", s));
325 (p,quad)
322 if p > 32 || p < 0 then raise (Parse_error ("invalid prefix size", s));
323 (p, quad)
326324
327325 let of_string_raw s i =
328 let (p,quad) = _of_string_raw s i in
326 let p, quad = _of_string_raw s i in
329327 make p quad
330328
331329 let _of_string_exn s =
334332 expect_end s i;
335333 res
336334
337 let of_string_exn s = let (p,quad) = _of_string_exn s in make p quad
335 let of_string_exn s =
336 let p, quad = _of_string_exn s in
337 make p quad
338338
339339 let of_string s = try_with_result of_string_exn s
340340
341341 let _of_netmask_exn ~netmask address =
342342 let rec find_greatest_one bits i =
343 if bits = 0_l then i-1 else find_greatest_one (bits >|> 1) (i+1)
343 if bits = 0_l then i - 1 else find_greatest_one (bits >|> 1) (i + 1)
344344 in
345 let one = netmask &&& (Int32.neg netmask) in
346 let sz = 32 - (find_greatest_one one (if one = 0_l then 33 else 0)) in
347 if netmask <> (mask sz)
348 then raise (Parse_error ("invalid netmask",to_string netmask))
345 let one = netmask &&& Int32.neg netmask in
346 let sz = 32 - find_greatest_one one (if one = 0_l then 33 else 0) in
347 if netmask <> mask sz then
348 raise (Parse_error ("invalid netmask", to_string netmask))
349349 else make sz address
350350
351351 let of_netmask_exn ~netmask ~address = _of_netmask_exn ~netmask address
353353 let of_netmask ~netmask ~address =
354354 try_with_result (_of_netmask_exn ~netmask) address
355355
356 let to_buffer buf (pre,sz) = Printf.bprintf buf "%a/%d" to_buffer pre sz
356 let to_buffer buf (pre, sz) = Printf.bprintf buf "%a/%d" to_buffer pre sz
357357
358358 let to_string subnet =
359359 let b = Buffer.create 18 in
360360 to_buffer b subnet;
361361 Buffer.contents b
362362
363 let pp ppf i =
364 Format.fprintf ppf "%s" (to_string i)
365
366 let mem ip (pre,sz) =
363 let pp ppf i = Format.fprintf ppf "%s" (to_string i)
364
365 let mem ip (pre, sz) =
367366 let m = mask sz in
368 (ip &&& m) = (pre &&& m)
369
370 let subset ~subnet:(pre1,sz1) ~network:(pre2,sz2) =
371 sz1 >= sz2 && mem pre1 (pre2,sz2)
367 ip &&& m = (pre &&& m)
368
369 let subset ~subnet:(pre1, sz1) ~network:(pre2, sz2) =
370 sz1 >= sz2 && mem pre1 (pre2, sz2)
372371
373372 let of_addr ip = make 32 ip
374373
375 let global = make 0 (ip 0 0 0 0)
376 let relative = make 8 (ip 0 0 0 0)
377 let loopback = make 8 (ip 127 0 0 0)
378 let link = make 16 (ip 169 254 0 0)
379 let multicast = make 4 (ip 224 0 0 0)
380 let multicast_org = make 14 (ip 239 192 0 0)
374 let global = make 0 (ip 0 0 0 0)
375
376 let relative = make 8 (ip 0 0 0 0)
377
378 let loopback = make 8 (ip 127 0 0 0)
379
380 let link = make 16 (ip 169 254 0 0)
381
382 let multicast = make 4 (ip 224 0 0 0)
383
384 let multicast_org = make 14 (ip 239 192 0 0)
385
381386 let multicast_admin = make 16 (ip 239 255 0 0)
382 let multicast_link = make 24 (ip 224 0 0 0)
387
388 let multicast_link = make 24 (ip 224 0 0 0)
389
383390 (* http://tools.ietf.org/html/rfc2365 *)
384391
385 let private_10 = make 8 (ip 10 0 0 0)
386 let private_172 = make 12 (ip 172 16 0 0)
392 let private_10 = make 8 (ip 10 0 0 0)
393
394 let private_172 = make 12 (ip 172 16 0 0)
395
387396 let private_192 = make 16 (ip 192 168 0 0)
388397
389 let private_blocks = [
390 loopback ; link ; private_10 ; private_172 ; private_192
391 ]
392
393 let broadcast (pre,sz) = pre ||| (0x0_FF_FF_FF_FF_l >|> sz)
394 let network (pre,sz) = pre &&& mask sz
395 let address (addr,_) = addr
396 let bits (_,sz) = sz
398 let private_blocks =
399 [ loopback; link; private_10; private_172; private_192 ]
400
401 let broadcast (pre, sz) =
402 Int32.logor pre (Int32.logxor (mask sz) 0xFF_FF_FF_FFl)
403
404 let network (pre, sz) = pre &&& mask sz
405
406 let address (addr, _) = addr
407
408 let bits (_, sz) = sz
409
397410 let netmask subnet = mask (bits subnet)
398411
399 let first (_,sz as cidr) =
400 if sz > 30 then
401 network cidr
402 else
403 network cidr |> succ |> failwith_msg
404
405 let last (_,sz as cidr) =
406 if sz > 30 then
407 broadcast cidr
408 else
409 broadcast cidr |> pred |> failwith_msg
412 let first ((_, sz) as cidr) =
413 if sz > 30 then network cidr else network cidr |> succ |> failwith_msg
414
415 let last ((_, sz) as cidr) =
416 if sz > 30 then broadcast cidr else broadcast cidr |> pred |> failwith_msg
410417 end
411418
412419 (* TODO: this could be optimized with something trie-like *)
418425 else if i = unspecified then Point
419426 else if i = broadcast then Admin
420427 else if mem Prefix.relative then Admin
421 else if mem Prefix.multicast
422 then (if mem Prefix.multicast_org then Organization
428 else if mem Prefix.multicast then
429 if mem Prefix.multicast_org then Organization
423430 else if mem Prefix.multicast_admin then Admin
424431 else if mem Prefix.multicast_link then Link
425 else Global)
432 else Global
426433 else Global
427434
428 let is_global i = (scope i) = Global
435 let is_global i = scope i = Global
436
429437 let is_multicast i = Prefix.(mem i multicast)
430 let is_private i = (scope i) <> Global
438
439 let is_private i = scope i <> Global
431440 end
432441
433442 module B128 = struct
434443 type t = int32 * int32 * int32 * int32
435444
436445 let of_int64 (a, b) =
437 Int64.(
438 to_int32 (shift_right_logical a 32),
439 to_int32 a,
440 to_int32 (shift_right_logical b 32),
441 to_int32 b)
442 let to_int64 (a,b,c,d) =
443 Int64.(
444 logor (shift_left (of_int32 a) 32) (of_int32 b),
445 logor (shift_left (of_int32 c) 32) (of_int32 d))
446 Int64.
447 ( to_int32 (shift_right_logical a 32),
448 to_int32 a,
449 to_int32 (shift_right_logical b 32),
450 to_int32 b )
451
452 let to_int64 (a, b, c, d) =
453 Int64.
454 ( logor (shift_left (of_int32 a) 32) (of_int32 b),
455 logor (shift_left (of_int32 c) 32) (of_int32 d) )
446456
447457 let of_int32 x = x
458
448459 let to_int32 x = x
449460
450461 let of_int16 (a, b, c, d, e, f, g, h) =
451 V4.of_int16 (a,b),
452 V4.of_int16 (c,d),
453 V4.of_int16 (e,f),
454 V4.of_int16 (g,h)
455
456 let to_int16 (x,y,z,t) =
457 let a,b = V4.to_int16 x
458 and c,d = V4.to_int16 y
459 and e,f = V4.to_int16 z
460 and g,h = V4.to_int16 t
462 ( V4.of_int16 (a, b),
463 V4.of_int16 (c, d),
464 V4.of_int16 (e, f),
465 V4.of_int16 (g, h) )
466
467 let to_int16 (x, y, z, t) =
468 let a, b = V4.to_int16 x
469 and c, d = V4.to_int16 y
470 and e, f = V4.to_int16 z
471 and g, h = V4.to_int16 t in
472 (a, b, c, d, e, f, g, h)
473
474 let write_octets_exn ?(off = 0) (a, b, c, d) byte =
475 V4.write_octets_exn ~off a byte;
476 V4.write_octets_exn ~off:(off + 4) b byte;
477 V4.write_octets_exn ~off:(off + 8) c byte;
478 V4.write_octets_exn ~off:(off + 12) d byte
479
480 let compare (a1, b1, c1, d1) (a2, b2, c2, d2) =
481 match V4.compare a1 a2 with
482 | 0 -> (
483 match V4.compare b1 b2 with
484 | 0 -> ( match V4.compare c1 c2 with 0 -> V4.compare d1 d2 | n -> n)
485 | n -> n)
486 | n -> n
487
488 let logand (a1, b1, c1, d1) (a2, b2, c2, d2) =
489 (a1 &&& a2, b1 &&& b2, c1 &&& c2, d1 &&& d2)
490
491 let logor (a1, b1, c1, d1) (a2, b2, c2, d2) =
492 (a1 ||| a2, b1 ||| b2, c1 ||| c2, d1 ||| d2)
493
494 let lognot (a, b, c, d) = Int32.(lognot a, lognot b, lognot c, lognot d)
495
496 let succ (a, b, c, d) =
497 let cb (n, tl) v =
498 match n with
499 | 0l -> (0l, v :: tl)
500 | n ->
501 let n = if Int32.equal v 0xFF_FF_FF_FFl then n else 0l in
502 (n, Int32.succ v :: tl)
461503 in
462 (a,b,c,d,e,f,g,h)
463
464 let write_octets_exn ?(off=0) (a,b,c,d) byte =
465 V4.write_octets_exn ~off a byte;
466 V4.write_octets_exn ~off:(off+4) b byte;
467 V4.write_octets_exn ~off:(off+8) c byte;
468 V4.write_octets_exn ~off:(off+12) d byte
469
470 let compare (a1,b1,c1,d1) (a2,b2,c2,d2) =
471 match V4.compare a1 a2 with
472 | 0 -> begin
473 match V4.compare b1 b2 with
474 | 0 -> begin
475 match V4.compare c1 c2 with
476 | 0 -> V4.compare d1 d2
477 | n -> n end
478 | n -> n end
479 | n -> n
480
481 let logand (a1,b1,c1,d1) (a2,b2,c2,d2) =
482 (a1 &&& a2, b1 &&& b2, c1 &&& c2, d1 &&& d2)
483
484 let logor (a1,b1,c1,d1) (a2,b2,c2,d2) =
485 (a1 ||| a2, b1 ||| b2, c1 ||| c2, d1 ||| d2)
486
487 let lognot (a,b,c,d) = Int32.(lognot a, lognot b, lognot c, lognot d)
488
489 let succ (a,b,c,d) =
490 let cb (n,tl) v =
504 match List.fold_left cb (1l, []) [ d; c; b; a ] with
505 | 0l, [ a; b; c; d ] -> Ok (of_int32 (a, b, c, d))
506 | n, [ _; _; _; _ ] when n > 0l ->
507 Error (`Msg "Ipaddr: highest address has been reached")
508 | _ -> Error (`Msg "Ipaddr: unexpected error with B128")
509
510 let pred (a, b, c, d) =
511 let cb (n, tl) v =
491512 match n with
492 | 0l -> (0l,v::tl)
513 | 0l -> (0l, v :: tl)
493514 | n ->
494 let n =
495 if Int32.equal v 0xFF_FF_FF_FFl then
496 n
497 else
498 0l
499 in
500 (n,Int32.succ v::tl)
515 let n = if v = 0x00_00_00_00l then n else 0l in
516 (n, Int32.pred v :: tl)
501517 in
502 match List.fold_left cb (1l,[]) [d;c;b;a] with
503 | 0l, [a;b;c;d] -> Ok (of_int32 (a,b,c,d))
504 | n, [_;_;_;_] when n > 0l ->
505 Error (`Msg "Ipaddr: highest address has been reached")
518 match List.fold_left cb (-1l, []) [ d; c; b; a ] with
519 | 0l, [ a; b; c; d ] -> Ok (of_int32 (a, b, c, d))
520 | n, [ _; _; _; _ ] when n < 0l ->
521 Error (`Msg "Ipaddr: lowest address has been reached")
506522 | _ -> Error (`Msg "Ipaddr: unexpected error with B128")
507523
508 let pred (a,b,c,d) =
509 let cb (n,tl) v =
510 match n with
511 | 0l -> (0l,v::tl)
512 | n ->
513 let n =
514 if v = 0x00_00_00_00l then
515 n
516 else
517 0l
518 in
519 (n,Int32.pred v::tl)
520 in
521 match List.fold_left cb (-1l,[]) [d;c;b;a] with
522 | 0l, [a;b;c;d] -> Ok (of_int32 (a,b,c,d))
523 | n, [_;_;_;_] when n < 0l ->
524 Error (`Msg "Ipaddr: lowest address has been reached")
525 | _ -> Error (`Msg "Ipaddr: unexpected error with B128")
526
527 let shift_right (a,b,c,d) sz =
528 let rec loop (a,b,c,d) sz =
529 if sz < 32 then (sz, (a,b,c,d))
530 else loop (0l,a,b,c) (sz - 32)
531 in
532 let (sz, (a,b,c,d)) = loop (a,b,c,d) sz in
533 let fn (saved,tl) part =
534 let new_saved = Int32.logand part (0xFF_FF_FF_FFl >|> sz) in
535 let new_part = (part >|> sz) ||| (saved <|< 32 - sz) in
536 (new_saved, new_part::tl)
537 in
538 match List.fold_left fn (0l,[]) [a;b;c;d] with
539 | _, [d;c;b;a] -> Ok (of_int32 (a, b, c, d))
540 | _ -> Error (`Msg "Ipaddr: unexpected error with B128.shift_right")
524 (* result is unspecified if sz < 0 *)
525 let shift_right (a, b, c, d) sz =
526 if sz < 0 || sz > 128 then
527 Error (`Msg "Ipaddr: unexpected argument sz (must be >= 0 and < 128)")
528 else
529 let rec loop (a, b, c, d) sz =
530 if sz < 32 then (sz, (a, b, c, d)) else loop (0l, a, b, c) (sz - 32)
531 in
532 let sz, (a, b, c, d) = loop (a, b, c, d) sz in
533 let fn (saved, tl) part =
534 let new_saved = Int32.logand part (0xFF_FF_FF_FFl >|> sz) in
535 let new_part = part >|> sz ||| (saved <|< 32 - sz) in
536 (new_saved, new_part :: tl)
537 in
538 match List.fold_left fn (0l, []) [ a; b; c; d ] with
539 | _, [ d; c; b; a ] -> Ok (of_int32 (a, b, c, d))
540 | _ -> Error (`Msg "Ipaddr: unexpected error with B128.shift_right")
541541 end
542542
543543 module V6 = struct
544544 include B128
545545
546546 (* TODO: Perhaps represent with bytestring? *)
547 let make a b c d e f g h = of_int16 (a,b,c,d,e,f,g,h)
547 let make a b c d e f g h = of_int16 (a, b, c, d, e, f, g, h)
548548
549549 (* parsing *)
550550 let parse_ipv6 s i =
551 let compressed = ref false in (* :: *)
551 let compressed = ref false in
552 (* :: *)
552553 let len = String.length s in
553 if len < !i + 1 then (raise (need_more s));
554 let use_bracket = s.[!i] = '['; in
554 if len < !i + 1 then raise (need_more s);
555 let use_bracket = s.[!i] = '[' in
555556 if use_bracket then incr i;
556 if len < !i + 2 then (raise (need_more s));
557 if len < !i + 2 then raise (need_more s);
557558 (* check if it starts with :: *)
558559 let l =
559 if s.[!i] = ':' then begin
560 if s.[!i] = ':' then (
560561 incr i;
561 if s.[!i] = ':' then begin
562 if s.[!i] = ':' then (
562563 compressed := true;
563564 incr i;
564 [-1]
565 end
566 else
567 raise (bad_char !i s);
568 end
565 [ -1 ])
566 else raise (bad_char !i s))
569567 else []
570568 in
571569
572570 let rec loop nb acc =
573571 if nb >= 8 then acc
574 else if !i >= len
575 then acc
572 else if !i >= len then acc
576573 else
577574 let pos = !i in
578575 let x = try parse_hex_int s i with _ -> -1 in
579576 if x < 0 then acc
580 else if nb = 7
581 then x::acc
582 else if !i < len && s.[!i] = ':'
583 then begin
577 else if nb = 7 then x :: acc
578 else if !i < len && s.[!i] = ':' then (
584579 incr i;
585 if !i < len
586 then if s.[!i] = ':'
587 then
588 if !compressed then (decr i; x::acc) (* trailing :: *)
589 else begin
590 compressed:=true;
580 if !i < len then
581 if s.[!i] = ':' then
582 if !compressed then (
583 decr i;
584 x :: acc (* trailing :: *))
585 else (
586 compressed := true;
591587 incr i;
592 loop (nb + 2) (-1::x::acc)
593 end
594 else begin
595 if is_number 16 (int_of_char s.[!i])
596 then loop (nb+1) (x::acc)
597 else raise (bad_char !i s)
598 end
599 else raise (need_more s)
600 end
601 else if !i < len && s.[!i] = '.'
602 then begin
603 i:= pos;
588 loop (nb + 2) (-1 :: x :: acc))
589 else if is_number 16 (int_of_char s.[!i]) then
590 loop (nb + 1) (x :: acc)
591 else raise (bad_char !i s)
592 else raise (need_more s))
593 else if !i < len && s.[!i] = '.' then (
594 i := pos;
604595 let v4 = V4.of_string_raw s i in
605 let (hi,lo) = V4.to_int16 v4 in
606 lo :: hi :: acc
607 end
608 else x::acc
596 let hi, lo = V4.to_int16 v4 in
597 lo :: hi :: acc)
598 else x :: acc
609599 in
610600
611601 let res = loop (List.length l) l in
612602 let res_len = List.length res in
613 if res_len > 8
614 then raise (Parse_error ("too many components",s))
615 else if res_len = 0
616 then raise (need_more s)
603 if res_len > 8 then raise (Parse_error ("too many components", s))
604 else if res_len = 0 then raise (need_more s)
617605 else
618606 let a = Array.make 8 0 in
619607 let missing =
620 if !compressed
621 then 8 - (res_len - 1)
622 else if res_len <> 8
623 then
624 if !i < len
625 then raise (bad_char !i s)
626 else raise (need_more s)
608 if !compressed then 8 - (res_len - 1)
609 else if res_len <> 8 then
610 if !i < len then raise (bad_char !i s) else raise (need_more s)
627611 else 0
628612 in
629 let _ = List.fold_left (fun i x ->
630 if x = -1
631 then i - missing
632 else begin
633 if x land 0xffff <> x
634 then raise (Parse_error
635 (Printf.sprintf "component %d out of bounds" i, s));
636 a.(i) <- x;
637 i - 1
638 end
639 ) 7 res in
640 (if use_bracket then expect_char s i ']');
613 let _ =
614 List.fold_left
615 (fun i x ->
616 if x = -1 then i - missing
617 else (
618 if x land 0xffff <> x then
619 raise
620 (Parse_error (Printf.sprintf "component %d out of bounds" i, s));
621 a.(i) <- x;
622 i - 1))
623 7 res
624 in
625 if use_bracket then expect_char s i ']';
641626 a
642627
643628 (* string conversion *)
656641
657642 (* http://tools.ietf.org/html/rfc5952 *)
658643 let to_buffer buf addr =
659
660 let (a,b,c,d,e,f,g,h) as comp = to_int16 addr in
661
662 let v4 = match comp with
663 | (0,0,0,0,0,0xffff,_,_) -> true
664 | _ -> false
644 let ((a, b, c, d, e, f, g, h) as comp) = to_int16 addr in
645
646 let v4 =
647 match comp with 0, 0, 0, 0, 0, 0xffff, _, _ -> true | _ -> false
665648 in
666649
667650 let rec loop elide zeros acc = function
668651 | 0 :: xs -> loop elide (zeros - 1) acc xs
669 | n :: xs when zeros = 0 -> loop elide 0 (n::acc) xs
670 | n :: xs -> loop (min elide zeros) 0 (n::zeros::acc) xs
652 | n :: xs when zeros = 0 -> loop elide 0 (n :: acc) xs
653 | n :: xs -> loop (min elide zeros) 0 (n :: zeros :: acc) xs
671654 | [] ->
672 let elide = min elide zeros in
673 (if elide < -1 then Some elide else None),
674 (if zeros = 0 then acc else zeros::acc)
655 let elide = min elide zeros in
656 ( (if elide < -1 then Some elide else None),
657 if zeros = 0 then acc else zeros :: acc )
675658 in
676659
677 let elide,l = loop 0 0 [] [h;g;f;e;d;c;b;a] in
678 assert(match elide with Some x when x < -8 -> false | _ -> true);
660 let elide, l = loop 0 0 [] [ h; g; f; e; d; c; b; a ] in
661 assert (match elide with Some x when x < -8 -> false | _ -> true);
679662
680663 let rec cons_zeros l x =
681 if x >= 0 then l else cons_zeros (Some 0::l) (x+1)
664 if x >= 0 then l else cons_zeros (Some 0 :: l) (x + 1)
682665 in
683666
684 let _,lrev = List.fold_left (fun (patt, l) x ->
685 if Some x = patt
686 then (None, (None::l))
687 else if x < 0
688 then (patt, (cons_zeros l x))
689 else (patt, ((Some x)::l))
690 ) (elide, []) l in
667 let _, lrev =
668 List.fold_left
669 (fun (patt, l) x ->
670 if Some x = patt then (None, None :: l)
671 else if x < 0 then (patt, cons_zeros l x)
672 else (patt, Some x :: l))
673 (elide, []) l
674 in
691675
692676 let rec fill = function
693 | [Some hi;Some lo] when v4 ->
694 let addr = V4.of_int16 (hi, lo) in
695 V4.to_buffer buf addr
696 | None::xs -> Buffer.add_string buf "::"; fill xs
697 | [Some n] -> Printf.bprintf buf "%x" n
698 | (Some n)::None::xs -> Printf.bprintf buf "%x::" n; fill xs
699 | (Some n)::xs -> Printf.bprintf buf "%x:" n; fill xs
677 | [ Some hi; Some lo ] when v4 ->
678 let addr = V4.of_int16 (hi, lo) in
679 V4.to_buffer buf addr
680 | None :: xs ->
681 Buffer.add_string buf "::";
682 fill xs
683 | [ Some n ] -> Printf.bprintf buf "%x" n
684 | Some n :: None :: xs ->
685 Printf.bprintf buf "%x::" n;
686 fill xs
687 | Some n :: xs ->
688 Printf.bprintf buf "%x:" n;
689 fill xs
700690 | [] -> ()
701 in fill (List.rev lrev)
691 in
692 fill (List.rev lrev)
702693
703694 let to_string l =
704695 let buf = Buffer.create 39 in
705696 to_buffer buf l;
706697 Buffer.contents buf
707698
708 let pp ppf i =
709 Format.fprintf ppf "%s" (to_string i)
699 let pp ppf i = Format.fprintf ppf "%s" (to_string i)
710700
711701 (* byte conversion *)
712702
713 let of_octets_exn ?(off=0) bs = (* TODO : from cstruct *)
703 let of_octets_exn ?(off = 0) bs =
704 (* TODO : from cstruct *)
714705 let hihi = V4.of_octets_exn ~off bs in
715 let hilo = V4.of_octets_exn ~off:(off+4) bs in
716 let lohi = V4.of_octets_exn ~off:(off+8) bs in
717 let lolo = V4.of_octets_exn ~off:(off+12) bs in
706 let hilo = V4.of_octets_exn ~off:(off + 4) bs in
707 let lohi = V4.of_octets_exn ~off:(off + 8) bs in
708 let lolo = V4.of_octets_exn ~off:(off + 12) bs in
718709 of_int32 (hihi, hilo, lohi, lolo)
719710
720711 let of_octets ?off bs = try_with_result (of_octets_exn ?off) bs
729720 (* MAC *)
730721 (* {{:https://tools.ietf.org/html/rfc2464#section-7}RFC 2464}. *)
731722 let multicast_to_mac i =
732 let (_,_,_,i) = to_int32 i in
723 let _, _, _, i = to_int32 i in
733724 let macb = Bytes.create 6 in
734725 Bytes.set macb 0 (Char.chr 0x33);
735726 Bytes.set macb 1 (Char.chr 0x33);
736 Bytes.set macb 2 (Char.chr ((|~) (i >! 24)));
737 Bytes.set macb 3 (Char.chr ((|~) (i >! 16)));
738 Bytes.set macb 4 (Char.chr ((|~) (i >! 8)));
739 Bytes.set macb 5 (Char.chr ((|~) (i >! 0)));
727 Bytes.set macb 2 (Char.chr (( |~ ) (i >! 24)));
728 Bytes.set macb 3 (Char.chr (( |~ ) (i >! 16)));
729 Bytes.set macb 4 (Char.chr (( |~ ) (i >! 8)));
730 Bytes.set macb 5 (Char.chr (( |~ ) (i >! 0)));
740731 Macaddr.of_octets_exn (Bytes.to_string macb)
741732
742733 (* Host *)
743 let to_domain_name (a,b,c,d) =
744 let name = [
745 hex_string_of_int32 ((d >|> 0) &&& 0xF_l);
746 hex_string_of_int32 ((d >|> 4) &&& 0xF_l);
747 hex_string_of_int32 ((d >|> 8) &&& 0xF_l);
748 hex_string_of_int32 ((d >|> 12) &&& 0xF_l);
749 hex_string_of_int32 ((d >|> 16) &&& 0xF_l);
750 hex_string_of_int32 ((d >|> 20) &&& 0xF_l);
751 hex_string_of_int32 ((d >|> 24) &&& 0xF_l);
752 hex_string_of_int32 ((d >|> 28) &&& 0xF_l);
753 hex_string_of_int32 ((c >|> 0) &&& 0xF_l);
754 hex_string_of_int32 ((c >|> 4) &&& 0xF_l);
755 hex_string_of_int32 ((c >|> 8) &&& 0xF_l);
756 hex_string_of_int32 ((c >|> 12) &&& 0xF_l);
757 hex_string_of_int32 ((c >|> 16) &&& 0xF_l);
758 hex_string_of_int32 ((c >|> 20) &&& 0xF_l);
759 hex_string_of_int32 ((c >|> 24) &&& 0xF_l);
760 hex_string_of_int32 ((c >|> 28) &&& 0xF_l);
761 hex_string_of_int32 ((b >|> 0) &&& 0xF_l);
762 hex_string_of_int32 ((b >|> 4) &&& 0xF_l);
763 hex_string_of_int32 ((b >|> 8) &&& 0xF_l);
764 hex_string_of_int32 ((b >|> 12) &&& 0xF_l);
765 hex_string_of_int32 ((b >|> 16) &&& 0xF_l);
766 hex_string_of_int32 ((b >|> 20) &&& 0xF_l);
767 hex_string_of_int32 ((b >|> 24) &&& 0xF_l);
768 hex_string_of_int32 ((b >|> 28) &&& 0xF_l);
769 hex_string_of_int32 ((a >|> 0) &&& 0xF_l);
770 hex_string_of_int32 ((a >|> 4) &&& 0xF_l);
771 hex_string_of_int32 ((a >|> 8) &&& 0xF_l);
772 hex_string_of_int32 ((a >|> 12) &&& 0xF_l);
773 hex_string_of_int32 ((a >|> 16) &&& 0xF_l);
774 hex_string_of_int32 ((a >|> 20) &&& 0xF_l);
775 hex_string_of_int32 ((a >|> 24) &&& 0xF_l);
776 hex_string_of_int32 ((a >|> 28) &&& 0xF_l);
777 "ip6";
778 "arpa"
779 ]
734 let to_domain_name (a, b, c, d) =
735 let name =
736 [
737 hex_string_of_int32 (d >|> 0 &&& 0xF_l);
738 hex_string_of_int32 (d >|> 4 &&& 0xF_l);
739 hex_string_of_int32 (d >|> 8 &&& 0xF_l);
740 hex_string_of_int32 (d >|> 12 &&& 0xF_l);
741 hex_string_of_int32 (d >|> 16 &&& 0xF_l);
742 hex_string_of_int32 (d >|> 20 &&& 0xF_l);
743 hex_string_of_int32 (d >|> 24 &&& 0xF_l);
744 hex_string_of_int32 (d >|> 28 &&& 0xF_l);
745 hex_string_of_int32 (c >|> 0 &&& 0xF_l);
746 hex_string_of_int32 (c >|> 4 &&& 0xF_l);
747 hex_string_of_int32 (c >|> 8 &&& 0xF_l);
748 hex_string_of_int32 (c >|> 12 &&& 0xF_l);
749 hex_string_of_int32 (c >|> 16 &&& 0xF_l);
750 hex_string_of_int32 (c >|> 20 &&& 0xF_l);
751 hex_string_of_int32 (c >|> 24 &&& 0xF_l);
752 hex_string_of_int32 (c >|> 28 &&& 0xF_l);
753 hex_string_of_int32 (b >|> 0 &&& 0xF_l);
754 hex_string_of_int32 (b >|> 4 &&& 0xF_l);
755 hex_string_of_int32 (b >|> 8 &&& 0xF_l);
756 hex_string_of_int32 (b >|> 12 &&& 0xF_l);
757 hex_string_of_int32 (b >|> 16 &&& 0xF_l);
758 hex_string_of_int32 (b >|> 20 &&& 0xF_l);
759 hex_string_of_int32 (b >|> 24 &&& 0xF_l);
760 hex_string_of_int32 (b >|> 28 &&& 0xF_l);
761 hex_string_of_int32 (a >|> 0 &&& 0xF_l);
762 hex_string_of_int32 (a >|> 4 &&& 0xF_l);
763 hex_string_of_int32 (a >|> 8 &&& 0xF_l);
764 hex_string_of_int32 (a >|> 12 &&& 0xF_l);
765 hex_string_of_int32 (a >|> 16 &&& 0xF_l);
766 hex_string_of_int32 (a >|> 20 &&& 0xF_l);
767 hex_string_of_int32 (a >|> 24 &&& 0xF_l);
768 hex_string_of_int32 (a >|> 28 &&& 0xF_l);
769 "ip6";
770 "arpa";
771 ]
780772 in
781773 Domain_name.(host_exn (of_strings_exn name))
782774
790782 let d = drop_label_exn ~rev ~amount:24 n'
791783 and c = drop_label_exn ~amount:8 (drop_label_exn ~rev ~amount:16 n')
792784 and b = drop_label_exn ~amount:16 (drop_label_exn ~rev ~amount:8 n')
793 and a = drop_label_exn ~amount:24 n'
794 in
785 and a = drop_label_exn ~amount:24 n' in
795786 let t b d =
796787 let v = Int32.of_int (parse_hex_int d (ref 0)) in
797 if v > 0xFl then
798 raise (Parse_error ("number in label too big", d))
799 else
800 v <|< b
788 if v > 0xFl then raise (Parse_error ("number in label too big", d))
789 else v <|< b
801790 in
802791 let f d =
803 List.fold_left (fun (acc, b) d -> Int32.add acc (t b d), b + 4)
792 List.fold_left
793 (fun (acc, b) d -> (Int32.add acc (t b d), b + 4))
804794 (0l, 0) (to_strings d)
805795 in
806796 try
807797 let a', _ = f a and b', _ = f b and c', _ = f c and d', _ = f d in
808798 Some (a', b', c', d')
809 with
810 | Parse_error _ -> None
811 else
812 None
813 else
814 None
799 with Parse_error _ -> None
800 else None
801 else None
815802
816803 (* constant *)
817804
818 let unspecified = make 0 0 0 0 0 0 0 0
819 let localhost = make 0 0 0 0 0 0 0 1
820 let interface_nodes = make 0xff01 0 0 0 0 0 0 1
821 let link_nodes = make 0xff02 0 0 0 0 0 0 1
805 let unspecified = make 0 0 0 0 0 0 0 0
806
807 let localhost = make 0 0 0 0 0 0 0 1
808
809 let interface_nodes = make 0xff01 0 0 0 0 0 0 1
810
811 let link_nodes = make 0xff02 0 0 0 0 0 0 1
812
822813 let interface_routers = make 0xff01 0 0 0 0 0 0 2
823 let link_routers = make 0xff02 0 0 0 0 0 0 2
824 let site_routers = make 0xff05 0 0 0 0 0 0 2
814
815 let link_routers = make 0xff02 0 0 0 0 0 0 2
816
817 let site_routers = make 0xff05 0 0 0 0 0 0 2
825818
826819 module Prefix = struct
827820 type addr = t
821
828822 type t = addr * int
829823
830 let compare (pre,sz) (pre',sz') =
824 let compare (pre, sz) (pre', sz') =
831825 let c = compare pre pre' in
832826 if c = 0 then Stdlib.compare sz sz' else c
833827
835829
836830 let _full =
837831 let f = 0x0_FFFF_FFFF_l in
838 f,f,f,f
839
840 let mask sz = V4.Prefix.(
841 mask (sz - 0),
842 mask (sz - 32),
843 mask (sz - 64),
844 mask (sz - 96))
845
846 let prefix (pre,sz) = (logand pre (mask sz),sz)
847
848 let make sz pre = (pre,sz)
849
850 let network_address (pre,sz) addr =
832 (f, f, f, f)
833
834 let mask sz =
835 V4.Prefix.(mask (sz - 0), mask (sz - 32), mask (sz - 64), mask (sz - 96))
836
837 let prefix (pre, sz) = (logand pre (mask sz), sz)
838
839 let make sz pre = (pre, sz)
840
841 let network_address (pre, sz) addr =
851842 logor (logand pre (mask sz)) (logand addr (lognot (mask sz)))
852843
853844 let _of_string_raw s i =
854845 let v6 = of_string_raw s i in
855846 expect_char s i '/';
856847 let p = parse_dec_int s i in
857 if p > 128 || p < 0
858 then raise (Parse_error ("invalid prefix size", s));
848 if p > 128 || p < 0 then raise (Parse_error ("invalid prefix size", s));
859849 (p, v6)
860850
861851 let of_string_raw s i =
862 let (p,v6) = _of_string_raw s i in
852 let p, v6 = _of_string_raw s i in
863853 make p v6
864854
865855 let _of_string_exn s =
868858 expect_end s i;
869859 res
870860
871 let of_string_exn s = let (p,v6) = _of_string_exn s in make p v6
861 let of_string_exn s =
862 let p, v6 = _of_string_exn s in
863 make p v6
872864
873865 let of_string s = try_with_result of_string_exn s
874866
878870 V4.Prefix.bits (V4.Prefix.of_netmask_exn ~netmask ~address:V4.any)
879871 in
880872 match netmask with
881 | (0_l,0_l,0_l,0_l) -> 0
882 | (lsw ,0_l ,0_l ,0_l) -> bits lsw
883 | (-1_l,lsw ,0_l ,0_l) -> bits lsw + 32
884 | (-1_l,-1_l,lsw ,0_l) -> bits lsw + 64
885 | (-1_l,-1_l,-1_l,lsw) -> bits lsw + 96
873 | 0_l, 0_l, 0_l, 0_l -> 0
874 | lsw, 0_l, 0_l, 0_l -> bits lsw
875 | -1_l, lsw, 0_l, 0_l -> bits lsw + 32
876 | -1_l, -1_l, lsw, 0_l -> bits lsw + 64
877 | -1_l, -1_l, -1_l, lsw -> bits lsw + 96
886878 | _ -> raise (Parse_error ("invalid netmask", to_string netmask))
887879 in
888880 make nm address
892884 let of_netmask ~netmask ~address =
893885 try_with_result (_of_netmask_exn ~netmask) address
894886
895 let to_buffer buf (pre,sz) =
896 Printf.bprintf buf "%a/%d" to_buffer pre sz
887 let to_buffer buf (pre, sz) = Printf.bprintf buf "%a/%d" to_buffer pre sz
897888
898889 let to_string subnet =
899890 let buf = Buffer.create 43 in
900891 to_buffer buf subnet;
901892 Buffer.contents buf
902893
903 let pp ppf i =
904 Format.fprintf ppf "%s" (to_string i)
905
906 let mem ip (pre,sz) =
894 let pp ppf i = Format.fprintf ppf "%s" (to_string i)
895
896 let mem ip (pre, sz) =
907897 let m = mask sz in
908898 logand ip m = logand pre m
909899
910 let subset ~subnet:(pre1,sz1) ~network:(pre2,sz2) =
911 sz1 >= sz2 && mem pre1 (pre2,sz2)
900 let subset ~subnet:(pre1, sz1) ~network:(pre2, sz2) =
901 sz1 >= sz2 && mem pre1 (pre2, sz2)
912902
913903 let of_addr ip = make 128 ip
914904
915 let global_unicast_001 = make 3 (ip 0x2000 0 0 0 0 0 0 0)
916 let link = make 64 (ip 0xfe80 0 0 0 0 0 0 0)
917 let unique_local = make 7 (ip 0xfc00 0 0 0 0 0 0 0)
918 let multicast = make 8 (ip 0xff00 0 0 0 0 0 0 0)
919 let ipv4_mapped = make 96 (ip 0 0 0 0 0 0xffff 0 0)
920 let noneui64_interface = make 3 (ip 0x0000 0 0 0 0 0 0 0)
921 let solicited_node = make 104 (ip 0xff02 0 0 0 0 1 0xff00 0)
922
923 let network (pre,sz) = logand pre (mask sz)
924 let address (addr,_) = addr
925 let bits (_,sz) = sz
905 let global_unicast_001 = make 3 (ip 0x2000 0 0 0 0 0 0 0)
906
907 let link = make 64 (ip 0xfe80 0 0 0 0 0 0 0)
908
909 let unique_local = make 7 (ip 0xfc00 0 0 0 0 0 0 0)
910
911 let multicast = make 8 (ip 0xff00 0 0 0 0 0 0 0)
912
913 let ipv4_mapped = make 96 (ip 0 0 0 0 0 0xffff 0 0)
914
915 let noneui64_interface = make 3 (ip 0x0000 0 0 0 0 0 0 0)
916
917 let solicited_node = make 104 (ip 0xff02 0 0 0 0 1 0xff00 0)
918
919 let network (pre, sz) = logand pre (mask sz)
920
921 let address (addr, _) = addr
922
923 let bits (_, sz) = sz
924
926925 let netmask subnet = mask (bits subnet)
927926
928 let first (_,sz as cidr) =
929 if sz > 126 then
930 network cidr
931 else
932 network cidr |> succ |> failwith_msg
933
934 let last (_,sz as cidr) =
935 let ffff = ip 0xffff 0xffff 0xffff 0xffff
936 0xffff 0xffff 0xffff 0xffff in
927 let first ((_, sz) as cidr) =
928 if sz > 126 then network cidr else network cidr |> succ |> failwith_msg
929
930 let last ((_, sz) as cidr) =
931 let ffff = ip 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff in
937932 logor (network cidr) (shift_right ffff sz |> failwith_msg)
938933 end
939934
941936 let scope i =
942937 let mem = Prefix.mem i in
943938 if mem Prefix.global_unicast_001 then Global
944 else if mem Prefix.ipv4_mapped
945 (* rfc says they are technically global but... *)
946 then V4.scope (let (_,_,_,v4) = to_int32 i in V4.of_int32 v4)
939 else if
940 mem Prefix.ipv4_mapped (* rfc says they are technically global but... *)
941 then
942 V4.scope
943 (let _, _, _, v4 = to_int32 i in
944 V4.of_int32 v4)
947945 else if mem Prefix.multicast then
948 let (x,_,_,_,_,_,_,_) = to_int16 i in
946 let x, _, _, _, _, _, _, _ = to_int16 i in
949947 match x land 0xf with
950948 | 0 -> Point
951949 | 1 -> Interface
962960 else Global
963961
964962 let link_address_of_mac =
965 let c b i = Char.code (String.get b i) in
963 let c b i = Char.code b.[i] in
966964 fun mac ->
967965 let bmac = Macaddr.to_octets mac in
968966 let c_0 = c bmac 0 lxor 2 in
969 let addr = make 0 0 0 0
970 (c_0 lsl 8 + c bmac 1)
971 (c bmac 2 lsl 8 + 0xff )
972 (0xfe00 + c bmac 3)
973 (c bmac 4 lsl 8 + c bmac 5)
967 let addr =
968 make 0 0 0 0
969 ((c_0 lsl 8) + c bmac 1)
970 ((c bmac 2 lsl 8) + 0xff)
971 (0xfe00 + c bmac 3)
972 ((c bmac 4 lsl 8) + c bmac 5)
974973 in
975974 Prefix.(network_address link addr)
976975
977 let is_global i = (scope i) = Global
976 let is_global i = scope i = Global
977
978978 let is_multicast i = Prefix.(mem i multicast)
979 let is_private i = (scope i) <> Global
979
980 let is_private i = scope i <> Global
980981 end
981982
982 type ('v4,'v6) v4v6 = V4 of 'v4 | V6 of 'v6
983 type t = (V4.t,V6.t) v4v6
984
985 let compare a b = match a,b with
983 type ('v4, 'v6) v4v6 = V4 of 'v4 | V6 of 'v6
984
985 type t = (V4.t, V6.t) v4v6
986
987 let compare a b =
988 match (a, b) with
986989 | V4 a, V4 b -> V4.compare a b
987990 | V6 a, V6 b -> V6.compare a b
988991 | V4 _, V6 _ -> -1
989992 | V6 _, V4 _ -> 1
990993
991 let to_string = function
992 | V4 x -> V4.to_string x
993 | V6 x -> V6.to_string x
994 let to_string = function V4 x -> V4.to_string x | V6 x -> V6.to_string x
994995
995996 let to_buffer buf = function
996997 | V4 x -> V4.to_buffer buf x
997998 | V6 x -> V6.to_buffer buf x
998999
999 let pp ppf i =
1000 Format.fprintf ppf "%s" (to_string i)
1000 let pp ppf i = Format.fprintf ppf "%s" (to_string i)
10011001
10021002 let of_string_raw s offset =
10031003 let len = String.length s in
10041004 if len < !offset + 1 then raise (need_more s);
10051005 match s.[0] with
1006 | '[' -> V6 (V6.of_string_raw s offset)
1007 | _ ->
1006 | '[' -> V6 (V6.of_string_raw s offset)
1007 | _ -> (
10081008 let pos = !offset in
10091009 try V4 (V4.of_string_raw s offset)
1010 with Parse_error (v4_msg,_) ->
1010 with Parse_error (v4_msg, _) -> (
10111011 offset := pos;
10121012 try V6 (V6.of_string_raw s offset)
1013 with Parse_error(v6_msg,s) ->
1014 let msg = Printf.sprintf
1015 "not an IPv4 address: %s\nnot an IPv6 address: %s"
1016 v4_msg v6_msg
1017 in raise (Parse_error (msg,s))
1013 with Parse_error (v6_msg, s) ->
1014 let msg =
1015 Printf.sprintf "not an IPv4 address: %s\nnot an IPv6 address: %s"
1016 v4_msg v6_msg
1017 in
1018 raise (Parse_error (msg, s))))
10181019
10191020 let of_string_exn s = of_string_raw s (ref 0)
10201021
10211022 let of_string s = try_with_result of_string_exn s
10221023
10231024 let v6_of_v4 v4 =
1024 V6.(Prefix.(network_address ipv4_mapped (of_int32 (0l,0l,0l,v4))))
1025 V6.(Prefix.(network_address ipv4_mapped (of_int32 (0l, 0l, 0l, v4))))
10251026
10261027 let v4_of_v6 v6 =
1027 if V6.Prefix.(mem v6 ipv4_mapped)
1028 then let (_,_,_,v4) = V6.to_int32 v6 in Some V4.(of_int32 v4)
1028 if V6.Prefix.(mem v6 ipv4_mapped) then
1029 let _, _, _, v4 = V6.to_int32 v6 in
1030 Some V4.(of_int32 v4)
10291031 else None
10301032
10311033 let to_v4 = function V4 v4 -> Some v4 | V6 v6 -> v4_of_v6 v6
10341036
10351037 let scope = function V4 v4 -> V4.scope v4 | V6 v6 -> V6.scope v6
10361038
1037 let is_global = function
1038 | V4 v4 -> V4.is_global v4
1039 | V6 v6 -> V6.is_global v6
1039 let is_global = function V4 v4 -> V4.is_global v4 | V6 v6 -> V6.is_global v6
10401040
10411041 let is_multicast = function
10421042 | V4 v4 -> V4.is_multicast v4
10561056
10571057 let of_domain_name n =
10581058 match Domain_name.count_labels n with
1059 | 6 ->
1060 begin match V4.of_domain_name n with
1061 | None -> None
1062 | Some x -> Some (V4 x)
1063 end
1064 | 34 ->
1065 begin match V6.of_domain_name n with
1066 | None -> None
1067 | Some x -> Some (V6 x)
1068 end
1059 | 6 -> (
1060 match V4.of_domain_name n with None -> None | Some x -> Some (V4 x))
1061 | 34 -> (
1062 match V6.of_domain_name n with None -> None | Some x -> Some (V6 x))
10691063 | _ -> None
10701064
10711065 let succ = function
10821076 end
10831077
10841078 type addr = t
1085 type t = (V4.Prefix.t,V6.Prefix.t) v4v6
1086
1087 let compare a b = match a,b with
1088 | V4 a , V4 b -> V4.Prefix.compare a b
1089 | V6 a , V6 b -> V6.Prefix.compare a b
1090 | V4 _ , V6 _ -> -1
1091 | V6 _ , V4 _ -> 1
1079
1080 type t = (V4.Prefix.t, V6.Prefix.t) v4v6
1081
1082 let compare a b =
1083 match (a, b) with
1084 | V4 a, V4 b -> V4.Prefix.compare a b
1085 | V6 a, V6 b -> V6.Prefix.compare a b
1086 | V4 _, V6 _ -> -1
1087 | V6 _, V4 _ -> 1
10921088
10931089 let of_string_raw s offset =
10941090 let len = String.length s in
10951091 if len < !offset + 1 then raise (need_more s);
10961092 match s.[0] with
1097 | '[' -> V6 (V6.Prefix.of_string_raw s offset)
1098 | _ ->
1093 | '[' -> V6 (V6.Prefix.of_string_raw s offset)
1094 | _ -> (
10991095 let pos = !offset in
11001096 try V4 (V4.Prefix.of_string_raw s offset)
1101 with Parse_error (v4_msg,_) ->
1097 with Parse_error (v4_msg, _) -> (
11021098 offset := pos;
11031099 try V6 (V6.Prefix.of_string_raw s offset)
1104 with Parse_error(v6_msg,s) ->
1105 let msg = Printf.sprintf
1106 "not an IPv4 prefix: %s\nnot an IPv6 prefix: %s"
1100 with Parse_error (v6_msg, s) ->
1101 let msg =
1102 Printf.sprintf "not an IPv4 prefix: %s\nnot an IPv6 prefix: %s"
11071103 v4_msg v6_msg
1108 in raise (Parse_error (msg,s))
1104 in
1105 raise (Parse_error (msg, s))))
11091106
11101107 let of_string_exn s = of_string_raw s (ref 0)
11111108
11121109 let of_string s = try_with_result of_string_exn s
11131110
1114 let v6_of_v4 v4 = V6.Prefix.make
1115 (96 + V4.Prefix.bits v4)
1116 (v6_of_v4 (V4.Prefix.network v4))
1117
1118 let v4_of_v6 v6 = match v4_of_v6 (V6.Prefix.network v6) with
1111 let v6_of_v4 v4 =
1112 V6.Prefix.make (96 + V4.Prefix.bits v4) (v6_of_v4 (V4.Prefix.network v4))
1113
1114 let v4_of_v6 v6 =
1115 match v4_of_v6 (V6.Prefix.network v6) with
11191116 | Some v4 -> Some (V4.Prefix.make (V6.Prefix.bits v6 - 96) v4)
11201117 | None -> None
11211118
11481145 | V4 p -> V4 (V4.Prefix.netmask p)
11491146 | V6 p -> V6 (V6.Prefix.netmask p)
11501147
1151 let pp ppf i =
1152 Format.fprintf ppf "%s" (to_string i)
1148 let pp ppf i = Format.fprintf ppf "%s" (to_string i)
11531149
11541150 let first = function
11551151 | V4 p -> V4 (V4.Prefix.first p)
11581154 let last = function
11591155 | V4 p -> V4 (V4.Prefix.last p)
11601156 | V6 p -> V6 (V6.Prefix.last p)
1161
11621157 end
1717
1818 (** A library for manipulation of IP address representations.
1919
20 {e %%VERSION%% - {{:%%PKG_HOMEPAGE%% }homepage}} *)
21
22 (** [Parse_error (err,packet)] is raised when parsing of the IP
23 address syntax fails. [err] contains a human-readable error
24 and [packet] is the original octet list that failed to parse. *)
20 {e v5.0.1 - {{:https://github.com/mirage/ocaml-ipaddr} homepage}} *)
21
2522 exception Parse_error of string * string
23 (** [Parse_error (err,packet)] is raised when parsing of the IP address syntax
24 fails. [err] contains a human-readable error and [packet] is the original
25 octet list that failed to parse. *)
2626
2727 (** Type of ordered address scope classifications *)
28 type scope =
29 | Point
30 | Interface
31 | Link
32 | Admin
33 | Site
34 | Organization
35 | Global
36
37 (** [string_of_scope scope] returns a human-readable representation
38 of {!scope}. *)
28 type scope = Point | Interface | Link | Admin | Site | Organization | Global
29
3930 val string_of_scope : scope -> string
40
41 (** [scope_of_string s] returns a {!scope} from a string representation
42 of [s]. Valid string values for [s] can be obtained via {!string_of_scope}. *)
43 val scope_of_string : string -> (scope, [> `Msg of string]) result
44
45 (** [pp_scope fmt scope] outputs a human-readable representation
46 of {!scope} to the [fmt] formatter. *)
47 val pp_scope : Format.formatter -> scope -> unit [@@ocaml.toplevel_printer]
31 (** [string_of_scope scope] returns a human-readable representation of {!scope}. *)
32
33 val scope_of_string : string -> (scope, [> `Msg of string ]) result
34 (** [scope_of_string s] returns a {!scope} from a string representation of [s].
35 Valid string values for [s] can be obtained via {!string_of_scope}. *)
36
37 val pp_scope : Format.formatter -> scope -> unit
38 [@@ocaml.toplevel_printer]
39 (** [pp_scope fmt scope] outputs a human-readable representation of {!scope} to
40 the [fmt] formatter. *)
4841
4942 (** A collection of functions for IPv4 addresses. *)
5043 module V4 : sig
44 type t
5145 (** Type of the internet protocol v4 address of a host *)
52 type t
53
54 (** Converts the low bytes of four int values into an abstract {! V4.t }. *)
46
5547 val make : int -> int -> int -> int -> t
48 (** Converts the low bytes of four int values into an abstract {!V4.t}. *)
5649
5750 (** {3 Text string conversion}
58 These manipulate human-readable IPv4 addresses (for example [192.168.1.2]). *)
59
51
52 These manipulate human-readable IPv4 addresses (for example
53 [192.168.1.2]). *)
54
55 val of_string : string -> (t, [> `Msg of string ]) result
6056 (** [of_string s] is the address {!t} represented by the human-readable IPv4
6157 address [s]. Returns a human-readable error string if parsing failed. *)
62 val of_string : string -> (t, [> `Msg of string ]) result
63
58
59 val of_string_exn : string -> t
6460 (** [of_string_exn s] is the address {!t} represented as a human-readable IPv4
6561 address [s]. Raises {!Parse_error} if [s] is not exactly 4 bytes long. *)
66 val of_string_exn : string -> t
67
62
63 val of_string_raw : string -> int ref -> t
6864 (** [of_string_raw s off] acts as {!of_string_exn} but takes as an extra
69 argument the offset into the string for reading. [off] will be
70 mutated to an unspecified value during the function call. [s] will
71 a {!Parse_error} exception if it is an invalid or truncated IP address. *)
72 val of_string_raw : string -> int ref -> t
73
74 (** [to_string ipv4] is the dotted decimal string representation
75 of [ipv4], i.e. [XXX.XX.X.XXX]. *)
65 argument the offset into the string for reading. [off] will be mutated to
66 an unspecified value during the function call. [s] will a {!Parse_error}
67 exception if it is an invalid or truncated IP address. *)
68
7669 val to_string : t -> string
77
70 (** [to_string ipv4] is the dotted decimal string representation of [ipv4],
71 i.e. [XXX.XX.X.XXX]. *)
72
73 val to_buffer : Buffer.t -> t -> unit
7874 (** [to_buffer buf ipv4] writes the string representation of [ipv4] into the
7975 buffer [buf]. *)
80 val to_buffer : Buffer.t -> t -> unit
81
82 (** [pp f ipv4] outputs a human-readable representation of [ipv4] to
83 the formatter [f]. *)
84 val pp : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
76
77 val pp : Format.formatter -> t -> unit
78 [@@ocaml.toplevel_printer]
79 (** [pp f ipv4] outputs a human-readable representation of [ipv4] to the
80 formatter [f]. *)
8581
8682 (** {3 Octets conversion}
87 These manipulate IPv4 addresses represented as a sequence of
88 four bytes. (e.g for example [0xc0a80102] will be the representation
89 of the human-readable [192.168.1.2] address. *)
90
83
84 These manipulate IPv4 addresses represented as a sequence of four bytes.
85 (e.g for example [0xc0a80102] will be the representation of the
86 human-readable [192.168.1.2] address. *)
87
88 val of_octets : ?off:int -> string -> (t, [> `Msg of string ]) result
9189 (** [of_octets ?off s] is the address {!t} represented by the IPv4 octets
92 represented by [s] starting from offset [off] within the string.
93 [s] must be at least [off+4] bytes long.
94 Returns a human-readable error string if parsing fails.
95 [off] defaults to 0. *)
96 val of_octets : ?off:int -> string -> (t, [> `Msg of string ]) result
97
98 (** [of_octets_exn ipv4_octets] is the IPv4 address represented
99 by [ipv4_octets] starting from offset [off] within the string.
100 Raises {!Parse_error} if [ipv4_octets] is not at least [off+4] bytes long.
101 [off] defaults to 0. *)
90 represented by [s] starting from offset [off] within the string. [s] must
91 be at least [off+4] bytes long. Returns a human-readable error string if
92 parsing fails. [off] defaults to 0. *)
93
10294 val of_octets_exn : ?off:int -> string -> t
103
95 (** [of_octets_exn ipv4_octets] is the IPv4 address represented by
96 [ipv4_octets] starting from offset [off] within the string. Raises
97 {!Parse_error} if [ipv4_octets] is not at least [off+4] bytes long. [off]
98 defaults to 0. *)
99
100 val write_octets :
101 ?off:int -> t -> bytes -> (unit, [> `Msg of string ]) result
104102 (** [write_octets ?off ipv4 b] writes the [ipv4] as octets to [b] starting
105 from offset [off]. [b] must be at least [off+4] long or an error is
106 returned. *)
107 val write_octets : ?off:int -> t -> bytes -> (unit, [> `Msg of string ]) result
108
103 from offset [off]. [b] must be at least [off+4] long or an error is
104 returned. *)
105
106 val write_octets_exn : ?off:int -> t -> bytes -> unit
109107 (** [write_octets_exn ?off ipv4 b] writes the [ipv4] as octets to [b] starting
110 from offset [off]. [b] must be at least [off+4] long or a
111 {!Parse_error} is raised. *)
112 val write_octets_exn : ?off:int -> t -> bytes -> unit
113
108 from offset [off]. [b] must be at least [off+4] long or a {!Parse_error}
109 is raised. *)
110
111 val to_octets : t -> string
114112 (** [to_octets ipv4] returns the 4 bytes representing the [ipv4] octets. *)
115 val to_octets : t -> string
116113
117114 (** {3 Int conversion} *)
118115
119 (** [of_int32 ipv4_packed] is the address represented by
120 [ipv4_packed]. *)
121116 val of_int32 : int32 -> t
122
117 (** [of_int32 ipv4_packed] is the address represented by [ipv4_packed]. *)
118
119 val to_int32 : t -> int32
123120 (** [to_int32 ipv4] is the 32-bit packed encoding of [ipv4]. *)
124 val to_int32 : t -> int32
125
126 (** [of_int16 ipv4_packed] is the address represented by
127 [ipv4_packed]. *)
128 val of_int16 : (int * int) -> t
129
121
122 val of_int16 : int * int -> t
123 (** [of_int16 ipv4_packed] is the address represented by [ipv4_packed]. *)
124
125 val to_int16 : t -> int * int
130126 (** [to_int16 ipv4] is the 16-bit packed encoding of [ipv4]. *)
131 val to_int16 : t -> int * int
132127
133128 (** {3 MAC conversion} *)
134129
135 (** [multicast_to_mac ipv4] is the MAC address corresponding to the
136 multicast address [ipv4]. Described by
137 {{:http://tools.ietf.org/html/rfc1112#section-6.2}RFC 1112}. *)
138130 val multicast_to_mac : t -> Macaddr.t
131 (** [multicast_to_mac ipv4] is the MAC address corresponding to the multicast
132 address [ipv4]. Described by
133 {{:http://tools.ietf.org/html/rfc1112#section-6.2} RFC 1112}. *)
139134
140135 (** {3 Host conversion} *)
141136
142 (** [to_domain_name ipv4] is the domain name label list for reverse
143 lookups of [ipv4]. This includes the [.in-addr.arpa] suffix. *)
144137 val to_domain_name : t -> [ `host ] Domain_name.t
145
138 (** [to_domain_name ipv4] is the domain name label list for reverse lookups of
139 [ipv4]. This includes the [.in-addr.arpa] suffix. *)
140
141 val of_domain_name : 'a Domain_name.t -> t option
146142 (** [of_domain_name name] is [Some t] if the [name] has an [.in-addr.arpa]
147143 suffix, and an IPv4 address prefixed. *)
148 val of_domain_name : 'a Domain_name.t -> t option
149144
150145 (** {3 Utility functions} *)
151146
152 (** [succ ipv4] is ip address next to [ipv4].
153 Returns a human-readable error string if it's already the highest address. *)
154147 val succ : t -> (t, [> `Msg of string ]) result
155
156 (** [pred ipv4] is ip address before [ipv4].
157 Returns a human-readable error string if it's already the lowest address. *)
148 (** [succ ipv4] is ip address next to [ipv4]. Returns a human-readable error
149 string if it's already the highest address. *)
150
158151 val pred : t -> (t, [> `Msg of string ]) result
152 (** [pred ipv4] is ip address before [ipv4]. Returns a human-readable error
153 string if it's already the lowest address. *)
159154
160155 (** {3 Common addresses} *)
161156
157 val any : t
162158 (** [any] is 0.0.0.0. *)
163 val any : t
164
159
160 val unspecified : t
165161 (** [unspecified] is 0.0.0.0. *)
166 val unspecified : t
167
162
163 val broadcast : t
168164 (** [broadcast] is 255.255.255.255. *)
169 val broadcast : t
170
165
166 val nodes : t
171167 (** [nodes] is 224.0.0.1. *)
172 val nodes : t
173
168
169 val routers : t
174170 (** [routers] is 224.0.0.2. *)
175 val routers : t
176
171
172 val localhost : t
177173 (** [localhost] is 127.0.0.1. *)
178 val localhost : t
179174
180175 (** A module for manipulating IPv4 network prefixes (CIDR). *)
181176 module Prefix : sig
182177 type addr = t
183178
179 type t
184180 (** Type of a internet protocol subnet: an address and prefix length. *)
185 type t
186
181
182 val mask : int -> addr
187183 (** [mask n] is the pseudo-address of an [n] bit subnet mask. *)
188 val mask : int -> addr
189
184
185 val make : int -> addr -> t
190186 (** [make n addr] is the cidr of [addr] with [n] bits prefix. *)
191 val make : int -> addr -> t
192
187
188 val prefix : t -> t
193189 (** [prefix cidr] is the subnet prefix of [cidr] where all non-prefix bits
194190 set to 0. *)
195 val prefix : t -> t
196
197 (** [network_address cidr addr] is the address with prefix [cidr]
198 and suffix from [addr].
199 See <http://tools.ietf.org/html/rfc4291#section-2.3>. *)
191
200192 val network_address : t -> addr -> addr
201
202 (** [of_string cidr] is the subnet prefix represented by the CIDR
203 string, [cidr]. Returns a human-readable parsing error message
204 if [cidr] is not a valid representation of a CIDR notation routing
205 prefix. *)
206 val of_string : string -> (t, [> `Msg of string ]) result
207
193 (** [network_address cidr addr] is the address with prefix [cidr] and suffix
194 from [addr]. See <http://tools.ietf.org/html/rfc4291#section-2.3>. *)
195
196 val of_string : string -> (t, [> `Msg of string ]) result
197 (** [of_string cidr] is the subnet prefix represented by the CIDR string,
198 [cidr]. Returns a human-readable parsing error message if [cidr] is not
199 a valid representation of a CIDR notation routing prefix. *)
200
201 val of_string_exn : string -> t
208202 (** [of_string_exn cidr] is the subnet prefix represented by the CIDR
209203 string, [cidr]. Raises [Parse_error] if [cidr] is not a valid
210204 representation of a CIDR notation routing prefix. *)
211 val of_string_exn : string -> t
212
213 (** Same as {!of_string_exn} but takes as an extra argument the offset
214 into the string for reading. *)
205
215206 val of_string_raw : string -> int ref -> t
216
217 (** [to_string cidr] is the CIDR notation string representation
218 of [cidr], i.e. [XXX.XX.X.XXX/XX]. *)
207 (** Same as {!of_string_exn} but takes as an extra argument the offset into
208 the string for reading. *)
209
219210 val to_string : t -> string
220
221 (** [pp f cidr] outputs a human-readable representation of [cidr]
222 to the formatter [f]. *)
223 val pp : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
224
225 (** [to_buffer buf cidr] writes the string representation
226 of [cidr] into the buffer [buf]. *)
211 (** [to_string cidr] is the CIDR notation string representation of [cidr],
212 i.e. [XXX.XX.X.XXX/XX]. *)
213
214 val pp : Format.formatter -> t -> unit
215 [@@ocaml.toplevel_printer]
216 (** [pp f cidr] outputs a human-readable representation of [cidr] to the
217 formatter [f]. *)
218
227219 val to_buffer : Buffer.t -> t -> unit
228
220 (** [to_buffer buf cidr] writes the string representation of [cidr] into the
221 buffer [buf]. *)
222
223 val of_netmask_exn : netmask:addr -> address:addr -> t
229224 (** [of_netmask_exn ~netmask ~address] is the subnet prefix of [address]
230225 with netmask [netmask]. *)
231 val of_netmask_exn : netmask:addr -> address:addr -> t
232
233 (** [of_netmask ~netmask ~address] is the cidr of [address] with
234 netmask [netmask]. *)
235 val of_netmask : netmask:addr -> address:addr ->
236 (t, [> `Msg of string ]) result
237
226
227 val of_netmask :
228 netmask:addr -> address:addr -> (t, [> `Msg of string ]) result
229 (** [of_netmask ~netmask ~address] is the cidr of [address] with netmask
230 [netmask]. *)
231
232 val mem : addr -> t -> bool
238233 (** [mem ip subnet] checks whether [ip] is found within [subnet]. *)
239 val mem : addr -> t -> bool
240
241 (** [subset ~subnet ~network] checks whether [subnet] is contained
242 within [network]. *)
234
243235 val subset : subnet:t -> network:t -> bool
244
245 (** [of_addr ip] create a subnet composed of only one address, [ip].
246 It is the same as [make 32 ip]. *)
236 (** [subset ~subnet ~network] checks whether [subnet] is contained within
237 [network]. *)
238
247239 val of_addr : addr -> t
248
240 (** [of_addr ip] create a subnet composed of only one address, [ip]. It is
241 the same as [make 32 ip]. *)
242
243 val global : t
249244 (** The default route, all addresses in IPv4-space, 0.0.0.0/0. *)
250 val global : t
251
245
246 val loopback : t
252247 (** The host loopback network, 127.0.0.0/8. *)
253 val loopback : t
254
248
249 val link : t
255250 (** The local-link network, 169.254.0.0/16. *)
256 val link : t
257
251
252 val relative : t
258253 (** The relative addressing network, 0.0.0.0/8. *)
259 val relative : t
260
254
255 val multicast : t
261256 (** The multicast network, 224.0.0.0/4. *)
262 val multicast : t
263
257
258 val private_10 : t
264259 (** The private subnet with 10 as first octet, 10.0.0.0/8. *)
265 val private_10 : t
266
260
261 val private_172 : t
267262 (** The private subnet with 172 as first octet, 172.16.0.0/12. *)
268 val private_172 : t
269
263
264 val private_192 : t
270265 (** The private subnet with 192 as first octet, 192.168.0.0/16. *)
271 val private_192 : t
272
273 (** The privately addressable networks: [loopback], [link],
274 [private_10], [private_172], [private_192]. *)
266
275267 val private_blocks : t list
276
268 (** The privately addressable networks: [loopback], [link], [private_10],
269 [private_172], [private_192]. *)
270
271 val broadcast : t -> addr
277272 (** [broadcast subnet] is the broadcast address for [subnet]. *)
278 val broadcast : t -> addr
279
273
274 val network : t -> addr
280275 (** [network subnet] is the address for [subnet]. *)
281 val network : t -> addr
282
276
277 val netmask : t -> addr
283278 (** [netmask subnet] is the netmask for [subnet]. *)
284 val netmask : t -> addr
285
279
280 val address : t -> addr
286281 (** [address cidr] is the address for [cidr]. *)
287 val address : t -> addr
288
282
283 val bits : t -> int
289284 (** [bits cidr] is the bit size of the [cidr] prefix. *)
290 val bits : t -> int
291
285
286 val first : t -> addr
292287 (** [first cidr] is first valid unicast address in this [cidr]. *)
293 val first : t -> addr
294
288
289 val last : t -> addr
295290 (** [last cidr] is last valid unicast address in this [cidr]. *)
296 val last : t -> addr
297291
298292 include Map.OrderedType with type t := t
299293 end
300294
301 (** [scope ipv4] is the classification of [ipv4] by the {! scope }
302 hierarchy. *)
303295 val scope : t -> scope
304
296 (** [scope ipv4] is the classification of [ipv4] by the {!scope} hierarchy. *)
297
298 val is_global : t -> bool
305299 (** [is_global ipv4] is a predicate indicating whether [ipv4] globally
306300 addresses a node. *)
307 val is_global : t -> bool
308
301
302 val is_multicast : t -> bool
309303 (** [is_multicast ipv4] is a predicate indicating whether [ipv4] is a
310304 multicast address. *)
311 val is_multicast : t -> bool
312
305
306 val is_private : t -> bool
313307 (** [is_private ipv4] is a predicate indicating whether [ipv4] privately
314308 addresses a node. *)
315 val is_private : t -> bool
316309
317310 include Map.OrderedType with type t := t
318311 end
319312
320
321313 (** A collection of functions for IPv6 addresses. *)
322314 module V6 : sig
315 type t
323316 (** Type of the internet protocol v6 address of a host *)
324 type t
325
326 (** Converts the low bytes of eight int values into an abstract
327 {! V6.t }. *)
317
328318 val make : int -> int -> int -> int -> int -> int -> int -> int -> t
319 (** Converts the low bytes of eight int values into an abstract {!V6.t}. *)
329320
330321 (** {3 Text string conversion} *)
331322
332 (** [of_string_exn ipv6_string] is the address represented
333 by [ipv6_string]. Raises {!Parse_error} if [ipv6_string] is not a
334 valid representation of an IPv6 address. *)
335323 val of_string_exn : string -> t
336
337 (** Same as [of_string_exn] but returns an option type instead of raising
338 an exception. *)
324 (** [of_string_exn ipv6_string] is the address represented by [ipv6_string].
325 Raises {!Parse_error} if [ipv6_string] is not a valid representation of an
326 IPv6 address. *)
327
339328 val of_string : string -> (t, [> `Msg of string ]) result
340
341 (** Same as [of_string_exn] but takes as an extra argument the offset into
342 the string for reading. *)
329 (** Same as [of_string_exn] but returns an option type instead of raising an
330 exception. *)
331
343332 val of_string_raw : string -> int ref -> t
344
345 (** [to_string ipv6] is the string representation of [ipv6],
346 i.e. [XXX:XX:X::XXX:XX]. *)
333 (** Same as [of_string_exn] but takes as an extra argument the offset into the
334 string for reading. *)
335
347336 val to_string : t -> string
348
337 (** [to_string ipv6] is the string representation of [ipv6], i.e.
338 [XXX:XX:X::XXX:XX]. *)
339
340 val to_buffer : Buffer.t -> t -> unit
349341 (** [to_buffer buf ipv6] writes the string representation of [ipv6] into the
350342 buffer [buf]. *)
351 val to_buffer : Buffer.t -> t -> unit
352
353 (** [pp f ipv6] outputs a human-readable representation of [ipv6] to
354 the formatter [f]. *)
355 val pp : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
343
344 val pp : Format.formatter -> t -> unit
345 [@@ocaml.toplevel_printer]
346 (** [pp f ipv6] outputs a human-readable representation of [ipv6] to the
347 formatter [f]. *)
356348
357349 (** {3 Octets conversion} *)
358350
359 (** [of_octets_exn ?off ipv6_octets] is the address represented
360 by [ipv6_octets], starting from offset [off].
361 Raises {!Parse_error} if [ipv6_octets] is not a valid representation of
362 an IPv6 address. *)
363351 val of_octets_exn : ?off:int -> string -> t
364
365 (** Same as {!of_octets_exn} but returns an result type instead of raising
366 an exception. *)
352 (** [of_octets_exn ?off ipv6_octets] is the address represented by
353 [ipv6_octets], starting from offset [off]. Raises {!Parse_error} if
354 [ipv6_octets] is not a valid representation of an IPv6 address. *)
355
367356 val of_octets : ?off:int -> string -> (t, [> `Msg of string ]) result
368
369 (** [write_octets_exn ?off ipv6 b] writes 16 bytes that encode [ipv6] into [b] starting
370 from offset [off] within [b]. [b] must be at least [off+16] bytes long or
371 a {!Parse_error} exception will be raised. *)
357 (** Same as {!of_octets_exn} but returns an result type instead of raising an
358 exception. *)
359
372360 val write_octets_exn : ?off:int -> t -> bytes -> unit
373
374 (** [write_octets ?off ipv6 b] writes 16 bytes that encode [ipv6] into [b] starting
375 from offset [off] within [b]. [b] must be at least [off+16] bytes long or
376 an error is returned. *)
377 val write_octets : ?off:int -> t -> bytes -> (unit, [> `Msg of string ]) result
378
361 (** [write_octets_exn ?off ipv6 b] writes 16 bytes that encode [ipv6] into [b]
362 starting from offset [off] within [b]. [b] must be at least [off+16] bytes
363 long or a {!Parse_error} exception will be raised. *)
364
365 val write_octets :
366 ?off:int -> t -> bytes -> (unit, [> `Msg of string ]) result
367 (** [write_octets ?off ipv6 b] writes 16 bytes that encode [ipv6] into [b]
368 starting from offset [off] within [b]. [b] must be at least [off+16] bytes
369 long or an error is returned. *)
370
371 val to_octets : t -> string
379372 (** [to_octets ipv6] returns the 16 bytes representing the [ipv6] octets. *)
380 val to_octets : t -> string
381373
382374 (** {3 Int conversion} *)
383375
376 val of_int64 : int64 * int64 -> t
384377 (** [of_int64 (ho, lo)] is the IPv6 address represented by two int64. *)
385 val of_int64 : int64 * int64 -> t
386
378
379 val to_int64 : t -> int64 * int64
387380 (** [to_int64 ipv6] is the 128-bit packed encoding of [ipv6]. *)
388 val to_int64 : t -> int64 * int64
389
381
382 val of_int32 : int32 * int32 * int32 * int32 -> t
390383 (** [of_int32 (a, b, c, d)] is the IPv6 address represented by four int32. *)
391 val of_int32 : int32 * int32 * int32 * int32 -> t
392
384
385 val to_int32 : t -> int32 * int32 * int32 * int32
393386 (** [to_int32 ipv6] is the 128-bit packed encoding of [ipv6]. *)
394 val to_int32 : t -> int32 * int32 * int32 * int32
395
387
388 val of_int16 : int * int * int * int * int * int * int * int -> t
396389 (** [of_int16 (a, b, c, d, e, f, g, h)] is the IPv6 address represented by
397390 eight 16-bit int. *)
398 val of_int16 : int * int * int * int * int * int * int * int -> t
399
391
392 val to_int16 : t -> int * int * int * int * int * int * int * int
400393 (** [to_int16 ipv6] is the 128-bit packed encoding of [ipv6]. *)
401 val to_int16 : t -> int * int * int * int * int * int * int * int
402394
403395 (** {3 MAC conversion} *)
404396
405 (** [multicast_to_mac ipv6] is the MAC address corresponding to the
406 multicast address [ipv6]. Described by
407 {{:https://tools.ietf.org/html/rfc2464#section-7}RFC 2464}. *)
408397 val multicast_to_mac : t -> Macaddr.t
398 (** [multicast_to_mac ipv6] is the MAC address corresponding to the multicast
399 address [ipv6]. Described by
400 {{:https://tools.ietf.org/html/rfc2464#section-7} RFC 2464}. *)
409401
410402 (** {3 Host conversion} *)
411403
412 (** [to_domain_name ipv6] is the domain name label list for reverse
413 lookups of [ipv6]. This includes the [.ip6.arpa] suffix. *)
414404 val to_domain_name : t -> [ `host ] Domain_name.t
415
416 (** [of_domain_name name] is [Some t] if the [name] has an [.ip6.arpa]
417 suffix, and an IPv6 address prefixed. *)
405 (** [to_domain_name ipv6] is the domain name label list for reverse lookups of
406 [ipv6]. This includes the [.ip6.arpa] suffix. *)
407
418408 val of_domain_name : 'a Domain_name.t -> t option
409 (** [of_domain_name name] is [Some t] if the [name] has an [.ip6.arpa] suffix,
410 and an IPv6 address prefixed. *)
419411
420412 (** {3 Utility functions} *)
421413
422 (** [succ ipv6] is ip address next to [ipv6]. Returns a human-readable
423 error string if it's already the highest address. *)
424414 val succ : t -> (t, [> `Msg of string ]) result
425
426 (** [pred ipv6] is ip address before [ipv6]. Returns a human-readable
427 error string if it's already the lowest address. *)
415 (** [succ ipv6] is ip address next to [ipv6]. Returns a human-readable error
416 string if it's already the highest address. *)
417
428418 val pred : t -> (t, [> `Msg of string ]) result
419 (** [pred ipv6] is ip address before [ipv6]. Returns a human-readable error
420 string if it's already the lowest address. *)
429421
430422 (** {3 Common addresses} *)
431423
424 val unspecified : t
432425 (** [unspecified] is ::. *)
433 val unspecified : t
434
426
427 val localhost : t
435428 (** [localhost] is ::1. *)
436 val localhost : t
437
429
430 val interface_nodes : t
438431 (** [interface_nodes] is ff01::01. *)
439 val interface_nodes : t
440
432
433 val link_nodes : t
441434 (** [link_nodes] is ff02::01. *)
442 val link_nodes : t
443
435
436 val interface_routers : t
444437 (** [interface_routers] is ff01::02. *)
445 val interface_routers : t
446
438
439 val link_routers : t
447440 (** [link_routers] is ff02::02. *)
448 val link_routers : t
449
441
442 val site_routers : t
450443 (** [site_routers] is ff05::02. *)
451 val site_routers : t
452444
453445 (** A module for manipulating IPv6 network prefixes (CIDR). *)
454446 module Prefix : sig
455447 type addr = t
456448
449 type t
457450 (** Type of a internet protocol subnet: an address and a prefix length. *)
458 type t
459
451
452 val mask : int -> addr
460453 (** [mask n] is the pseudo-address of an [n] bit subnet mask. *)
461 val mask : int -> addr
462
454
455 val make : int -> addr -> t
463456 (** [make n addr] is the cidr of [addr] with [n] bit prefix. *)
464 val make : int -> addr -> t
465
457
458 val prefix : t -> t
466459 (** [prefix cidr] is the subnet prefix of [cidr] where all non-prefix bits
467460 set to 0. *)
468 val prefix : t -> t
469
470 (** [network_address cidr addr] is the address with prefix [cidr]
471 and suffix from [addr].
472 See <http://tools.ietf.org/html/rfc4291#section-2.3>. *)
461
473462 val network_address : t -> addr -> addr
474
463 (** [network_address cidr addr] is the address with prefix [cidr] and suffix
464 from [addr]. See <http://tools.ietf.org/html/rfc4291#section-2.3>. *)
465
466 val of_string_exn : string -> t
475467 (** [of_string_exn cidr] is the subnet prefix represented by the CIDR
476468 string, [cidr]. Raises {!Parse_error} if [cidr] is not a valid
477469 representation of a CIDR notation routing prefix. *)
478 val of_string_exn : string -> t
479
480 (** Same as {!of_string_exn} but returns a result type instead of raising
481 an exception. *)
470
482471 val of_string : string -> (t, [> `Msg of string ]) result
483
484 (** Same as {!of_string_exn} but takes as an extra argument the offset
485 into the string for reading. *)
472 (** Same as {!of_string_exn} but returns a result type instead of raising an
473 exception. *)
474
486475 val of_string_raw : string -> int ref -> t
487
488 (** [to_string cidr] is the CIDR notation string representation
489 of [cidr], i.e. XXX:XX:X::XXX/XX. *)
476 (** Same as {!of_string_exn} but takes as an extra argument the offset into
477 the string for reading. *)
478
490479 val to_string : t -> string
491
492 (** [pp f cidr] outputs a human-readable representation of [cidr]
493 to the formatter [f]. *)
494 val pp : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
495
496 (** [to_buffer buf cidr] writes the string representation
497 of [cidr] to the buffer [buf]. *)
480 (** [to_string cidr] is the CIDR notation string representation of [cidr],
481 i.e. XXX:XX:X::XXX/XX. *)
482
483 val pp : Format.formatter -> t -> unit
484 [@@ocaml.toplevel_printer]
485 (** [pp f cidr] outputs a human-readable representation of [cidr] to the
486 formatter [f]. *)
487
498488 val to_buffer : Buffer.t -> t -> unit
499
489 (** [to_buffer buf cidr] writes the string representation of [cidr] to the
490 buffer [buf]. *)
491
492 val of_netmask_exn : netmask:addr -> address:addr -> t
500493 (** [of_netmask_exn ~netmask ~address] is the subnet prefix of [address]
501494 with netmask [netmask]. *)
502 val of_netmask_exn : netmask:addr -> address:addr -> t
503
504 (** [of_netmask ~netmask ~address] is the cidr of [address] with
505 netmask [netmask]. *)
506 val of_netmask : netmask:addr -> address:addr ->
507 (t, [> `Msg of string ]) result
508
495
496 val of_netmask :
497 netmask:addr -> address:addr -> (t, [> `Msg of string ]) result
498 (** [of_netmask ~netmask ~address] is the cidr of [address] with netmask
499 [netmask]. *)
500
501 val mem : addr -> t -> bool
509502 (** [mem ip subnet] checks whether [ip] is found within [subnet]. *)
510 val mem : addr -> t -> bool
511
512 (** [subset ~subnet ~network] checks whether [subnet] is contained
513 within [network]. *)
503
514504 val subset : subnet:t -> network:t -> bool
515
516 (** [of_addr ip] create a subnet composed of only one address, [ip].
517 It is the same as [make 128 ip]. *)
505 (** [subset ~subnet ~network] checks whether [subnet] is contained within
506 [network]. *)
507
518508 val of_addr : addr -> t
519
509 (** [of_addr ip] create a subnet composed of only one address, [ip]. It is
510 the same as [make 128 ip]. *)
511
512 val global_unicast_001 : t
520513 (** Global Unicast 001, 2000::/3. *)
521 val global_unicast_001 : t
522
514
515 val unique_local : t
523516 (** The Unique Local Unicast (ULA), fc00::/7. *)
524 val unique_local : t
525
517
518 val link : t
526519 (** Link-Local Unicast, fe80::/64. *)
527 val link : t
528
520
521 val multicast : t
529522 (** The multicast network, ff00::/8. *)
530 val multicast : t
531
523
524 val ipv4_mapped : t
532525 (** IPv4-mapped addresses, ::ffff:0:0/96. *)
533 val ipv4_mapped : t
534
526
527 val noneui64_interface : t
535528 (** Global Unicast addresses that don't use Modified EUI64 interface
536529 identifiers, ::/3. *)
537 val noneui64_interface : t
538
530
531 val solicited_node : t
539532 (** Solicited-Node multicast addresses *)
540 val solicited_node : t
541
533
534 val network : t -> addr
542535 (** [network subnet] is the address for [subnet]. *)
543 val network : t -> addr
544
536
537 val netmask : t -> addr
545538 (** [netmask subnet] is the netmask for [subnet]. *)
546 val netmask : t -> addr
547
539
540 val address : t -> addr
548541 (** [address cidr] is the address for [cidr]. *)
549 val address : t -> addr
550
542
543 val bits : t -> int
551544 (** [bits subnet] is the bit size of the [subnet] prefix. *)
552 val bits : t -> int
553
545
546 val first : t -> addr
554547 (** [first subnet] is first valid unicast address in this [subnet]. *)
555 val first : t -> addr
556
548
549 val last : t -> addr
557550 (** [last subnet] is last valid unicast address in this [subnet]. *)
558 val last : t -> addr
559551
560552 include Map.OrderedType with type t := t
561553 end
562554
563 (** [scope ipv6] is the classification of [ipv6] by the {! scope }
564 hierarchy. *)
565555 val scope : t -> scope
566
567 (** [link_address_of_mac mac] is the link-local address for an
568 Ethernet interface derived by the IEEE MAC -> EUI-64 map with
569 the Universal/Local bit complemented for IPv6.
570 @see <https://tools.ietf.org/html/rfc2464#section-4> RFC 2464
571 *)
556 (** [scope ipv6] is the classification of [ipv6] by the {!scope} hierarchy. *)
557
572558 val link_address_of_mac : Macaddr.t -> t
573
559 (** [link_address_of_mac mac] is the link-local address for an Ethernet
560 interface derived by the IEEE MAC -> EUI-64 map with the Universal/Local
561 bit complemented for IPv6.
562
563 @see <https://tools.ietf.org/html/rfc2464#section-4> RFC 2464 *)
564
565 val is_global : t -> bool
574566 (** [is_global ipv6] is a predicate indicating whether [ipv6] globally
575567 addresses a node. *)
576 val is_global : t -> bool
577
568
569 val is_multicast : t -> bool
578570 (** [is_multicast ipv6] is a predicate indicating whether [ipv6] is a
579571 multicast address. *)
580 val is_multicast : t -> bool
581
572
573 val is_private : t -> bool
582574 (** [is_private ipv6] is a predicate indicating whether [ipv6] privately
583575 addresses a node. *)
584 val is_private : t -> bool
585576
586577 include Map.OrderedType with type t := t
587578 end
588579
589580 (** Type of either an IPv4 value or an IPv6 value *)
590 type ('v4,'v6) v4v6 = V4 of 'v4 | V6 of 'v6
591
581 type ('v4, 'v6) v4v6 = V4 of 'v4 | V6 of 'v6
582
583 type t = (V4.t, V6.t) v4v6
592584 (** Type of any IP address *)
593 type t = (V4.t,V6.t) v4v6
594
585
586 val to_string : t -> string
595587 (** [to_string addr] is the text string representation of [addr]. *)
596 val to_string : t -> string
597
588
589 val to_buffer : Buffer.t -> t -> unit
598590 (** [to_buffer buf addr] writes the text string representation of [addr] into
599591 [buf]. *)
600 val to_buffer : Buffer.t -> t -> unit
601
602 (** [pp f ip] outputs a human-readable representation of [ip] to the
603 formatter [f]. *)
604 val pp : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
605
606 (** [of_string_exn s] parses [s] as an IPv4 or IPv6 address.
607 Raises {!Parse_error} if [s] is not a valid string representation of an IP
608 address. *)
592
593 val pp : Format.formatter -> t -> unit
594 [@@ocaml.toplevel_printer]
595 (** [pp f ip] outputs a human-readable representation of [ip] to the formatter
596 [f]. *)
597
609598 val of_string_exn : string -> t
610
599 (** [of_string_exn s] parses [s] as an IPv4 or IPv6 address. Raises
600 {!Parse_error} if [s] is not a valid string representation of an IP address. *)
601
602 val of_string : string -> (t, [> `Msg of string ]) result
611603 (** Same as {!of_string_exn} but returns a result type instead of raising an
612604 exception. *)
613 val of_string : string -> (t, [> `Msg of string ]) result
614
615 (** Same as [of_string_exn] but takes as an extra argument the offset into
616 the string for reading. *)
605
617606 val of_string_raw : string -> int ref -> t
618
619 (** [v4_of_v6 ipv6] is the IPv4 representation of the IPv6 address [ipv6].
620 If [ipv6] is not an IPv4-mapped address, None is returned. *)
607 (** Same as [of_string_exn] but takes as an extra argument the offset into the
608 string for reading. *)
609
621610 val v4_of_v6 : V6.t -> V4.t option
622
611 (** [v4_of_v6 ipv6] is the IPv4 representation of the IPv6 address [ipv6]. If
612 [ipv6] is not an IPv4-mapped address, None is returned. *)
613
614 val to_v4 : t -> V4.t option
623615 (** [to_v4 addr] is the IPv4 representation of [addr]. *)
624 val to_v4 : t -> V4.t option
625
616
617 val v6_of_v4 : V4.t -> V6.t
626618 (** [v6_of_v4 ipv4] is the IPv6 representation of the IPv4 address [ipv4]. *)
627 val v6_of_v4 : V4.t -> V6.t
628
619
620 val to_v6 : t -> V6.t
629621 (** [to_v6 addr] is the IPv6 representation of [addr]. *)
630 val to_v6 : t -> V6.t
631
632 (** [scope addr] is the classification of [addr] by the {! scope }
633 hierarchy. *)
622
634623 val scope : t -> scope
635
636 (** [is_global addr] is a predicate indicating whether [addr] globally
637 addresses a node. *)
624 (** [scope addr] is the classification of [addr] by the {!scope} hierarchy. *)
625
638626 val is_global : t -> bool
639
640 (** [is_multicast addr] is a predicate indicating whether [addr] is a
641 multicast address. *)
627 (** [is_global addr] is a predicate indicating whether [addr] globally addresses
628 a node. *)
629
642630 val is_multicast : t -> bool
643
631 (** [is_multicast addr] is a predicate indicating whether [addr] is a multicast
632 address. *)
633
634 val is_private : t -> bool
644635 (** [is_private addr] is a predicate indicating whether [addr] privately
645636 addresses a node. *)
646 val is_private : t -> bool
647
648 (** [multicast_to_mac addr] is the MAC address corresponding to the
649 multicast address [addr]. See {!V4.multicast_to_mac} and
650 {!V6.multicast_to_mac}.*)
637
651638 val multicast_to_mac : t -> Macaddr.t
652
653 (** [to_domain_name addr] is the domain name label list for reverse
654 lookups of [addr]. This includes the [.in-addr.arpa] or [.ip6.arpa] suffix. *)
639 (** [multicast_to_mac addr] is the MAC address corresponding to the multicast
640 address [addr]. See {!V4.multicast_to_mac} and {!V6.multicast_to_mac}.*)
641
655642 val to_domain_name : t -> [ `host ] Domain_name.t
656
643 (** [to_domain_name addr] is the domain name label list for reverse lookups of
644 [addr]. This includes the [.in-addr.arpa] or [.ip6.arpa] suffix. *)
645
646 val of_domain_name : 'a Domain_name.t -> t option
657647 (** [of_domain_name name] is [Some t] if the [name] has an [.in-addr.arpa] or
658648 [ip6.arpa] suffix, and an IP address prefixed. *)
659 val of_domain_name : 'a Domain_name.t -> t option
660
661 (** [succ addr] is ip address next to [addr]. Returns a human-readable
662 error string if it's already the highest address. *)
649
663650 val succ : t -> (t, [> `Msg of string ]) result
664
665 (** [pred addr] is ip address before [addr]. Returns a human-readable
666 error string if it's already the lowest address. *)
651 (** [succ addr] is ip address next to [addr]. Returns a human-readable error
652 string if it's already the highest address. *)
653
667654 val pred : t -> (t, [> `Msg of string ]) result
655 (** [pred addr] is ip address before [addr]. Returns a human-readable error
656 string if it's already the lowest address. *)
668657
669658 module Prefix : sig
670659 type addr = t
671660
661 type t = (V4.Prefix.t, V6.Prefix.t) v4v6
672662 (** Type of a internet protocol subnet *)
673 type t = (V4.Prefix.t, V6.Prefix.t) v4v6
674
663
664 val to_string : t -> string
675665 (** [to_string subnet] is the text string representation of [subnet]. *)
676 val to_string : t -> string
677
666
667 val to_buffer : Buffer.t -> t -> unit
678668 (** [to_buffer buf subnet] writes the text string representation of [subnet]
679669 into [buf]. *)
680 val to_buffer : Buffer.t -> t -> unit
681
682 (** [pp f subnet] outputs a human-readable representation of [subnet]
683 to the formatter [f]. *)
684 val pp : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
685
686 (** [of_string_exn cidr] is the subnet prefix represented by the CIDR
687 string, [cidr]. Raises {!Parse_error} if [cidr] is not a valid
688 representation of a CIDR notation routing prefix. *)
670
671 val pp : Format.formatter -> t -> unit
672 [@@ocaml.toplevel_printer]
673 (** [pp f subnet] outputs a human-readable representation of [subnet] to the
674 formatter [f]. *)
675
689676 val of_string_exn : string -> t
690
691 (** Same as {!of_string_exn} but returns a result type instead of raising
692 an exception. *)
693 val of_string : string -> (t, [> `Msg of string]) result
694
695 (** Same as {!of_string_exn} but takes as an extra argument the offset
696 into the string for reading. *)
677 (** [of_string_exn cidr] is the subnet prefix represented by the CIDR string,
678 [cidr]. Raises {!Parse_error} if [cidr] is not a valid representation of a
679 CIDR notation routing prefix. *)
680
681 val of_string : string -> (t, [> `Msg of string ]) result
682 (** Same as {!of_string_exn} but returns a result type instead of raising an
683 exception. *)
684
697685 val of_string_raw : string -> int ref -> t
698
699 (** [v4_of_v6 ipv6] is the IPv4 representation of the IPv6 subnet [ipv6].
700 If [ipv6] is not an IPv4-mapped subnet, None is returned. *)
686 (** Same as {!of_string_exn} but takes as an extra argument the offset into
687 the string for reading. *)
688
701689 val v4_of_v6 : V6.Prefix.t -> V4.Prefix.t option
702
690 (** [v4_of_v6 ipv6] is the IPv4 representation of the IPv6 subnet [ipv6]. If
691 [ipv6] is not an IPv4-mapped subnet, None is returned. *)
692
693 val to_v4 : t -> V4.Prefix.t option
703694 (** [to_v4 subnet] is the IPv4 representation of [subnet]. *)
704 val to_v4 : t -> V4.Prefix.t option
705
695
696 val v6_of_v4 : V4.Prefix.t -> V6.Prefix.t
706697 (** [v6_of_v4 ipv4] is the IPv6 representation of the IPv4 subnet [ipv4]. *)
707 val v6_of_v4 : V4.Prefix.t -> V6.Prefix.t
708
698
699 val to_v6 : t -> V6.Prefix.t
709700 (** [to_v6 subnet] is the IPv6 representation of [subnet]. *)
710 val to_v6 : t -> V6.Prefix.t
711
701
702 val mem : addr -> t -> bool
712703 (** [mem ip subnet] checks whether [ip] is found within [subnet]. *)
713 val mem : addr -> t -> bool
714
715 (** [subset ~subnet ~network] checks whether [subnet] is contained
716 within [network]. *)
704
717705 val subset : subnet:t -> network:t -> bool
718
706 (** [subset ~subnet ~network] checks whether [subnet] is contained within
707 [network]. *)
708
709 val of_addr : addr -> t
719710 (** [of_addr ip] create a subnet composed of only one address, [ip].*)
720 val of_addr : addr -> t
721
711
712 val network : t -> addr
722713 (** [network subnet] is the address for [subnet]. *)
723 val network : t -> addr
724
714
715 val netmask : t -> addr
725716 (** [netmask subnet] is the netmask for [subnet]. *)
726 val netmask : t -> addr
727
717
718 val first : t -> addr
728719 (** [first subnet] is first valid unicast address in this [subnet]. *)
729 val first : t -> addr
730
720
721 val last : t -> addr
731722 (** [last subnet] is last valid unicast address in this [subnet]. *)
732 val last : t -> addr
733723
734724 include Map.OrderedType with type t := t
735725 end
2222 with Ipaddr.Parse_error (msg, _) -> Error (`Msg ("Ipaddr: " ^ msg))
2323
2424 module V4 = struct
25
2625 let of_cstruct_exn cs =
2726 let len = Cstruct.len cs in
2827 if len < 4 then raise (need_more (Cstruct.to_string cs));
2928 Ipaddr.V4.of_int32 (Cstruct.BE.get_uint32 cs 0)
3029
31 let of_cstruct cs =
32 try_with_result of_cstruct_exn cs
30 let of_cstruct cs = try_with_result of_cstruct_exn cs
3331
3432 let write_cstruct_exn i cs =
3533 let len = Cstruct.len cs in
4038 let cs = allocator 4 in
4139 write_cstruct_exn i cs;
4240 cs
43
4441 end
4542
4643 module V6 = struct
47
4844 open Ipaddr.V6
4945
5046 let of_cstruct_exn cs =
5652 let lolo = Cstruct.BE.get_uint32 cs 12 in
5753 of_int32 (hihi, hilo, lohi, lolo)
5854
59 let of_cstruct cs =
60 try_with_result of_cstruct_exn cs
55 let of_cstruct cs = try_with_result of_cstruct_exn cs
6156
6257 let write_cstruct_exn i cs =
6358 let len = Cstruct.len cs in
1919
2020 (** Ipv4 address conversions *)
2121 module V4 : sig
22 val of_cstruct : Cstruct.t -> (Ipaddr.V4.t, [> `Msg of string ]) result
23 (** [of_cstruct c] parses the first 4 octets of [c] into an IPv4 address. *)
2224
23 (** [of_cstruct c] parses the first 4 octets of [c] into an IPv4 address. *)
24 val of_cstruct : Cstruct.t -> (Ipaddr.V4.t, [> `Msg of string ]) result
25
25 val of_cstruct_exn : Cstruct.t -> Ipaddr.V4.t
2626 (** [of_cstruct_exn] parses the first 4 octets of [c] into an IPv4 address.
2727 Raises {!Ipaddr.Parse_failure} on error. *)
28 val of_cstruct_exn : Cstruct.t -> Ipaddr.V4.t
2928
30 (** [to_cstruct ipv4] is a cstruct of length 4 encoding [ipv4].
31 The cstruct is allocated using [allocator]. If [allocator] is
32 not provided, [Cstruct.create] is used. *)
33 val to_cstruct: ?allocator:(int -> Cstruct.t) -> Ipaddr.V4.t -> Cstruct.t
29 val to_cstruct : ?allocator:(int -> Cstruct.t) -> Ipaddr.V4.t -> Cstruct.t
30 (** [to_cstruct ipv4] is a cstruct of length 4 encoding [ipv4]. The cstruct is
31 allocated using [allocator]. If [allocator] is not provided,
32 [Cstruct.create] is used. *)
3433
35 (** [write_cstruct_exn ipv4 cs] writes 4 bytes into [cs] representing
36 the [ipv4] address octets. Raises {!Ipaddr.Parse_error} if [cs]
37 is not at least 4 bytes long. *)
3834 val write_cstruct_exn : Ipaddr.V4.t -> Cstruct.t -> unit
35 (** [write_cstruct_exn ipv4 cs] writes 4 bytes into [cs] representing the
36 [ipv4] address octets. Raises {!Ipaddr.Parse_error} if [cs] is not at
37 least 4 bytes long. *)
3938 end
4039
4140 (** Ipv6 address conversions *)
4241 module V6 : sig
42 val of_cstruct : Cstruct.t -> (Ipaddr.V6.t, [> `Msg of string ]) result
43 (** [of_cstruct c] parses the first 16 octets of [c] into an IPv6 address. *)
4344
44 (** [of_cstruct c] parses the first 16 octets of [c] into an IPv6 address. *)
45 val of_cstruct : Cstruct.t -> (Ipaddr.V6.t, [> `Msg of string ]) result
46
45 val of_cstruct_exn : Cstruct.t -> Ipaddr.V6.t
4746 (** [of_cstruct_exn] parses the first 16 octets of [c] into an IPv6 address.
4847 Raises {!Ipaddr.Parse_failure} on error. *)
49 val of_cstruct_exn : Cstruct.t -> Ipaddr.V6.t
5048
51 (** [to_cstruct ipv6] is a cstruct of length 16 encoding [ipv6].
52 The cstruct is allocated using [allocator]. If [allocator] is
53 not provided, [Cstruct.create] is used. *)
54 val to_cstruct: ?allocator:(int -> Cstruct.t) -> Ipaddr.V6.t -> Cstruct.t
49 val to_cstruct : ?allocator:(int -> Cstruct.t) -> Ipaddr.V6.t -> Cstruct.t
50 (** [to_cstruct ipv6] is a cstruct of length 16 encoding [ipv6]. The cstruct
51 is allocated using [allocator]. If [allocator] is not provided,
52 [Cstruct.create] is used. *)
5553
56 (** [write_cstruct_exn ipv6 cs] writes 16 bytes into [cs] representing
57 the [ipv6] address octets. Raises {!Ipaddr.Parse_error} if [cs]
58 is not at least 16 bytes long. *)
5954 val write_cstruct_exn : Ipaddr.V6.t -> Cstruct.t -> unit
55 (** [write_cstruct_exn ipv6 cs] writes 16 bytes into [cs] representing the
56 [ipv6] address octets. Raises {!Ipaddr.Parse_error} if [cs] is not at
57 least 16 bytes long. *)
6058 end
1919 let of_sexp fn = function
2020 | Sexp.List _ -> failwith "expecting sexp atom"
2121 | Sexp.Atom s -> (
22 match fn s with Ok r -> r | Error (`Msg msg) -> failwith msg )
22 match fn s with Ok r -> r | Error (`Msg msg) -> failwith msg)
2323
2424 let to_sexp fn t = Sexp.Atom (fn t)
2525
1414 *
1515 *)
1616
17 (** serialisers to and from {!Ipaddr} and s-expression {!Sexplib0} format
18
19 To use these with ppx-based derivers, simply replace the reference to the
20 {!Ipaddr} type definition with {!Ipaddr_sexp} instead. That will import the
21 sexp-conversion functions, and the actual type definitions are simply aliases
22 to the corresponding type within {!Ipaddr}. For example, you might do:
17 (** serialisers to and from {!Ipaddr} and s-expression {!Sexplib0} format
2318
24 {[
25 type t = {
26 ip: Ipaddr_sexp.t;
27 mac: Macaddr_sexp.t;
28 } [@@deriving sexp]
29 ]}
19 To use these with ppx-based derivers, simply replace the reference to the
20 {!Ipaddr} type definition with {!Ipaddr_sexp} instead. That will import the
21 sexp-conversion functions, and the actual type definitions are simply
22 aliases to the corresponding type within {!Ipaddr}. For example, you might
23 do:
3024
31 The actual types of the records will be aliases to the main library types,
32 and there will be two new functions available as converters.
25 {[
26 type t = { ip : Ipaddr_sexp.t; mac : Macaddr_sexp.t } [@@deriving sexp]
27 ]}
3328
34 {[
35 type t = {
36 ip: Ipaddr.t;
37 mac: Macaddr.t;
38 }
39 val sexp_of_t : t -> Sexplib0.t
40 val t_of_sexp : Sexplib0.t -> t
41 ]}
42 *)
29 The actual types of the records will be aliases to the main library types,
30 and there will be two new functions available as converters.
31
32 {[
33 type t = { ip : Ipaddr.t; mac : Macaddr.t }
34
35 val sexp_of_t : t -> Sexplib0.t
36
37 val t_of_sexp : Sexplib0.t -> t
38 ]} *)
4339
4440 type t = Ipaddr.t
4541
0 let printers = [
1 "Ipaddr.pp";
2 "Ipaddr.Prefix.pp";
3 "Ipaddr.V4.pp";
4 "Ipaddr.V4.Prefix.pp";
5 "Ipaddr.V6.pp";
6 "Ipaddr.V6.Prefix.pp";
7 "Macaddr.pp";
8 ]
0 let printers =
1 [
2 "Ipaddr.pp";
3 "Ipaddr.Prefix.pp";
4 "Ipaddr.V4.pp";
5 "Ipaddr.V4.Prefix.pp";
6 "Ipaddr.V6.pp";
7 "Ipaddr.V6.Prefix.pp";
8 "Macaddr.pp";
9 ]
910
10 let eval_string
11 ?(print_outcome = false) ?(err_formatter = Format.err_formatter) str =
11 let eval_string ?(print_outcome = false) ?(err_formatter = Format.err_formatter)
12 str =
1213 let lexbuf = Lexing.from_string str in
1314 let phrase = !Toploop.parse_toplevel_phrase lexbuf in
1415 Toploop.execute_phrase print_outcome err_formatter phrase
00 val printers : string list
1
12 val eval_string :
23 ?print_outcome:bool -> ?err_formatter:Format.formatter -> string -> bool
4
35 val install_printers : string list -> bool
1414 *
1515 *)
1616
17 let to_inet_addr t =
18 Unix.inet_addr_of_string (Ipaddr.to_string t)
17 let to_inet_addr t = Unix.inet_addr_of_string (Ipaddr.to_string t)
1918
20 let of_inet_addr t =
21 Ipaddr.of_string_exn (Unix.string_of_inet_addr t)
19 let of_inet_addr t = Ipaddr.of_string_exn (Unix.string_of_inet_addr t)
2220
2321 module V4 = struct
22 let to_inet_addr t = Unix.inet_addr_of_string (Ipaddr.V4.to_string t)
2423
25 let to_inet_addr t =
26 Unix.inet_addr_of_string (Ipaddr.V4.to_string t)
24 let of_inet_addr_exn t = Ipaddr.V4.of_string_exn (Unix.string_of_inet_addr t)
2725
28 let of_inet_addr_exn t =
29 Ipaddr.V4.of_string_exn (Unix.string_of_inet_addr t)
30
31 let of_inet_addr t =
32 try Some (of_inet_addr_exn t)
33 with _ -> None
26 let of_inet_addr t = try Some (of_inet_addr_exn t) with _ -> None
3427 end
3528
3629 module V6 = struct
30 let to_inet_addr t = Unix.inet_addr_of_string (Ipaddr.V6.to_string t)
3731
38 let to_inet_addr t =
39 Unix.inet_addr_of_string (Ipaddr.V6.to_string t)
32 let of_inet_addr_exn t = Ipaddr.V6.of_string_exn (Unix.string_of_inet_addr t)
4033
41 let of_inet_addr_exn t =
42 Ipaddr.V6.of_string_exn (Unix.string_of_inet_addr t)
43
44 let of_inet_addr t =
45 try Some (of_inet_addr_exn t)
46 with _ -> None
34 let of_inet_addr t = try Some (of_inet_addr_exn t) with _ -> None
4735 end
1616
1717 (** Convert to and from [Unix] to [Ipaddr] representations
1818
19 {e %%VERSION%% - {{:%%PKG_HOMEPAGE%% }homepage}} *)
19 {e v5.0.1 - {{:https://github.com/mirage/ocaml-ipaddr} homepage}} *)
2020
21 (** [to_inet_addr ip] is the {! Unix.inet_addr} equivalent of the
22 IPv4 or IPv6 address [ip]. *)
2321 val to_inet_addr : Ipaddr.t -> Unix.inet_addr
22 (** [to_inet_addr ip] is the {!Unix.inet_addr} equivalent of the IPv4 or IPv6
23 address [ip]. *)
2424
25 (** [of_inet_addr ip] is the {! Ipaddr.t} equivalent of the
26 {! Unix.inet_addr} [ip]. *)
2725 val of_inet_addr : Unix.inet_addr -> Ipaddr.t
26 (** [of_inet_addr ip] is the {!Ipaddr.t} equivalent of the {!Unix.inet_addr}
27 [ip]. *)
2828
2929 module V4 : sig
30 val to_inet_addr : Ipaddr.V4.t -> Unix.inet_addr
31 (** [to_inet_addr ip] is the {!Unix.inet_addr} equivalent of the IPv4 address
32 [ip]. *)
3033
31 (** [to_inet_addr ip] is the {! Unix.inet_addr} equivalent of the
32 IPv4 address [ip]. *)
33 val to_inet_addr : Ipaddr.V4.t -> Unix.inet_addr
34 val of_inet_addr_exn : Unix.inet_addr -> Ipaddr.V4.t
35 (** [of_inet_addr_exn ip] is the {!Ipaddr.t} equivalent of the
36 {!Unix.inet_addr} [ip] IPv4 address. Raises {!Ipaddr.Parse_error} if [ip]
37 is not a valid representation of an IPv4 address. *)
3438
35 (** [of_inet_addr_exn ip] is the {! Ipaddr.t} equivalent of the
36 {!Unix.inet_addr} [ip] IPv4 address. Raises {! Ipaddr.Parse_error} if
37 [ip] is not a valid representation of an IPv4 address. *)
38 val of_inet_addr_exn : Unix.inet_addr -> Ipaddr.V4.t
39
39 val of_inet_addr : Unix.inet_addr -> Ipaddr.V4.t option
4040 (** Same as [of_inet_addr_exn] but returns an option type instead of raising
4141 an exception. *)
42 val of_inet_addr : Unix.inet_addr -> Ipaddr.V4.t option
4342 end
4443
4544 module V6 : sig
45 val to_inet_addr : Ipaddr.V6.t -> Unix.inet_addr
46 (** [to_inet_addr ip] is the {!Unix.inet_addr} equivalent of the IPv6 address
47 [ip]. *)
4648
47 (** [to_inet_addr ip] is the {! Unix.inet_addr} equivalent of the
48 IPv6 address [ip]. *)
49 val to_inet_addr : Ipaddr.V6.t -> Unix.inet_addr
49 val of_inet_addr_exn : Unix.inet_addr -> Ipaddr.V6.t
50 (** [of_inet_addr_exn ip] is the {!Ipaddr.t} equivalent of the
51 {!Unix.inet_addr} [ip] IPv6 address. Raises {!Ipaddr.Parse_error} if [ip]
52 is not a valid representation of an IPv6 address. *)
5053
51
52 (** [of_inet_addr_exn ip] is the {! Ipaddr.t} equivalent of the
53 {!Unix.inet_addr} [ip] IPv6 address. Raises {! Ipaddr.Parse_error} if
54 [ip] is not a valid representation of an IPv6 address. *)
55 val of_inet_addr_exn : Unix.inet_addr -> Ipaddr.V6.t
56
54 val of_inet_addr : Unix.inet_addr -> Ipaddr.V6.t option
5755 (** Same as [of_inet_addr_exn] but returns an option type instead of raising
5856 an exception. *)
59 val of_inet_addr : Unix.inet_addr -> Ipaddr.V6.t option
6057 end
1919 let need_more x = Parse_error ("not enough data", x)
2020
2121 let try_with_result fn a =
22 try Ok (fn a)
23 with Parse_error (msg, _) -> Error (`Msg ("Macaddr: " ^ msg))
22 try Ok (fn a) with Parse_error (msg, _) -> Error (`Msg ("Macaddr: " ^ msg))
2423
2524 type t = Bytes.t (* length 6 only *)
2625
2827
2928 (* Raw MAC address off the wire (network endian) *)
3029 let of_octets_exn x =
31 if String.length x <> 6
32 then raise (Parse_error ("MAC is exactly 6 bytes", x))
30 if String.length x <> 6 then raise (Parse_error ("MAC is exactly 6 bytes", x))
3331 else Bytes.of_string x
3432
3533 let of_octets x = try_with_result of_octets_exn x
3634
3735 let int_of_hex_char c =
3836 let c = int_of_char (Char.uppercase_ascii c) - 48 in
39 if c > 9
40 then if c > 16
41 then c - 7 (* upper hex offset *)
42 else -1 (* :;<=>?@ *)
37 if c > 9 then
38 if c > 16 then c - 7 (* upper hex offset *) else -1 (* :;<=>?@ *)
4339 else c
4440
45 let is_hex i = i >=0 && i < 16
41 let is_hex i = i >= 0 && i < 16
4642
4743 let bad_char i s =
48 let msg = Printf.sprintf "invalid character '%c' at %d" s.[i] i
49 in Parse_error (msg, s)
44 let msg = Printf.sprintf "invalid character '%c' at %d" s.[i] i in
45 Parse_error (msg, s)
5046
5147 let parse_hex_int term s i =
5248 let len = String.length s in
5349 let rec hex prev =
5450 let j = !i in
5551 if j >= len then prev
56 else let c = s.[j] in
57 let k = int_of_hex_char c in
58 if is_hex k
59 then (incr i; hex ((prev lsl 4) + k))
60 else if List.mem c term
61 then prev
62 else raise (bad_char j s)
52 else
53 let c = s.[j] in
54 let k = int_of_hex_char c in
55 if is_hex k then (
56 incr i;
57 hex ((prev lsl 4) + k))
58 else if List.mem c term then prev
59 else raise (bad_char j s)
6360 in
6461 let i = !i in
65 if i < len
66 then if is_hex (int_of_hex_char s.[i])
67 then hex 0
68 else raise (bad_char i s)
62 if i < len then
63 if is_hex (int_of_hex_char s.[i]) then hex 0 else raise (bad_char i s)
6964 else raise (need_more s)
7065
7166 let parse_sextuple s i =
7267 let m = Bytes.create 6 in
7368 try
7469 let p = !i in
75 Bytes.set m 0 (Char.chr (parse_hex_int [':';'-'] s i));
76 if !i >= String.length s
77 then raise (need_more s)
70 Bytes.set m 0 (Char.chr (parse_hex_int [ ':'; '-' ] s i));
71 if !i >= String.length s then raise (need_more s)
7872 else
79 let sep = [s.[!i]] in
80 (if !i - p <> 2 then raise (Parse_error ("hex pairs required",s)));
73 let sep = [ s.[!i] ] in
74 if !i - p <> 2 then raise (Parse_error ("hex pairs required", s));
8175 incr i;
82 for k=1 to 4 do
76 for k = 1 to 4 do
8377 let p = !i in
8478 Bytes.set m k (Char.chr (parse_hex_int sep s i));
85 (if !i - p <> 2 then raise (Parse_error ("hex pairs required",s)));
86 incr i;
79 if !i - p <> 2 then raise (Parse_error ("hex pairs required", s));
80 incr i
8781 done;
8882 let p = !i in
8983 Bytes.set m 5 (Char.chr (parse_hex_int [] s i));
90 (if !i - p <> 2 then raise (Parse_error ("hex pairs required",s)));
84 if !i - p <> 2 then raise (Parse_error ("hex pairs required", s));
9185 m
9286 with Invalid_argument _ ->
93 raise (Parse_error ("address segment too large",s))
87 raise (Parse_error ("address segment too large", s))
9488
9589 (* Read a MAC address colon-separated string *)
9690 let of_string_exn x = parse_sextuple x (ref 0)
9993
10094 let chri x i = Char.code (Bytes.get x i)
10195
102 let to_string ?(sep=':') x =
103 Printf.sprintf "%02x%c%02x%c%02x%c%02x%c%02x%c%02x"
104 (chri x 0) sep
105 (chri x 1) sep
106 (chri x 2) sep
107 (chri x 3) sep
108 (chri x 4) sep
109 (chri x 5)
96 let to_string ?(sep = ':') x =
97 Printf.sprintf "%02x%c%02x%c%02x%c%02x%c%02x%c%02x" (chri x 0) sep (chri x 1)
98 sep (chri x 2) sep (chri x 3) sep (chri x 4) sep (chri x 5)
11099
111100 let to_octets x = Bytes.to_string x
112101
113 let pp ppf i =
114 Format.fprintf ppf "%s" (to_string i)
102 let pp ppf i = Format.fprintf ppf "%s" (to_string i)
115103
116104 let broadcast = Bytes.make 6 '\255'
117105
118106 let make_local bytegenf =
119107 let x = Bytes.create 6 in
120108 (* set locally administered and unicast bits *)
121 Bytes.set x 0 (Char.chr ((((bytegenf 0) lor 2) lsr 1) lsl 1));
122 for i = 1 to 5 do Bytes.set x i (Char.chr (bytegenf i)) done;
109 Bytes.set x 0 (Char.chr (((bytegenf 0 lor 2) lsr 1) lsl 1));
110 for i = 1 to 5 do
111 Bytes.set x i (Char.chr (bytegenf i))
112 done;
123113 x
124114
125 let get_oui x =
126 ((chri x 0) lsl 16) lor ((chri x 1) lsl 8) lor (chri x 2)
115 let get_oui x = (chri x 0 lsl 16) lor (chri x 1 lsl 8) lor chri x 2
127116
128 let is_local x = (((chri x 0) lsr 1) land 1) = 1
117 let is_local x = (chri x 0 lsr 1) land 1 = 1
129118
130 let is_unicast x = ((chri x 0) land 1) = 0
119 let is_unicast x = chri x 0 land 1 = 0
1515
1616 (** A library for manipulation of MAC address representations.
1717
18 {e %%VERSION%% - {{:%%PKG_HOMEPAGE%% }homepage}} *)
18 {e v5.0.1 - {{:https://github.com/mirage/ocaml-ipaddr} homepage}} *)
1919
20 (** [Parse_error (err,packet)] is raised when parsing of the MAC
21 address syntax fails. [err] contains a human-readable error
22 and [packet] is the original octet list that failed to parse. *)
2320 exception Parse_error of string * string
21 (** [Parse_error (err,packet)] is raised when parsing of the MAC address syntax
22 fails. [err] contains a human-readable error and [packet] is the original
23 octet list that failed to parse. *)
2424
25 type t
2526 (** Type of the hardware address (MAC) of an ethernet interface. *)
26 type t
2727
2828 (** {2 Functions converting MAC addresses to/from octets/string} *)
2929
30 (** [of_octets_exn buf] is the hardware address extracted from
31 [buf]. Raises [Parse_error] if [buf] has not length 6. *)
3230 val of_octets_exn : string -> t
31 (** [of_octets_exn buf] is the hardware address extracted from [buf]. Raises
32 [Parse_error] if [buf] has not length 6. *)
3333
34 (** Same as {!of_octets_exn} but returns a result type instead of
35 raising an exception. *)
36 val of_octets : string -> (t, [> `Msg of string]) result
34 val of_octets : string -> (t, [> `Msg of string ]) result
35 (** Same as {!of_octets_exn} but returns a result type instead of raising an
36 exception. *)
3737
38 (** [of_string_exn mac_string] is the human-readable hardware address represented by
39 [mac_string]. Raises {!Parse_error} if [mac_string] is not a
38 val of_string_exn : string -> t
39 (** [of_string_exn mac_string] is the human-readable hardware address
40 represented by [mac_string]. Raises {!Parse_error} if [mac_string] is not a
4041 valid representation of a MAC address. *)
41 val of_string_exn : string -> t
4242
43 val of_string : string -> (t, [> `Msg of string ]) result
4344 (** Same as {!of_string_exn} but returns a result type instead of raising an
4445 exception. *)
45 val of_string : string -> (t, [> `Msg of string]) result
4646
47 (** [to_octets mac_addr] is a string of size 6 encoding [mac_addr] as a
48 sequence of bytes. *)
4947 val to_octets : t -> string
48 (** [to_octets mac_addr] is a string of size 6 encoding [mac_addr] as a sequence
49 of bytes. *)
5050
51 val to_string : ?sep:char -> t -> string
5152 (** [to_string ?(sep=':') mac_addr] is the [sep]-separated string representation
5253 of [mac_addr], i.e. [xx:xx:xx:xx:xx:xx]. *)
53 val to_string : ?sep:char -> t -> string
5454
55 (** [pp f mac_addr] outputs a human-readable representation of [mac_addr] to
56 the formatter [f]. *)
57 val pp : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
55 val pp : Format.formatter -> t -> unit
56 [@@ocaml.toplevel_printer]
57 (** [pp f mac_addr] outputs a human-readable representation of [mac_addr] to the
58 formatter [f]. *)
5859
60 val broadcast : t
5961 (** [broadcast] is [ff:ff:ff:ff:ff:ff]. *)
60 val broadcast : t
6162
62 (** [make_local bytegen] creates a unicast, locally administered MAC
63 address given a function mapping octet offset to octet value. *)
6463 val make_local : (int -> int) -> t
64 (** [make_local bytegen] creates a unicast, locally administered MAC address
65 given a function mapping octet offset to octet value. *)
6566
67 val get_oui : t -> int
6668 (** [get_oui macaddr] is the integer organization identifier for [macaddr]. *)
67 val get_oui : t -> int
6869
69 (** [is_local macaddr] is the predicate on the locally administered bit
70 of [macaddr]. *)
7170 val is_local : t -> bool
71 (** [is_local macaddr] is the predicate on the locally administered bit of
72 [macaddr]. *)
7273
73 (** [is_unicast macaddr] the is the predicate on the unicast bit of
74 [macaddr]. *)
7574 val is_unicast : t -> bool
75 (** [is_unicast macaddr] the is the predicate on the unicast bit of [macaddr]. *)
7676
7777 include Map.OrderedType with type t := t
2020 with Macaddr.Parse_error (msg, _) -> Error (`Msg ("Macaddr: " ^ msg))
2121
2222 let of_cstruct_exn cs =
23 if Cstruct.len cs <> 6
24 then raise (Macaddr.Parse_error ("MAC is exactly 6 bytes", Cstruct.to_string cs))
23 if Cstruct.len cs <> 6 then
24 raise (Macaddr.Parse_error ("MAC is exactly 6 bytes", Cstruct.to_string cs))
2525 else Cstruct.to_string cs |> Macaddr.of_octets_exn
2626
27 let of_cstruct cs =
28 try_with_result of_cstruct_exn cs
27 let of_cstruct cs = try_with_result of_cstruct_exn cs
2928
30 let write_cstruct_exn (mac:Macaddr.t) cs =
29 let write_cstruct_exn (mac : Macaddr.t) cs =
3130 let len = Cstruct.len cs in
3231 let mac = Macaddr.to_octets mac in
3332 if len <> 6 then raise (Macaddr.Parse_error ("MAC is exactly 6 bytes", mac));
1717
1818 (** Convert to and from Cstructs and MAC address. *)
1919
20 val of_cstruct : Cstruct.t -> (Macaddr.t, [> `Msg of string ]) result
2021 (** [of_cstruct c] parses the 6 octets of [c] into a MAC address. *)
21 val of_cstruct : Cstruct.t -> (Macaddr.t, [> `Msg of string ]) result
2222
23 (** [of_cstruct_exn] parses the 6 octets of [c] into a MAC address.
24 Raises {!Macaddr.Parse_failure} on error. *)
2523 val of_cstruct_exn : Cstruct.t -> Macaddr.t
24 (** [of_cstruct_exn] parses the 6 octets of [c] into a MAC address. Raises
25 {!Macaddr.Parse_failure} on error. *)
2626
27 (** [to_cstruct mac] is a cstruct of length 4 encoding [ipv4].
28 The cstruct is allocated using [allocator]. If [allocator] is
29 not provided, [Cstruct.create] is used. *)
30 val to_cstruct: ?allocator:(int -> Cstruct.t) -> Macaddr.t -> Cstruct.t
27 val to_cstruct : ?allocator:(int -> Cstruct.t) -> Macaddr.t -> Cstruct.t
28 (** [to_cstruct mac] is a cstruct of length 4 encoding [ipv4]. The cstruct is
29 allocated using [allocator]. If [allocator] is not provided,
30 [Cstruct.create] is used. *)
3131
32 (** [write_cstruct_exn mac cs] writes 6 bytes into [cs] representing
33 the [mac] address octets. Raises {!Macaddr.Parse_error} if [cs]
34 is not 6 bytes long. *)
3532 val write_cstruct_exn : Macaddr.t -> Cstruct.t -> unit
33 (** [write_cstruct_exn mac cs] writes 6 bytes into [cs] representing the [mac]
34 address octets. Raises {!Macaddr.Parse_error} if [cs] is not 6 bytes long. *)
1919 let of_sexp fn = function
2020 | Sexp.List _ -> failwith "expecting sexp atom"
2121 | Sexp.Atom s -> (
22 match fn s with Ok r -> r | Error (`Msg msg) -> failwith msg )
22 match fn s with Ok r -> r | Error (`Msg msg) -> failwith msg)
2323
2424 let to_sexp fn t = Sexp.Atom (fn t)
2525
1616
1717 (** serialisers to and from {!Macaddr} and s-expression {!Sexplib0} format
1818
19 To use these with ppx-based derivers, simply replace the reference to the
20 {!Macaddr} type definition with {!Macaddr_sexp} instead. That will import the
21 sexp-conversion functions, and the actual type definitions are simply aliases
22 to the corresponding type within {!Ipaddr}. For example, you might do:
19 To use these with ppx-based derivers, simply replace the reference to the
20 {!Macaddr} type definition with {!Macaddr_sexp} instead. That will import
21 the sexp-conversion functions, and the actual type definitions are simply
22 aliases to the corresponding type within {!Ipaddr}. For example, you might
23 do:
2324
24 {[
25 type t = {
26 ip: Ipaddr_sexp.t;
27 mac: Macaddr_sexp.t;
28 } [@@deriving sexp]
29 ]}
25 {[
26 type t = { ip : Ipaddr_sexp.t; mac : Macaddr_sexp.t } [@@deriving sexp]
27 ]}
3028
31 The actual types of the records will be aliases to the main library types,
32 and there will be two new functions available as converters.
29 The actual types of the records will be aliases to the main library types,
30 and there will be two new functions available as converters.
3331
34 {[
35 type t = {
36 ip: Ipaddr.t;
37 mac: Macaddr.t;
38 }
39 val sexp_of_t : t -> Sexplib0.t
40 val t_of_sexp : Sexplib0.t -> t
41 ]}
42 *)
32 {[
33 type t = { ip : Ipaddr.t; mac : Macaddr.t }
34
35 val sexp_of_t : t -> Sexplib0.t
36
37 val t_of_sexp : Sexplib0.t -> t
38 ]} *)
4339
4440 type t = Macaddr.t
4541
4844 val t_of_sexp : Sexplib0.Sexp.t -> Macaddr.t
4945
5046 val compare : Macaddr.t -> Macaddr.t -> int
51
0 let printers = [
1 "Macaddr.pp";
2 ]
0 let printers = [ "Macaddr.pp" ]
31
4 let eval_string
5 ?(print_outcome = false) ?(err_formatter = Format.err_formatter) str =
2 let eval_string ?(print_outcome = false) ?(err_formatter = Format.err_formatter)
3 str =
64 let lexbuf = Lexing.from_string str in
75 let phrase = !Toploop.parse_toplevel_phrase lexbuf in
86 Toploop.execute_phrase print_outcome err_formatter phrase
0 (rule (copy# ../lib/ipaddr_sexp.ml ipaddr_sexp.ml))
1 (rule (copy# ../lib/macaddr_sexp.ml macaddr_sexp.ml))
2 (rule (copy# ../lib/ipaddr.ml ipaddr_internal.ml))
0 (rule
1 (copy# ../lib/ipaddr_sexp.ml ipaddr_sexp.ml))
32
3 (rule
4 (copy# ../lib/macaddr_sexp.ml macaddr_sexp.ml))
5
6 (rule
7 (copy# ../lib/ipaddr.ml ipaddr_internal.ml))
48
59 (library
610 (name test_macaddr_sexp)
711 (wrapped false)
812 (modules macaddr_sexp)
9 (preprocess (pps ppx_sexp_conv))
13 (preprocess
14 (pps ppx_sexp_conv))
1015 (libraries macaddr sexplib0))
1116
1217 (library
1318 (name test_ipaddr_sexp)
1419 (wrapped false)
1520 (modules ipaddr_sexp)
16 (preprocess (pps ppx_sexp_conv))
21 (preprocess
22 (pps ppx_sexp_conv))
1723 (libraries ipaddr sexplib0))
1824
1925 (test
1717 open OUnit
1818 open Ipaddr
1919
20 let error s msg = s, Parse_error (msg,s)
20 let error s msg = (s, Parse_error (msg, s))
21
2122 let need_more s = error s "not enough data"
23
2224 let bad_char i s =
2325 error s (Printf.sprintf "invalid character '%c' at %d" s.[i] i)
2426
25 let (>>=) v f = match v with Ok v -> f v | Error _ as e -> e
27 let ( >>= ) v f = match v with Ok v -> f v | Error _ as e -> e
2628
2729 let assert_raises ~msg exn test_fn =
2830 assert_raises ~msg exn (fun () ->
29 try test_fn ()
30 with rtexn -> begin
31 (if exn <> rtexn then (
32 Printf.eprintf "Stacktrace for '%s':\n%!" msg;
33 Printexc.print_backtrace stderr;
34 ));
35 raise rtexn
36 end)
31 try test_fn ()
32 with rtexn ->
33 if exn <> rtexn then (
34 Printf.eprintf "Stacktrace for '%s':\n%!" msg;
35 Printexc.print_backtrace stderr);
36 raise rtexn)
3737
3838 module Test_v4 = struct
3939 let test_string_rt () =
40 let addrs = [
41 "192.168.0.1", "192.168.0.1";
42 ] in
43 List.iter (fun (addr,rt) ->
44 let os = V4.of_string_exn addr in
45 let ts = V4.to_string os in
46 assert_equal ~msg:addr ts rt;
47 let os = Ipaddr_sexp.(V4.t_of_sexp (V4.sexp_of_t os)) in
48 let ts = V4.to_string os in
49 assert_equal ~msg:addr ts rt;
50 ) addrs
40 let addrs = [ ("192.168.0.1", "192.168.0.1") ] in
41 List.iter
42 (fun (addr, rt) ->
43 let os = V4.of_string_exn addr in
44 let ts = V4.to_string os in
45 assert_equal ~msg:addr ts rt;
46 let os = Ipaddr_sexp.(V4.t_of_sexp (V4.sexp_of_t os)) in
47 let ts = V4.to_string os in
48 assert_equal ~msg:addr ts rt)
49 addrs
5150
5251 let test_string_rt_bad () =
53 let addrs = [
54 need_more "192.168.0";
55 bad_char 11 "192.168.0.1.1";
56 error "192.268.2.1" "second octet out of bounds";
57 bad_char 4 "192. 168.1.1";
58 bad_char 4 "192..0.1";
59 bad_char 3 "192,168.0.1";
60 ] in
61 List.iter (fun (addr,exn) ->
62 assert_raises ~msg:addr exn (fun () -> V4.of_string_exn addr)
63 ) addrs
52 let addrs =
53 [
54 need_more "192.168.0";
55 bad_char 11 "192.168.0.1.1";
56 error "192.268.2.1" "second octet out of bounds";
57 bad_char 4 "192. 168.1.1";
58 bad_char 4 "192..0.1";
59 bad_char 3 "192,168.0.1";
60 ]
61 in
62 List.iter
63 (fun (addr, exn) ->
64 assert_raises ~msg:addr exn (fun () -> V4.of_string_exn addr))
65 addrs
6466
6567 let test_string_raw_rt () =
66 let addrs = [
67 ("IP: 192.168.0.1!!!",4), ("192.168.0.1",15);
68 ("IP: 192.168.0.1.1!!!",4), ("192.168.0.1",15);
69 ] in
70 List.iter (fun ((addr,off),result) ->
71 let c = ref off in
72 let os = V4.of_string_raw addr c in
73 let ts = V4.to_string os in
74 assert_equal ~msg:addr (ts,!c) result
75 ) addrs
68 let addrs =
69 [
70 (("IP: 192.168.0.1!!!", 4), ("192.168.0.1", 15));
71 (("IP: 192.168.0.1.1!!!", 4), ("192.168.0.1", 15));
72 ]
73 in
74 List.iter
75 (fun ((addr, off), result) ->
76 let c = ref off in
77 let os = V4.of_string_raw addr c in
78 let ts = V4.to_string os in
79 assert_equal ~msg:addr (ts, !c) result)
80 addrs
7681
7782 let test_string_raw_rt_bad () =
78 let addrs = [
79 (let s = "IP: 192.168.0!!!" in
80 (s,4), (Parse_error ("invalid character '!' at 13",s), 13));
81 ] in
82 List.iter (fun ((addr,off),(exn,cursor)) ->
83 let c = ref off in
84 assert_raises ~msg:addr exn (fun () -> V4.of_string_raw addr c);
85 assert_equal ~msg:(Printf.sprintf "%s cursor <> %d (%d)" addr cursor !c)
86 !c cursor
87 ) addrs
83 let addrs =
84 [
85 (let s = "IP: 192.168.0!!!" in
86 ((s, 4), (Parse_error ("invalid character '!' at 13", s), 13)));
87 ]
88 in
89 List.iter
90 (fun ((addr, off), (exn, cursor)) ->
91 let c = ref off in
92 assert_raises ~msg:addr exn (fun () -> V4.of_string_raw addr c);
93 assert_equal
94 ~msg:(Printf.sprintf "%s cursor <> %d (%d)" addr cursor !c)
95 !c cursor)
96 addrs
8897
8998 let test_bytes_rt () =
9099 let addr = "\254\099\003\128" in
91100 assert_equal ~msg:(String.escaped addr)
92 V4.(to_octets (of_octets_exn addr)) addr
101 V4.(to_octets (of_octets_exn addr))
102 addr
93103
94104 let test_bytes_rt_bad () =
95 let addrs = [
96 need_more "\254\099\003";
97 ] in
98 List.iter (fun (addr,exn) ->
99 assert_raises ~msg:(String.escaped addr) exn
100 (fun () -> V4.of_octets_exn addr)
101 ) addrs
105 let addrs = [ need_more "\254\099\003" ] in
106 List.iter
107 (fun (addr, exn) ->
108 assert_raises ~msg:(String.escaped addr) exn (fun () ->
109 V4.of_octets_exn addr))
110 addrs
102111
103112 let test_int32_rt () =
104113 let addr = 0x0_F0_AB_00_01_l in
105 assert_equal ~msg:(Printf.sprintf "%08lX" addr)
106 V4.(to_int32 (of_int32 addr)) addr
114 assert_equal
115 ~msg:(Printf.sprintf "%08lX" addr)
116 V4.(to_int32 (of_int32 addr))
117 addr
107118
108119 let test_prefix_string_rt () =
109 let subnets = [
110 "192.168.0.0/24", "192.168.0.0/24";
111 "0.0.0.0/0", "0.0.0.0/0";
112 "192.168.0.1/24", "192.168.0.0/24";
113 "192.168.0.0/0", "0.0.0.0/0";
114 ] in
115 List.iter (fun (subnet,rt) ->
116 let os = V4.Prefix.of_string_exn subnet |> V4.Prefix.prefix in
117 let ts = V4.Prefix.to_string os in
118 assert_equal ~msg:subnet ts rt;
119 let os = Ipaddr_sexp.(V4.Prefix.(t_of_sexp (sexp_of_t os))) in
120 let ts = V4.Prefix.to_string os in
121 assert_equal ~msg:subnet ts rt;
122 ) subnets
120 let subnets =
121 [
122 ("192.168.0.0/24", "192.168.0.0/24");
123 ("0.0.0.0/0", "0.0.0.0/0");
124 ("192.168.0.1/24", "192.168.0.0/24");
125 ("192.168.0.0/0", "0.0.0.0/0");
126 ]
127 in
128 List.iter
129 (fun (subnet, rt) ->
130 let os = V4.Prefix.of_string_exn subnet |> V4.Prefix.prefix in
131 let ts = V4.Prefix.to_string os in
132 assert_equal ~msg:subnet ts rt;
133 let os = Ipaddr_sexp.(V4.Prefix.(t_of_sexp (sexp_of_t os))) in
134 let ts = V4.Prefix.to_string os in
135 assert_equal ~msg:subnet ts rt)
136 subnets
123137
124138 let test_prefix_string_rt_bad () =
125 let subnets = [
126 bad_char 9 "192.168.0/24";
127 bad_char 10 "192.168.0./24";
128 error "192.168.0.0/33" "invalid prefix size";
129 bad_char 14 "192.168.0.0/30/1";
130 bad_char 12 "192.168.0.0/-1";
131 ] in
132 List.iter (fun (subnet,exn) ->
133 assert_raises ~msg:subnet exn (fun () -> V4.Prefix.of_string_exn subnet)
134 ) subnets
139 let subnets =
140 [
141 bad_char 9 "192.168.0/24";
142 bad_char 10 "192.168.0./24";
143 error "192.168.0.0/33" "invalid prefix size";
144 bad_char 14 "192.168.0.0/30/1";
145 bad_char 12 "192.168.0.0/-1";
146 ]
147 in
148 List.iter
149 (fun (subnet, exn) ->
150 assert_raises ~msg:subnet exn (fun () -> V4.Prefix.of_string_exn subnet))
151 subnets
135152
136153 let test_network_address_rt () =
137 let netaddrs = [
138 "192.168.0.1/24", "192.168.0.0/24", "192.168.0.1";
139 ] in
140 List.iter (fun (netaddr,net,addr) ->
141 let netv4 = V4.Prefix.of_string_exn net in
142 let addrv4 = V4.of_string_exn addr in
143 let cidr = V4.Prefix.of_string_exn netaddr in
144 let prefix = V4.Prefix.prefix cidr
145 and v4 = V4.Prefix.address cidr
146 in
147 assert_equal ~msg:(net^" <> "^(V4.Prefix.to_string prefix)) netv4 prefix;
148 assert_equal ~msg:(addr^" <> "^(V4.to_string v4)) addrv4 v4;
149 let addrstr = V4.Prefix.to_string cidr in
150 assert_equal ~msg:(netaddr^" <> "^addrstr) netaddr addrstr;
151 ) netaddrs
154 let netaddrs = [ ("192.168.0.1/24", "192.168.0.0/24", "192.168.0.1") ] in
155 List.iter
156 (fun (netaddr, net, addr) ->
157 let netv4 = V4.Prefix.of_string_exn net in
158 let addrv4 = V4.of_string_exn addr in
159 let cidr = V4.Prefix.of_string_exn netaddr in
160 let prefix = V4.Prefix.prefix cidr and v4 = V4.Prefix.address cidr in
161 assert_equal
162 ~msg:(net ^ " <> " ^ V4.Prefix.to_string prefix)
163 netv4 prefix;
164 assert_equal ~msg:(addr ^ " <> " ^ V4.to_string v4) addrv4 v4;
165 let addrstr = V4.Prefix.to_string cidr in
166 assert_equal ~msg:(netaddr ^ " <> " ^ addrstr) netaddr addrstr)
167 netaddrs
152168
153169 let test_prefix_broadcast () =
154 let pairs = [
155 "192.168.0.0/16", "192.168.255.255";
156 "192.168.0.0/24", "192.168.0.255";
157 "192.168.1.1/24", "192.168.1.255";
158 "192.168.0.128/29", "192.168.0.135";
159 "0.0.0.0/0", "255.255.255.255";
160 ] in
161 List.iter (fun (subnet,bcast) ->
162 let r = V4.(to_string (Prefix.(broadcast (of_string_exn subnet)))) in
163 assert_equal ~msg:(subnet ^ " <> " ^ r) r bcast
164 ) pairs
170 let pairs =
171 [
172 ("192.168.0.0/16", "192.168.255.255");
173 ("192.168.0.0/24", "192.168.0.255");
174 ("192.168.1.1/24", "192.168.1.255");
175 ("192.168.0.128/29", "192.168.0.135");
176 ("192.168.0.0/31", "192.168.0.1");
177 ("192.168.0.0/32", "192.168.0.0");
178 ("0.0.0.0/0", "255.255.255.255");
179 ]
180 in
181 List.iter
182 (fun (subnet, bcast) ->
183 let r = V4.(to_string Prefix.(broadcast (of_string_exn subnet))) in
184 assert_equal ~msg:(subnet ^ " <> " ^ r) r bcast)
185 pairs
165186
166187 let test_prefix_bits () =
167 let pairs = V4.Prefix.([
168 global, 0;
169 loopback, 8;
170 link, 16;
171 relative, 8;
172 multicast, 4;
173 private_10, 8;
174 private_172, 12;
175 private_192, 16;
176 ]) in
177 List.iter (fun (subnet,bits) ->
178 let msg = (V4.Prefix.to_string subnet) ^ " <> " ^ (string_of_int bits) in
179 assert_equal ~msg (V4.Prefix.bits subnet) bits
180 ) pairs
188 let pairs =
189 V4.Prefix.
190 [
191 (global, 0);
192 (loopback, 8);
193 (link, 16);
194 (relative, 8);
195 (multicast, 4);
196 (private_10, 8);
197 (private_172, 12);
198 (private_192, 16);
199 ]
200 in
201 List.iter
202 (fun (subnet, bits) ->
203 let msg = V4.Prefix.to_string subnet ^ " <> " ^ string_of_int bits in
204 assert_equal ~msg (V4.Prefix.bits subnet) bits)
205 pairs
181206
182207 let test_prefix_netmask () =
183 let nets = [
184 "192.168.0.1/32","255.255.255.255";
185 "192.168.0.1/31","255.255.255.254";
186 "192.168.0.1/1", "128.0.0.0";
187 "192.168.0.1/0", "0.0.0.0";
188 ] in
189 List.iter (fun (net_str,nm_str) ->
190 let cidr = V4.Prefix.of_string_exn net_str in
191 let prefix = V4.Prefix.prefix cidr
192 and address = V4.Prefix.address cidr
193 in
194 let netmask = V4.Prefix.netmask prefix in
195 let nnm_str = V4.to_string netmask in
196 let msg = Printf.sprintf "netmask %s <> %s" nnm_str nm_str in
197 assert_equal ~msg nnm_str nm_str;
198 let prefix = V4.Prefix.of_netmask_exn ~netmask ~address in
199 let nns = V4.Prefix.to_string prefix in
200 let msg = Printf.sprintf "%s is %s under netmask iso" net_str nns in
201 assert_equal ~msg net_str nns
202 ) nets
208 let nets =
209 [
210 ("192.168.0.1/32", "255.255.255.255");
211 ("192.168.0.1/31", "255.255.255.254");
212 ("192.168.0.1/1", "128.0.0.0");
213 ("192.168.0.1/0", "0.0.0.0");
214 ]
215 in
216 List.iter
217 (fun (net_str, nm_str) ->
218 let cidr = V4.Prefix.of_string_exn net_str in
219 let prefix = V4.Prefix.prefix cidr
220 and address = V4.Prefix.address cidr in
221 let netmask = V4.Prefix.netmask prefix in
222 let nnm_str = V4.to_string netmask in
223 let msg = Printf.sprintf "netmask %s <> %s" nnm_str nm_str in
224 assert_equal ~msg nnm_str nm_str;
225 let prefix = V4.Prefix.of_netmask_exn ~netmask ~address in
226 let nns = V4.Prefix.to_string prefix in
227 let msg = Printf.sprintf "%s is %s under netmask iso" net_str nns in
228 assert_equal ~msg net_str nns)
229 nets
203230
204231 let test_prefix_netmask_bad () =
205 let bad_masks = [
206 error "127.255.255.255" "invalid netmask";
207 error "255.255.254.128" "invalid netmask";
208 ] in
209 List.iter (fun (nm_str,exn) ->
210 let netmask = V4.of_string_exn nm_str in
211 let address = V4.of_string_exn "192.168.0.1" in
212 assert_raises ~msg:nm_str exn
213 (fun () -> V4.Prefix.of_netmask_exn ~netmask ~address)
214 ) bad_masks
232 let bad_masks =
233 [
234 error "127.255.255.255" "invalid netmask";
235 error "255.255.254.128" "invalid netmask";
236 ]
237 in
238 List.iter
239 (fun (nm_str, exn) ->
240 let netmask = V4.of_string_exn nm_str in
241 let address = V4.of_string_exn "192.168.0.1" in
242 assert_raises ~msg:nm_str exn (fun () ->
243 V4.Prefix.of_netmask_exn ~netmask ~address))
244 bad_masks
215245
216246 let test_scope () =
217247 let ip = V4.of_string_exn in
218248 (*let is subnet addr = V4.Prefix.(mem addr subnet) in*)
219249 let is_scope scop addr = scop = V4.scope addr in
220 let ships = V4.([
221 unspecified, "global", is_global, false;
222 unspecified, "multicast", is_multicast, false;
223 unspecified, "point", is_scope Point, true;
224 localhost, "global", is_global, false;
225 localhost, "multicast", is_multicast, false;
226 localhost, "interface", is_scope Interface, true;
227 broadcast, "global", is_global, false;
228 broadcast, "multicast", is_multicast, false;
229 broadcast, "admin", is_scope Admin, true;
230 nodes, "global", is_global, false;
231 nodes, "multicast", is_multicast, true;
232 nodes, "interface", is_scope Link, true;
233 routers, "global", is_global, false;
234 routers, "multicast", is_multicast, true;
235 routers, "link", is_scope Link, true;
236 ip "192.168.0.1", "private", is_private, true;
237 ip "10.3.21.155", "private", is_private, true;
238 ip "172.16.0.0", "private", is_private, true;
239 ip "172.31.255.255", "private", is_private, true;
240 ip "172.15.255.255", "private", is_private, false;
241 ip "172.32.0.0", "private", is_private, false;
242 ]) in
243 List.iter (fun (addr,lbl,pred,is_mem) ->
244 let mems = if is_mem then "" else " not" in
245 let msg = (V4.to_string addr)^" is"^mems^" in "^lbl in
246 assert_equal ~msg (pred addr) is_mem
247 ) ships
250 let ships =
251 V4.
252 [
253 (unspecified, "global", is_global, false);
254 (unspecified, "multicast", is_multicast, false);
255 (unspecified, "point", is_scope Point, true);
256 (localhost, "global", is_global, false);
257 (localhost, "multicast", is_multicast, false);
258 (localhost, "interface", is_scope Interface, true);
259 (broadcast, "global", is_global, false);
260 (broadcast, "multicast", is_multicast, false);
261 (broadcast, "admin", is_scope Admin, true);
262 (nodes, "global", is_global, false);
263 (nodes, "multicast", is_multicast, true);
264 (nodes, "interface", is_scope Link, true);
265 (routers, "global", is_global, false);
266 (routers, "multicast", is_multicast, true);
267 (routers, "link", is_scope Link, true);
268 (ip "192.168.0.1", "private", is_private, true);
269 (ip "10.3.21.155", "private", is_private, true);
270 (ip "172.16.0.0", "private", is_private, true);
271 (ip "172.31.255.255", "private", is_private, true);
272 (ip "172.15.255.255", "private", is_private, false);
273 (ip "172.32.0.0", "private", is_private, false);
274 ]
275 in
276 List.iter
277 (fun (addr, lbl, pred, is_mem) ->
278 let mems = if is_mem then "" else " not" in
279 let msg = V4.to_string addr ^ " is" ^ mems ^ " in " ^ lbl in
280 assert_equal ~msg (pred addr) is_mem)
281 ships
248282
249283 let test_map () =
250 let module M = Map.Make(V4) in
284 let module M = Map.Make (V4) in
251285 let m = M.add (V4.of_string_exn "1.0.0.1") "min" M.empty in
252286 let m = M.add (V4.of_string_exn "254.254.254.254") "the greatest host" m in
253287 let m = M.add (V4.of_string_exn "1.0.0.1") "the least host" m in
254288 assert_equal ~msg:"size" (M.cardinal m) 2;
255 let (min_key, min_val) = M.min_binding m in
256 assert_equal ~msg:("min is '" ^ min_val ^"'") (min_key, min_val)
289 let min_key, min_val = M.min_binding m in
290 assert_equal
291 ~msg:("min is '" ^ min_val ^ "'")
292 (min_key, min_val)
257293 (V4.of_string_exn "1.0.0.1", "the least host");
258294 assert_equal ~msg:"max" (M.max_binding m)
259295 (V4.of_string_exn "254.254.254.254", "the greatest host")
260296
261297 let test_prefix_map () =
262 let module M = Map.Make(V4.Prefix) in
298 let module M = Map.Make (V4.Prefix) in
263299 let of_string s = s |> V4.Prefix.of_string_exn |> V4.Prefix.prefix in
264300 let m = M.add (of_string "0.0.0.0/0") "everyone" M.empty in
265301 let m = M.add (of_string "192.0.0.0/1") "weirdos" m in
272308 assert_equal ~msg:"max" (M.max_binding m)
273309 (V4.Prefix.of_string_exn "254.0.0.0/8", "top-end");
274310 assert_equal ~msg:"third"
275 (M.find (V4.Prefix.of_string_exn "128.0.0.0/1") m) "high-bitters"
311 (M.find (V4.Prefix.of_string_exn "128.0.0.0/1") m)
312 "high-bitters"
276313
277314 let test_special_addr () =
278315 assert_equal ~msg:"broadcast" V4.broadcast V4.Prefix.(broadcast global);
279 assert_equal ~msg:"any" V4.any V4.Prefix.(network global);
316 assert_equal ~msg:"any" V4.any V4.Prefix.(network global);
280317 assert_equal ~msg:"localhost" true V4.(Prefix.(mem localhost loopback))
281318
282319 let test_multicast_mac () =
283320 let ip = V4.of_octets_exn "\xff\xbf\x9f\x8f" in
284321 let multicast = V4.Prefix.(network_address multicast ip) in
285 let unicast_mac_str = Macaddr.to_string (V4.multicast_to_mac ip) in
322 let unicast_mac_str = Macaddr.to_string (V4.multicast_to_mac ip) in
286323 let multicast_mac_str = Macaddr.to_string (V4.multicast_to_mac multicast) in
287324 let mac_str = "01:00:5e:3f:9f:8f" in
288 assert_equal ~msg:("unicast_mac "^unicast_mac_str^" <> "^mac_str)
289 unicast_mac_str mac_str;
290 assert_equal ~msg:("multicast_mac "^multicast_mac_str^" <> "^mac_str)
325 assert_equal
326 ~msg:("unicast_mac " ^ unicast_mac_str ^ " <> " ^ mac_str)
327 unicast_mac_str mac_str;
328 assert_equal
329 ~msg:("multicast_mac " ^ multicast_mac_str ^ " <> " ^ mac_str)
291330 multicast_mac_str mac_str
292331
293332 let test_domain_name () =
296335 Domain_name.(host_exn (of_string_exn "16.32.64.128.in-addr.arpa"))
297336 in
298337 assert_equal ~cmp:Domain_name.equal ~msg:"to_domain_name"
299 (V4.to_domain_name ip) name ;
338 (V4.to_domain_name ip) name;
300339 assert_equal ~msg:"of_domain_name" (V4.of_domain_name name) (Some ip)
301340
302341 let test_cstruct_rt () =
303342 let addr = "\254\099\003\128" in
304343 assert_equal ~msg:(String.escaped addr)
305 (Cstruct.to_string Ipaddr_cstruct.V4.(to_cstruct (of_cstruct_exn (Cstruct.of_string addr)))) addr
344 (Cstruct.to_string
345 Ipaddr_cstruct.V4.(
346 to_cstruct (of_cstruct_exn (Cstruct.of_string addr))))
347 addr
306348
307349 let test_cstruct_rt_bad () =
308 let addrs = [
309 need_more "\254\099\003";
310 ] in
311 List.iter (fun (addr,exn) ->
312 assert_raises ~msg:(String.escaped addr) exn
313 (fun () -> Ipaddr_cstruct.V4.of_cstruct_exn (Cstruct.of_string addr))
314 ) addrs
350 let addrs = [ need_more "\254\099\003" ] in
351 List.iter
352 (fun (addr, exn) ->
353 assert_raises ~msg:(String.escaped addr) exn (fun () ->
354 Ipaddr_cstruct.V4.of_cstruct_exn (Cstruct.of_string addr)))
355 addrs
315356
316357 let test_prefix_mem () =
317358 let ip = V4.of_string_exn in
318359 let prefix = V4.Prefix.of_string_exn in
319 let ships = [
320 ip "10.0.0.7", prefix "10.0.0.0/29", true;
321 ip "172.16.255.254", prefix "172.16.255.254/31", true;
322 ip "192.168.0.1", prefix "0.0.0.0/0", true;
323 ip "192.168.0.1", V4.Prefix.private_192, true;
324 ip "255.255.255.255", prefix "255.255.255.255/32", true;
325 ip "192.0.2.1", prefix "192.0.2.0/32", false;
326 ip "192.0.2.1", prefix "192.0.0.0/23", false;
327 ip "255.255.255.255", prefix "0.0.0.0/1", false;
328 ] in
329 List.iter (fun (addr,subnet,is_mem) ->
330 let msg = Printf.sprintf "%s is%s in %s"
331 (V4.to_string addr) (if is_mem then "" else " not") (V4.Prefix.to_string subnet)
332 in
333 assert_equal ~msg (V4.Prefix.mem addr subnet) is_mem
334 ) ships
360 let ships =
361 [
362 (ip "10.0.0.7", prefix "10.0.0.0/29", true);
363 (ip "172.16.255.254", prefix "172.16.255.254/31", true);
364 (ip "192.168.0.1", prefix "0.0.0.0/0", true);
365 (ip "192.168.0.1", V4.Prefix.private_192, true);
366 (ip "255.255.255.255", prefix "255.255.255.255/32", true);
367 (ip "192.0.2.1", prefix "192.0.2.0/32", false);
368 (ip "192.0.2.1", prefix "192.0.0.0/23", false);
369 (ip "255.255.255.255", prefix "0.0.0.0/1", false);
370 ]
371 in
372 List.iter
373 (fun (addr, subnet, is_mem) ->
374 let msg =
375 Printf.sprintf "%s is%s in %s" (V4.to_string addr)
376 (if is_mem then "" else " not")
377 (V4.Prefix.to_string subnet)
378 in
379 assert_equal ~msg (V4.Prefix.mem addr subnet) is_mem)
380 ships
335381
336382 let test_succ_pred () =
337383 let open V4 in
342388 let assert_equal = assert_equal ~printer in
343389 let ip1 = of_string_exn "0.0.0.0" in
344390 let ip2 = of_string_exn "255.255.255.255" in
345 assert_equal ~msg:"succ 0.0.0.0"
346 (of_string "0.0.0.1") (succ ip1);
391 assert_equal ~msg:"succ 0.0.0.0" (of_string "0.0.0.1") (succ ip1);
347392 assert_equal ~msg:"succ 255.255.255.255"
348 (Error (`Msg "Ipaddr: highest address has been reached")) (succ ip2);
393 (Error (`Msg "Ipaddr: highest address has been reached"))
394 (succ ip2);
349395 assert_equal ~msg:"succ (succ 255.255.255.255)"
350396 (Error (`Msg "Ipaddr: highest address has been reached"))
351397 (succ ip2 >>= succ);
352398 assert_equal ~msg:"pred 0.0.0.0"
353 (Error (`Msg "Ipaddr: lowest address has been reached")) (pred ip1);
399 (Error (`Msg "Ipaddr: lowest address has been reached"))
400 (pred ip1);
354401 ()
355402
356403 let test_prefix_first_last () =
375422 (Ipaddr.V4.of_string_exn "169.254.169.254")
376423 (last (of_string_exn "169.254.169.254/32"))
377424
378 let suite = "Test V4" >::: [
379 "string_rt" >:: test_string_rt;
380 "string_rt_bad" >:: test_string_rt_bad;
381 "string_raw_rt" >:: test_string_raw_rt;
382 "string_raw_rt_bad" >:: test_string_raw_rt_bad;
383 "bytes_rt" >:: test_bytes_rt;
384 "bytes_rt_bad" >:: test_bytes_rt_bad;
385 "cstruct_rt" >:: test_cstruct_rt;
386 "cstruct_rt_bad" >:: test_cstruct_rt_bad;
387 "int32_rt" >:: test_int32_rt;
388 "prefix_string_rt" >:: test_prefix_string_rt;
389 "prefix_string_rt_bad" >:: test_prefix_string_rt_bad;
390 "network_address_rt" >:: test_network_address_rt;
391 "prefix_broadcast" >:: test_prefix_broadcast;
392 "prefix_bits" >:: test_prefix_bits;
393 "prefix_netmask" >:: test_prefix_netmask;
394 "prefix_netmask_bad" >:: test_prefix_netmask_bad;
395 "scope" >:: test_scope;
396 "map" >:: test_map;
397 "prefix_map" >:: test_prefix_map;
398 "special_addr" >:: test_special_addr;
399 "multicast_mac" >:: test_multicast_mac;
400 "domain_name" >:: test_domain_name;
401 "prefix_mem" >:: test_prefix_mem;
402 "succ_pred" >:: test_succ_pred;
403 "prefix_first_last" >:: test_prefix_first_last;
404 ]
425 let suite =
426 "Test V4"
427 >::: [
428 "string_rt" >:: test_string_rt;
429 "string_rt_bad" >:: test_string_rt_bad;
430 "string_raw_rt" >:: test_string_raw_rt;
431 "string_raw_rt_bad" >:: test_string_raw_rt_bad;
432 "bytes_rt" >:: test_bytes_rt;
433 "bytes_rt_bad" >:: test_bytes_rt_bad;
434 "cstruct_rt" >:: test_cstruct_rt;
435 "cstruct_rt_bad" >:: test_cstruct_rt_bad;
436 "int32_rt" >:: test_int32_rt;
437 "prefix_string_rt" >:: test_prefix_string_rt;
438 "prefix_string_rt_bad" >:: test_prefix_string_rt_bad;
439 "network_address_rt" >:: test_network_address_rt;
440 "prefix_broadcast" >:: test_prefix_broadcast;
441 "prefix_bits" >:: test_prefix_bits;
442 "prefix_netmask" >:: test_prefix_netmask;
443 "prefix_netmask_bad" >:: test_prefix_netmask_bad;
444 "scope" >:: test_scope;
445 "map" >:: test_map;
446 "prefix_map" >:: test_prefix_map;
447 "special_addr" >:: test_special_addr;
448 "multicast_mac" >:: test_multicast_mac;
449 "domain_name" >:: test_domain_name;
450 "prefix_mem" >:: test_prefix_mem;
451 "succ_pred" >:: test_succ_pred;
452 "prefix_first_last" >:: test_prefix_first_last;
453 ]
405454 end
406
407455
408456 module Test_v6 = struct
409457 let test_string_rt () =
410 let addrs = [
411 "2001:db8::ff00:42:8329","2001:db8::ff00:42:8329";
412 "::ffff:192.168.1.1", "::ffff:192.168.1.1";
413 "::", "::";
414 "[::]", "::";
415 "1:1:1:1::1:1:1", "1:1:1:1:0:1:1:1";
416 "0:0:0:1:1:0:0:0", "::1:1:0:0:0";
417 "0:0:0:1:1::", "::1:1:0:0:0";
418 "::1:0:0:0:0", "0:0:0:1::";
419 "FE80::", "fe80::";
420 "::192.168.0.1", "::c0a8:1";
421 ] in
422 List.iter (fun (addr,rt) ->
423 let os = V6.of_string_exn addr in
424 let ts = V6.to_string os in
425 assert_equal ~msg:(addr^" <> "^rt^" ("^ts^")") ts rt;
426 let os = Ipaddr_sexp.(V6.t_of_sexp (V6.sexp_of_t os)) in
427 let ts = V6.to_string os in
428 assert_equal ~msg:(addr^" <> "^rt^" ("^ts^")") ts rt;
429 ) addrs
458 let addrs =
459 [
460 ("2001:db8::ff00:42:8329", "2001:db8::ff00:42:8329");
461 ("::ffff:192.168.1.1", "::ffff:192.168.1.1");
462 ("::", "::");
463 ("[::]", "::");
464 ("1:1:1:1::1:1:1", "1:1:1:1:0:1:1:1");
465 ("0:0:0:1:1:0:0:0", "::1:1:0:0:0");
466 ("0:0:0:1:1::", "::1:1:0:0:0");
467 ("::1:0:0:0:0", "0:0:0:1::");
468 ("FE80::", "fe80::");
469 ("::192.168.0.1", "::c0a8:1");
470 ]
471 in
472 List.iter
473 (fun (addr, rt) ->
474 let os = V6.of_string_exn addr in
475 let ts = V6.to_string os in
476 assert_equal ~msg:(addr ^ " <> " ^ rt ^ " (" ^ ts ^ ")") ts rt;
477 let os = Ipaddr_sexp.(V6.t_of_sexp (V6.sexp_of_t os)) in
478 let ts = V6.to_string os in
479 assert_equal ~msg:(addr ^ " <> " ^ rt ^ " (" ^ ts ^ ")") ts rt)
480 addrs
430481
431482 let test_string_rt_bad () =
432 let addrs = [
433 need_more "[";
434 need_more "[:";
435 need_more "[]"; (* ? *)
436 need_more ":";
437 need_more "[::";
438 bad_char 4 "::1:g:f";
439 bad_char 3 "::1::";
440 bad_char 4 "1::2::3";
441 need_more "1:2:3:4:5:6:7";
442 bad_char 15 "1:2:3:4:5:6:7:8:9";
443 bad_char 15 "1:2:3:4:5:6:7:8::";
444 error "12345::12:2" "component 0 out of bounds";
445 bad_char 1 ":1";
446 ] in
447 List.iter (fun (addr,exn) ->
448 assert_raises ~msg:addr exn (fun () -> V6.of_string_exn addr)
449 ) addrs
483 let addrs =
484 [
485 need_more "[";
486 need_more "[:";
487 need_more "[]";
488 (* ? *)
489 need_more ":";
490 need_more "[::";
491 bad_char 4 "::1:g:f";
492 bad_char 3 "::1::";
493 bad_char 4 "1::2::3";
494 need_more "1:2:3:4:5:6:7";
495 bad_char 15 "1:2:3:4:5:6:7:8:9";
496 bad_char 15 "1:2:3:4:5:6:7:8::";
497 error "12345::12:2" "component 0 out of bounds";
498 bad_char 1 ":1";
499 ]
500 in
501 List.iter
502 (fun (addr, exn) ->
503 assert_raises ~msg:addr exn (fun () -> V6.of_string_exn addr))
504 addrs
450505
451506 let test_string_raw_rt () =
452 let addrs = [
453 ("IP: 2001:db8::ff00:42:8329!",4), ("2001:db8::ff00:42:8329",26);
454 ("IP: ::ffff:192.168.1.1 ",4), ("::ffff:192.168.1.1",22);
455 ("IP: :::",4), ("::",6);
456 ("IP: [::]:",4), ("::",8);
457 ("IP: 1:1:1:1::1:1:1:1",4), ("1:1:1:1:0:1:1:1",18);
458 ("IP: ::1:1:0:0:0::g",4), ("::1:1:0:0:0",15);
459 ] in
460 List.iter (fun ((addr,off),(result,cursor)) ->
461 let c = ref off in
462 let os = V6.of_string_raw addr c in
463 let ts = V6.to_string os in
464 let msg = Printf.sprintf "%s at %d: %s at %d <> %s at %d"
465 addr off result cursor ts !c
466 in assert_equal ~msg (ts,!c) (result,cursor)
467 ) addrs
507 let addrs =
508 [
509 (("IP: 2001:db8::ff00:42:8329!", 4), ("2001:db8::ff00:42:8329", 26));
510 (("IP: ::ffff:192.168.1.1 ", 4), ("::ffff:192.168.1.1", 22));
511 (("IP: :::", 4), ("::", 6));
512 (("IP: [::]:", 4), ("::", 8));
513 (("IP: 1:1:1:1::1:1:1:1", 4), ("1:1:1:1:0:1:1:1", 18));
514 (("IP: ::1:1:0:0:0::g", 4), ("::1:1:0:0:0", 15));
515 ]
516 in
517 List.iter
518 (fun ((addr, off), (result, cursor)) ->
519 let c = ref off in
520 let os = V6.of_string_raw addr c in
521 let ts = V6.to_string os in
522 let msg =
523 Printf.sprintf "%s at %d: %s at %d <> %s at %d" addr off result cursor
524 ts !c
525 in
526 assert_equal ~msg (ts, !c) (result, cursor))
527 addrs
468528
469529 let test_string_raw_rt_bad () =
470 let error (s,c) msg c' = (s,c), (Parse_error (msg,s),c') in
530 let error (s, c) msg c' = ((s, c), (Parse_error (msg, s), c')) in
471531 let need_more loc = error loc "not enough data" in
472 let bad_char i (s,c) =
473 error (s,c) (Printf.sprintf "invalid character '%c' at %d" s.[i] i) i
474 in
475 let addrs = [
476 need_more ("IP: [] ",4) 5;
477 bad_char 5 ("IP: : ",4);
478 bad_char 7 ("IP: [:: ",4);
479 bad_char 17 ("IP: 1:2:3:4:5:6:7 ",4);
480 error ("IP: 12345::12:2 ",4) "component 0 out of bounds" 15;
481 bad_char 5 ("IP: :1 ",4);
482 need_more ("IP: ::1:1:0:0:0:",4) 16;
483 bad_char 8 ("IP: ::1:g:f ",4);
484 ] in
485 List.iter (fun ((addr,off),(exn,cursor)) ->
486 let c = ref off in
487 assert_raises ~msg:addr exn (fun () -> V6.of_string_raw addr c);
488 assert_equal ~msg:(Printf.sprintf "%s cursor <> %d (%d)" addr cursor !c)
489 !c cursor
490 ) addrs
532 let bad_char i (s, c) =
533 error (s, c) (Printf.sprintf "invalid character '%c' at %d" s.[i] i) i
534 in
535 let addrs =
536 [
537 need_more ("IP: [] ", 4) 5;
538 bad_char 5 ("IP: : ", 4);
539 bad_char 7 ("IP: [:: ", 4);
540 bad_char 17 ("IP: 1:2:3:4:5:6:7 ", 4);
541 error ("IP: 12345::12:2 ", 4) "component 0 out of bounds" 15;
542 bad_char 5 ("IP: :1 ", 4);
543 need_more ("IP: ::1:1:0:0:0:", 4) 16;
544 bad_char 8 ("IP: ::1:g:f ", 4);
545 ]
546 in
547 List.iter
548 (fun ((addr, off), (exn, cursor)) ->
549 let c = ref off in
550 assert_raises ~msg:addr exn (fun () -> V6.of_string_raw addr c);
551 assert_equal
552 ~msg:(Printf.sprintf "%s cursor <> %d (%d)" addr cursor !c)
553 !c cursor)
554 addrs
491555
492556 let test_bytes_rt () =
493557 let addr =
497561 assert_equal ~msg:(String.escaped addr) V6.(to_octets v6) addr
498562
499563 let test_bytes_rt_bad () =
500 let addrs = [
501 need_more "\000\000\000\000\000\000\000\000\000\000\255\255\192\168\001";
502 ] in
503 List.iter (fun (addr,exn) ->
504 assert_raises ~msg:(String.escaped addr) exn
505 (fun () -> V6.of_octets_exn addr)
506 ) addrs
564 let addrs =
565 [
566 need_more "\000\000\000\000\000\000\000\000\000\000\255\255\192\168\001";
567 ]
568 in
569 List.iter
570 (fun (addr, exn) ->
571 assert_raises ~msg:(String.escaped addr) exn (fun () ->
572 V6.of_octets_exn addr))
573 addrs
507574
508575 let test_cstruct_rt () =
509576 let addr =
510577 "\000\000\000\000\000\000\000\000\000\000\255\255\192\168\000\001"
511578 in
512579 let v6 = Ipaddr_cstruct.V6.of_cstruct_exn (Cstruct.of_string addr) in
513 assert_equal ~msg:(String.escaped addr) (Cstruct.to_string Ipaddr_cstruct.V6.(to_cstruct v6)) addr
580 assert_equal ~msg:(String.escaped addr)
581 (Cstruct.to_string Ipaddr_cstruct.V6.(to_cstruct v6))
582 addr
514583
515584 let test_cstruct_rt_bad () =
516 let addrs = [
517 need_more "\000\000\000\000\000\000\000\000\000\000\255\255\192\168\001";
518 ] in
519 List.iter (fun (addr,exn) ->
520 assert_raises ~msg:(String.escaped addr) exn
521 (fun () -> Ipaddr_cstruct.V6.of_cstruct_exn (Cstruct.of_string addr))
522 ) addrs
585 let addrs =
586 [
587 need_more "\000\000\000\000\000\000\000\000\000\000\255\255\192\168\001";
588 ]
589 in
590 List.iter
591 (fun (addr, exn) ->
592 assert_raises ~msg:(String.escaped addr) exn (fun () ->
593 Ipaddr_cstruct.V6.of_cstruct_exn (Cstruct.of_string addr)))
594 addrs
523595
524596 let test_int32_rt () =
525 let (a,b,c,d) as addr =
526 0x2001_0665_l, 0x0000_0000_l, 0xff00_00ff_l, 0xfe00_0001_l
527 in
528 assert_equal ~msg:(Printf.sprintf "%08lx %08lx %08lx %08lx" a b c d)
529 V6.(to_int32 (of_int32 addr)) addr
597 let ((a, b, c, d) as addr) =
598 (0x2001_0665_l, 0x0000_0000_l, 0xff00_00ff_l, 0xfe00_0001_l)
599 in
600 assert_equal
601 ~msg:(Printf.sprintf "%08lx %08lx %08lx %08lx" a b c d)
602 V6.(to_int32 (of_int32 addr))
603 addr
530604
531605 let test_prefix_string_rt () =
532 let subnets = [
533 "2000::/3", "2000::/3";
534 "c012::/2", "c000::/2";
535 "ffff:ffff:ffff::ffff/0", "::/0";
536 "::/0", "::/0";
537 "::/128", "::/128";
538 "::1/128", "::1/128";
539 "::/64", "::/64";
540 "[::]/64", "::/64";
541 ] in
542 List.iter (fun (subnet,rt) ->
543 let os = V6.Prefix.of_string_exn subnet |> V6.Prefix.prefix in
544 let ts = V6.Prefix.to_string os in
545 assert_equal ~msg:subnet ts rt;
546 let os = Ipaddr_sexp.(V6.Prefix.(t_of_sexp (sexp_of_t os))) in
547 let ts = V6.Prefix.to_string os in
548 assert_equal ~msg:subnet ts rt;
549 ) subnets
606 let subnets =
607 [
608 ("2000::/3", "2000::/3");
609 ("c012::/2", "c000::/2");
610 ("ffff:ffff:ffff::ffff/0", "::/0");
611 ("::/0", "::/0");
612 ("::/128", "::/128");
613 ("::1/128", "::1/128");
614 ("::/64", "::/64");
615 ("[::]/64", "::/64");
616 ]
617 in
618 List.iter
619 (fun (subnet, rt) ->
620 let os = V6.Prefix.of_string_exn subnet |> V6.Prefix.prefix in
621 let ts = V6.Prefix.to_string os in
622 assert_equal ~msg:subnet ts rt;
623 let os = Ipaddr_sexp.(V6.Prefix.(t_of_sexp (sexp_of_t os))) in
624 let ts = V6.Prefix.to_string os in
625 assert_equal ~msg:subnet ts rt)
626 subnets
550627
551628 let test_prefix_string_rt_bad () =
552 let subnets = [
553 need_more "/24";
554 need_more "::";
555 error "::/130" "invalid prefix size";
556 bad_char 5 "::/30/1";
557 bad_char 7 "2000::/-1";
558 bad_char 5 "1::3:/4";
559 ] in
560 List.iter (fun (subnet,exn) ->
561 assert_raises ~msg:subnet exn (fun () -> V6.Prefix.of_string_exn subnet)
562 ) subnets
629 let subnets =
630 [
631 need_more "/24";
632 need_more "::";
633 error "::/130" "invalid prefix size";
634 bad_char 5 "::/30/1";
635 bad_char 7 "2000::/-1";
636 bad_char 5 "1::3:/4";
637 ]
638 in
639 List.iter
640 (fun (subnet, exn) ->
641 assert_raises ~msg:subnet exn (fun () -> V6.Prefix.of_string_exn subnet))
642 subnets
563643
564644 let test_network_address_rt () =
565 let netaddrs = [
566 "::1/24", "::/24", "::1";
567 ] in
568 List.iter (fun (netaddr,net,addr) ->
569 let netv4 = V6.Prefix.of_string_exn net in
570 let addrv4 = V6.of_string_exn addr in
571 let cidr = V6.Prefix.of_string_exn netaddr in
572 let prefix = V6.Prefix.prefix cidr
573 and v4 = V6.Prefix.address cidr
574 in
575 let prefix = V6.Prefix.prefix prefix in
576 assert_equal ~msg:(net^" <> "^(V6.Prefix.to_string prefix)) netv4 prefix;
577 assert_equal ~msg:(addr^" <> "^(V6.to_string v4)) addrv4 v4;
578 let addrstr = V6.Prefix.to_string cidr in
579 assert_equal ~msg:(netaddr^" <> "^addrstr) netaddr addrstr;
580 ) netaddrs
645 let netaddrs = [ ("::1/24", "::/24", "::1") ] in
646 List.iter
647 (fun (netaddr, net, addr) ->
648 let netv4 = V6.Prefix.of_string_exn net in
649 let addrv4 = V6.of_string_exn addr in
650 let cidr = V6.Prefix.of_string_exn netaddr in
651 let prefix = V6.Prefix.prefix cidr and v4 = V6.Prefix.address cidr in
652 let prefix = V6.Prefix.prefix prefix in
653 assert_equal
654 ~msg:(net ^ " <> " ^ V6.Prefix.to_string prefix)
655 netv4 prefix;
656 assert_equal ~msg:(addr ^ " <> " ^ V6.to_string v4) addrv4 v4;
657 let addrstr = V6.Prefix.to_string cidr in
658 assert_equal ~msg:(netaddr ^ " <> " ^ addrstr) netaddr addrstr)
659 netaddrs
581660
582661 let test_prefix_bits () =
583 let pairs = V6.Prefix.([
584 global_unicast_001, 3;
585 link, 64;
586 unique_local, 7;
587 multicast, 8;
588 ipv4_mapped, 96;
589 noneui64_interface, 3;
590 ]) in
591 List.iter (fun (subnet,bits) ->
592 let msg = (V6.Prefix.to_string subnet) ^ " <> bits "
593 ^ (string_of_int bits) in
594 assert_equal ~msg (V6.Prefix.bits subnet) bits
595 ) pairs
662 let pairs =
663 V6.Prefix.
664 [
665 (global_unicast_001, 3);
666 (link, 64);
667 (unique_local, 7);
668 (multicast, 8);
669 (ipv4_mapped, 96);
670 (noneui64_interface, 3);
671 ]
672 in
673 List.iter
674 (fun (subnet, bits) ->
675 let msg =
676 V6.Prefix.to_string subnet ^ " <> bits " ^ string_of_int bits
677 in
678 assert_equal ~msg (V6.Prefix.bits subnet) bits)
679 pairs
596680
597681 let test_prefix_netmask () =
598 let nets = [
599 "8::1/128","ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";
600 "8::1/127","ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe";
601 "8::1/96", "ffff:ffff:ffff:ffff:ffff:ffff::";
602 "8::1/64", "ffff:ffff:ffff:ffff::";
603 "8::1/32", "ffff:ffff::";
604 "8::1/1", "8000::";
605 "8::1/0", "::";
606 ] in
607 List.iter (fun (net_str,nm_str) ->
608 let cidr = V6.Prefix.of_string_exn net_str in
609 let prefix = V6.Prefix.prefix cidr
610 and address = V6.Prefix.address cidr
611 in
612 let netmask = V6.Prefix.netmask prefix in
613 let nnm_str = V6.to_string netmask in
614 let msg = Printf.sprintf "netmask %s <> %s" nnm_str nm_str in
615 assert_equal ~msg nnm_str nm_str;
616 let prefix = V6.Prefix.of_netmask_exn ~netmask ~address in
617 let nns = V6.Prefix.to_string prefix in
618 let msg = Printf.sprintf "%s is %s under netmask iso" net_str nns in
619 assert_equal ~msg net_str nns
620 ) nets
682 let nets =
683 [
684 ("8::1/128", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
685 ("8::1/127", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe");
686 ("8::1/96", "ffff:ffff:ffff:ffff:ffff:ffff::");
687 ("8::1/64", "ffff:ffff:ffff:ffff::");
688 ("8::1/32", "ffff:ffff::");
689 ("8::1/1", "8000::");
690 ("8::1/0", "::");
691 ]
692 in
693 List.iter
694 (fun (net_str, nm_str) ->
695 let cidr = V6.Prefix.of_string_exn net_str in
696 let prefix = V6.Prefix.prefix cidr
697 and address = V6.Prefix.address cidr in
698 let netmask = V6.Prefix.netmask prefix in
699 let nnm_str = V6.to_string netmask in
700 let msg = Printf.sprintf "netmask %s <> %s" nnm_str nm_str in
701 assert_equal ~msg nnm_str nm_str;
702 let prefix = V6.Prefix.of_netmask_exn ~netmask ~address in
703 let nns = V6.Prefix.to_string prefix in
704 let msg = Printf.sprintf "%s is %s under netmask iso" net_str nns in
705 assert_equal ~msg net_str nns)
706 nets
621707
622708 let test_prefix_netmask_bad () =
623 let bad_masks = [
624 error "7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" "invalid netmask";
625 error "ffff:ffff:ffff:ffff:ffff:fffe:8000:0" "invalid netmask";
626 error "ffff:ffff:ffff:fffe:8000::" "invalid netmask";
627 error "ffff:fffe:8000::" "invalid netmask";
628 ] in
629 List.iter (fun (nm_str,exn) ->
630 let netmask = V6.of_string_exn nm_str in
631 let address = V6.of_string_exn "::" in
632 assert_raises ~msg:nm_str exn
633 (fun () -> V6.Prefix.of_netmask_exn ~netmask ~address)
634 ) bad_masks
709 let bad_masks =
710 [
711 error "7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" "invalid netmask";
712 error "ffff:ffff:ffff:ffff:ffff:fffe:8000:0" "invalid netmask";
713 error "ffff:ffff:ffff:fffe:8000::" "invalid netmask";
714 error "ffff:fffe:8000::" "invalid netmask";
715 ]
716 in
717 List.iter
718 (fun (nm_str, exn) ->
719 let netmask = V6.of_string_exn nm_str in
720 let address = V6.of_string_exn "::" in
721 assert_raises ~msg:nm_str exn (fun () ->
722 V6.Prefix.of_netmask_exn ~netmask ~address))
723 bad_masks
635724
636725 let test_scope () =
637726 let localhost_v4 = V6.of_string_exn "::ffff:127.0.0.1" in
638727 let is subnet addr = V6.Prefix.(mem addr subnet) in
639728 let is_scope scop addr = scop = V6.scope addr in
640 let ships = V6.([
641 unspecified, "global", is_global, false;
642 unspecified, "multicast", is_multicast, false;
643 unspecified, "point", is_scope Point, true;
644 localhost, "global", is_global, false;
645 localhost, "multicast", is_multicast, false;
646 localhost, "interface", is_scope Interface, true;
647 interface_nodes, "global", is_global, false;
648 interface_nodes, "multicast", is_multicast, true;
649 interface_nodes, "interface", is_scope Interface, true;
650 link_nodes, "global", is_global, false;
651 link_nodes, "multicast", is_multicast, true;
652 link_nodes, "link", is_scope Link, true;
653 link_routers, "global", is_global, false;
654 link_routers, "multicast", is_multicast, true;
655 link_routers, "link", is_scope Link, true;
656 localhost_v4, "global", is_global, false;
657 localhost_v4, "multicast", is_multicast, false;
658 localhost_v4, "ipv4", is Prefix.ipv4_mapped, true;
659 localhost_v4, "noneui64", is Prefix.noneui64_interface, true;
660 localhost_v4, "global_001",is Prefix.global_unicast_001, false;
661 localhost_v4, "interface", is_scope Interface, true;
662 ]) in
663 List.iter (fun (addr,lbl,pred,is_mem) ->
664 let mems = if is_mem then "" else " not" in
665 let msg = (V6.to_string addr)^" is"^mems^" in "^lbl in
666 assert_equal ~msg (pred addr) is_mem
667 ) ships
729 let ships =
730 V6.
731 [
732 (unspecified, "global", is_global, false);
733 (unspecified, "multicast", is_multicast, false);
734 (unspecified, "point", is_scope Point, true);
735 (localhost, "global", is_global, false);
736 (localhost, "multicast", is_multicast, false);
737 (localhost, "interface", is_scope Interface, true);
738 (interface_nodes, "global", is_global, false);
739 (interface_nodes, "multicast", is_multicast, true);
740 (interface_nodes, "interface", is_scope Interface, true);
741 (link_nodes, "global", is_global, false);
742 (link_nodes, "multicast", is_multicast, true);
743 (link_nodes, "link", is_scope Link, true);
744 (link_routers, "global", is_global, false);
745 (link_routers, "multicast", is_multicast, true);
746 (link_routers, "link", is_scope Link, true);
747 (localhost_v4, "global", is_global, false);
748 (localhost_v4, "multicast", is_multicast, false);
749 (localhost_v4, "ipv4", is Prefix.ipv4_mapped, true);
750 (localhost_v4, "noneui64", is Prefix.noneui64_interface, true);
751 (localhost_v4, "global_001", is Prefix.global_unicast_001, false);
752 (localhost_v4, "interface", is_scope Interface, true);
753 ]
754 in
755 List.iter
756 (fun (addr, lbl, pred, is_mem) ->
757 let mems = if is_mem then "" else " not" in
758 let msg = V6.to_string addr ^ " is" ^ mems ^ " in " ^ lbl in
759 assert_equal ~msg (pred addr) is_mem)
760 ships
668761
669762 let test_map () =
670 let module M = Map.Make(V6) in
763 let module M = Map.Make (V6) in
671764 let maxs = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" in
672765 let m = M.add (V6.of_string_exn "::0:0") "min" M.empty in
673766 let m = M.add (V6.of_string_exn maxs) "the greatest host" m in
674767 let m = M.add (V6.of_string_exn "::") "the least host" m in
675768 assert_equal ~msg:"size" (M.cardinal m) 2;
676 let (min_key, min_val) = M.min_binding m in
677 assert_equal ~msg:("min is '" ^ min_val ^"'") (min_key, min_val)
769 let min_key, min_val = M.min_binding m in
770 assert_equal
771 ~msg:("min is '" ^ min_val ^ "'")
772 (min_key, min_val)
678773 (V6.of_string_exn "::0:0:0", "the least host");
679774 assert_equal ~msg:"max" (M.max_binding m)
680775 (V6.of_string_exn maxs, "the greatest host")
681776
682777 let test_prefix_map () =
683 let module M = Map.Make(V6.Prefix) in
778 let module M = Map.Make (V6.Prefix) in
684779 let of_string s = s |> V6.Prefix.of_string_exn |> V6.Prefix.prefix in
685780 let m = M.add (of_string "::ffff:0.0.0.0/0") "everyone" M.empty in
686781 let m = M.add (of_string "::ffff:192.0.0.0/1") "weirdos" m in
693788 assert_equal ~msg:"max" (M.max_binding m)
694789 (of_string "::ffff:254.0.0.0/8", "top-end");
695790 assert_equal ~msg:"third"
696 (M.find (of_string "::ffff:128.0.0.0/1") m) "high-bitters"
791 (M.find (of_string "::ffff:128.0.0.0/1") m)
792 "high-bitters"
697793
698794 let test_multicast_mac () =
699795 let on = 0xFFFF in
700796 let ip = V6.make on on on on on 0xFFFF 0xFEFE 0xFDFD in
701 let unicast = V6.Prefix.(network_address global_unicast_001 ip) in
797 let unicast = V6.Prefix.(network_address global_unicast_001 ip) in
702798 let multicast = V6.Prefix.(network_address multicast ip) in
703 let unicast_mac_str = Macaddr.to_string (V6.multicast_to_mac unicast) in
799 let unicast_mac_str = Macaddr.to_string (V6.multicast_to_mac unicast) in
704800 let multicast_mac_str = Macaddr.to_string (V6.multicast_to_mac multicast) in
705801 let mac_str = "33:33:fe:fe:fd:fd" in
706 assert_equal ~msg:("unicast_mac "^unicast_mac_str^" <> "^mac_str)
707 unicast_mac_str mac_str;
708 assert_equal ~msg:("multicast_mac "^multicast_mac_str^" <> "^mac_str)
802 assert_equal
803 ~msg:("unicast_mac " ^ unicast_mac_str ^ " <> " ^ mac_str)
804 unicast_mac_str mac_str;
805 assert_equal
806 ~msg:("multicast_mac " ^ multicast_mac_str ^ " <> " ^ mac_str)
709807 multicast_mac_str mac_str
710808
711809 let test_domain_name () =
715813 in
716814 let name = Domain_name.(host_exn (of_string_exn name)) in
717815 assert_equal ~cmp:Domain_name.equal ~msg:"to_domain_name"
718 (V6.to_domain_name ip) name ;
816 (V6.to_domain_name ip) name;
719817 assert_equal ~msg:"of_domain_name" (V6.of_domain_name name) (Some ip)
720818
721819 let test_link_address_of_mac () =
722820 let mac = Macaddr.of_string_exn "34-56-78-9A-BC-DE" in
723821 let ip_str = V6.(to_string (link_address_of_mac mac)) in
724822 let expected = "fe80::3656:78ff:fe9a:bcde" in
725 assert_equal ~msg:("link_address_of_mac "^ip_str^" <> "^expected)
823 assert_equal
824 ~msg:("link_address_of_mac " ^ ip_str ^ " <> " ^ expected)
726825 ip_str expected
727826
728827 let test_succ_pred () =
736835 let ip2 = of_string_exn "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" in
737836 let ip3 = of_string_exn "::2" in
738837 assert_equal ~msg:"succ ::" (of_string "::1") (succ ip1);
739 assert_equal ~msg:"succ (succ ::)"
740 (of_string "::2") (succ ip1 >>= succ);
838 assert_equal ~msg:"succ (succ ::)" (of_string "::2") (succ ip1 >>= succ);
741839 assert_equal ~msg:"succ ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
742 (Error (`Msg "Ipaddr: highest address has been reached")) (succ ip2);
743 assert_equal ~msg:"pred ::2" (of_string "::1") (pred ip3) ;
744 assert_equal ~msg:"pred ::ffff:ffff"
745 (of_string "::ffff:fffd")
840 (Error (`Msg "Ipaddr: highest address has been reached"))
841 (succ ip2);
842 assert_equal ~msg:"pred ::2" (of_string "::1") (pred ip3);
843 assert_equal ~msg:"pred ::ffff:ffff" (of_string "::ffff:fffd")
746844 (of_string "::ffff:ffff" >>= pred >>= pred);
747845 assert_equal ~msg:"pred ::"
748 (Error (`Msg "Ipaddr: lowest address has been reached")) (pred ip1);
846 (Error (`Msg "Ipaddr: lowest address has been reached"))
847 (pred ip1);
749848 assert_equal ~msg:"pred (succ ::2)" (Ok ip3) (succ ip3 >>= pred)
750849
751850 let test_first_last () =
753852 let open Prefix in
754853 let ip_of_string = V6.of_string_exn in
755854 let assert_equal = assert_equal ~printer:V6.to_string in
756 assert_equal ~msg:"first ::/64"
757 (ip_of_string "::1") (first @@ of_string_exn "::/64");
758 assert_equal ~msg:"first ::ff00/120"
759 (ip_of_string "::ff01") (first @@ of_string_exn "::ff00/120");
760 assert_equal ~msg:"first ::aaa0/127"
761 (ip_of_string "::aaa0") (first @@ of_string_exn "::aaa0/127");
855 assert_equal ~msg:"first ::/64" (ip_of_string "::1")
856 (first @@ of_string_exn "::/64");
857 assert_equal ~msg:"first ::ff00/120" (ip_of_string "::ff01")
858 (first @@ of_string_exn "::ff00/120");
859 assert_equal ~msg:"first ::aaa0/127" (ip_of_string "::aaa0")
860 (first @@ of_string_exn "::aaa0/127");
762861 assert_equal ~msg:"first ::aaa0/128" (ip_of_string "::aaa0")
763862 (first @@ of_string_exn "::aaa0/128");
764 assert_equal ~msg:"last ::/64" (ip_of_string "::ffff:ffff:ffff:ffff")
863 assert_equal ~msg:"last ::/64"
864 (ip_of_string "::ffff:ffff:ffff:ffff")
765865 (last @@ of_string_exn "::/64");
766866 assert_equal ~msg:"last ::/120" (ip_of_string "::ff")
767867 (last @@ of_string_exn "::/120");
768868 assert_equal ~msg:"last ::/112" (ip_of_string "::ffff")
769869 (last @@ of_string_exn "::/112");
770 assert_equal ~msg:"last ::bbbb:eeee:0000:0000/64" (ip_of_string "::ffff:ffff:ffff:ffff")
870 assert_equal ~msg:"last ::bbbb:eeee:0000:0000/64"
871 (ip_of_string "::ffff:ffff:ffff:ffff")
771872 (last @@ of_string_exn "::bbbb:eeee:0000:0000/64");
772873 assert_equal ~msg:"last ::aaa0/127" (ip_of_string "::aaa1")
773874 (last @@ of_string_exn "::aaa0/127");
774875 assert_equal ~msg:"last ::aaa0/128" (ip_of_string "::aaa0")
775876 (last @@ of_string_exn "::aaa0/128")
776877
777 let suite = "Test V6" >::: [
778 "string_rt" >:: test_string_rt;
779 "string_rt_bad" >:: test_string_rt_bad;
780 "string_raw_rt" >:: test_string_raw_rt;
781 "string_raw_rt_bad" >:: test_string_raw_rt_bad;
782 "bytes_rt" >:: test_bytes_rt;
783 "bytes_rt_bad" >:: test_bytes_rt_bad;
784 "cstruct_rt" >:: test_cstruct_rt;
785 "cstruct_rt_bad" >:: test_cstruct_rt_bad;
786 "int32_rt" >:: test_int32_rt;
787 "prefix_string_rt" >:: test_prefix_string_rt;
788 "prefix_string_rt_bad" >:: test_prefix_string_rt_bad;
789 "network_address_rt" >:: test_network_address_rt;
790 "prefix_bits" >:: test_prefix_bits;
791 "prefix_netmask" >:: test_prefix_netmask;
792 "prefix_netmask_bad" >:: test_prefix_netmask_bad;
793 "scope" >:: test_scope;
794 "map" >:: test_map;
795 "prefix_map" >:: test_prefix_map;
796 "multicast_mac" >:: test_multicast_mac;
797 "domain_name" >:: test_domain_name;
798 "link_address_of_mac" >:: test_link_address_of_mac;
799 "succ_pred" >:: test_succ_pred;
800 "first_last" >:: test_first_last;
801 ]
878 let suite =
879 "Test V6"
880 >::: [
881 "string_rt" >:: test_string_rt;
882 "string_rt_bad" >:: test_string_rt_bad;
883 "string_raw_rt" >:: test_string_raw_rt;
884 "string_raw_rt_bad" >:: test_string_raw_rt_bad;
885 "bytes_rt" >:: test_bytes_rt;
886 "bytes_rt_bad" >:: test_bytes_rt_bad;
887 "cstruct_rt" >:: test_cstruct_rt;
888 "cstruct_rt_bad" >:: test_cstruct_rt_bad;
889 "int32_rt" >:: test_int32_rt;
890 "prefix_string_rt" >:: test_prefix_string_rt;
891 "prefix_string_rt_bad" >:: test_prefix_string_rt_bad;
892 "network_address_rt" >:: test_network_address_rt;
893 "prefix_bits" >:: test_prefix_bits;
894 "prefix_netmask" >:: test_prefix_netmask;
895 "prefix_netmask_bad" >:: test_prefix_netmask_bad;
896 "scope" >:: test_scope;
897 "map" >:: test_map;
898 "prefix_map" >:: test_prefix_map;
899 "multicast_mac" >:: test_multicast_mac;
900 "domain_name" >:: test_domain_name;
901 "link_address_of_mac" >:: test_link_address_of_mac;
902 "succ_pred" >:: test_succ_pred;
903 "first_last" >:: test_first_last;
904 ]
802905 end
803906
804907 let test_string_raw_rt () =
805 let addrs = [
806 ("IP: 192.168.0.0!!",4), ("192.168.0.0",15);
807 ("IP: 192:168:0::!!",4), ("192:168::",15);
808 ("IP: [192:168::]!!",4), ("192:168::",15);
809 ] in
810 List.iter (fun ((addr,off),(result,cursor)) ->
811 let c = ref off in
812 let os = of_string_raw addr c in
813 let ts = to_string os in
814 let msg = Printf.sprintf "%s at %d: %s at %d <> %s at %d"
815 addr off result cursor ts !c
816 in assert_equal ~msg (ts,!c) (result,cursor)
817 ) addrs
908 let addrs =
909 [
910 (("IP: 192.168.0.0!!", 4), ("192.168.0.0", 15));
911 (("IP: 192:168:0::!!", 4), ("192:168::", 15));
912 (("IP: [192:168::]!!", 4), ("192:168::", 15));
913 ]
914 in
915 List.iter
916 (fun ((addr, off), (result, cursor)) ->
917 let c = ref off in
918 let os = of_string_raw addr c in
919 let ts = to_string os in
920 let msg =
921 Printf.sprintf "%s at %d: %s at %d <> %s at %d" addr off result cursor
922 ts !c
923 in
924 assert_equal ~msg (ts, !c) (result, cursor))
925 addrs
818926
819927 let test_string_raw_rt_bad () =
820 let error (s,c) msg c' = (s,c), (Parse_error (msg,s),c') in
821 let addrs = [
822 error ("IP: ::192.168 ",4) "not an IPv4 address: invalid character ':' at 4\nnot an IPv6 address: invalid character ' ' at 13" 13;
823 error ("IP: [::192.168] ",4) "not an IPv4 address: invalid character '[' at 4\nnot an IPv6 address: invalid character ']' at 14" 14; (* ? *)
824 error ("IP: 192:168::3.5 ",4) "not an IPv4 address: invalid character ':' at 7\nnot an IPv6 address: invalid character ' ' at 16" 16;
825 ] in
826 List.iter (fun ((addr,off),(exn,cursor)) ->
827 let c = ref off in
828 assert_raises ~msg:addr exn (fun () -> of_string_raw addr c);
829 assert_equal ~msg:(Printf.sprintf "%s cursor <> %d (%d)" addr cursor !c)
830 !c cursor
831 ) addrs
928 let error (s, c) msg c' = ((s, c), (Parse_error (msg, s), c')) in
929 let addrs =
930 [
931 error ("IP: ::192.168 ", 4)
932 "not an IPv4 address: invalid character ':' at 4\n\
933 not an IPv6 address: invalid character ' ' at 13" 13;
934 error ("IP: [::192.168] ", 4)
935 "not an IPv4 address: invalid character '[' at 4\n\
936 not an IPv6 address: invalid character ']' at 14" 14;
937 (* ? *)
938 error ("IP: 192:168::3.5 ", 4)
939 "not an IPv4 address: invalid character ':' at 7\n\
940 not an IPv6 address: invalid character ' ' at 16" 16;
941 ]
942 in
943 List.iter
944 (fun ((addr, off), (exn, cursor)) ->
945 let c = ref off in
946 assert_raises ~msg:addr exn (fun () -> of_string_raw addr c);
947 assert_equal
948 ~msg:(Printf.sprintf "%s cursor <> %d (%d)" addr cursor !c)
949 !c cursor)
950 addrs
832951
833952 let test_map () =
834 let module M = Map.Make(Ipaddr) in
953 let module M = Map.Make (Ipaddr) in
835954 let maxv6 = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" in
836955 let maxv4 = "254.254.254.254" in
837956 let m = M.add (of_string_exn maxv4) "the greatest host v4" M.empty in
841960 let m = M.add (of_string_exn "1.0.0.1") "minv4" m in
842961 let m = M.add (of_string_exn "1.0.0.1") "the least host v4" m in
843962 assert_equal ~msg:"size" (M.cardinal m) 4;
844 let (min_key, min_val) = M.min_binding m in
845 assert_equal ~msg:("min is '" ^ min_val ^"'") (min_key, min_val)
963 let min_key, min_val = M.min_binding m in
964 assert_equal
965 ~msg:("min is '" ^ min_val ^ "'")
966 (min_key, min_val)
846967 (of_string_exn "1.0.0.1", "the least host v4");
847968 assert_equal ~msg:"max" (M.max_binding m)
848969 (of_string_exn maxv6, "the greatest host v6")
849970
850971 let test_prefix_mem () =
851972 let ip = of_string_exn in
852 let ships = [
853 ip "192.168.0.1", V4 V4.Prefix.private_192, true;
854 ip "192.168.0.1", Prefix.of_string_exn "::ffff:0:0/96", true;
855 ip "192.168.0.1", Prefix.of_string_exn "::ffff:0:0/95", true;
856 ip "192.168.0.1", Prefix.of_string_exn "::ffff:0:0/97", false;
857 ip "192.168.0.1", Prefix.of_string_exn "::ffff:128.0.0.0/97", true;
858 ip "::ffff:10.0.0.1", V4 V4.Prefix.private_10, true;
859 ip "::fffe:10.0.0.1", V4 V4.Prefix.private_10, false;
860 ] in
861 List.iter (fun (addr,subnet,is_mem) ->
862 let msg = Printf.sprintf "%s is%s in %s"
863 (to_string addr) (if is_mem then "" else " not") (Prefix.to_string subnet)
864 in
865 assert_equal ~msg (Prefix.mem addr subnet) is_mem
866 ) ships
973 let ships =
974 [
975 (ip "192.168.0.1", V4 V4.Prefix.private_192, true);
976 (ip "192.168.0.1", Prefix.of_string_exn "::ffff:0:0/96", true);
977 (ip "192.168.0.1", Prefix.of_string_exn "::ffff:0:0/95", true);
978 (ip "192.168.0.1", Prefix.of_string_exn "::ffff:0:0/97", false);
979 (ip "192.168.0.1", Prefix.of_string_exn "::ffff:128.0.0.0/97", true);
980 (ip "::ffff:10.0.0.1", V4 V4.Prefix.private_10, true);
981 (ip "::fffe:10.0.0.1", V4 V4.Prefix.private_10, false);
982 ]
983 in
984 List.iter
985 (fun (addr, subnet, is_mem) ->
986 let msg =
987 Printf.sprintf "%s is%s in %s" (to_string addr)
988 (if is_mem then "" else " not")
989 (Prefix.to_string subnet)
990 in
991 assert_equal ~msg (Prefix.mem addr subnet) is_mem)
992 ships
867993
868994 let test_prefix_subset () =
869995 let pre = Prefix.of_string_exn in
870 let ships = [
871 pre "10.0.0.1/32", pre "10.0.0.1/32", true;
872 pre "10.0.0.1/32", pre "10.0.0.2/32", false;
873 pre "10.0.0.3/32", pre "10.0.0.2/31", true;
874 pre "10.0.0.2/31", pre "10.0.0.3/32", false;
875 pre "10.0.10.0/24", V4 V4.Prefix.private_10, true;
876 V4 V4.Prefix.private_10, pre "10.0.10.0/24", false;
877 ] in
878 List.iter (fun (subnet1,subnet2,is_subset) ->
879 let msg = Printf.sprintf "%s is%s subset of %s"
880 (Prefix.to_string subnet1)
881 (if is_subset then "" else " not")
882 (Prefix.to_string subnet2)
883 in
884 assert_equal ~msg
885 (Prefix.subset ~subnet:subnet1 ~network:subnet2) is_subset
886 ) ships
887
888 let suite = "Test Generic Addresses" >::: [
889 "string_raw_rt" >:: test_string_raw_rt;
890 "string_raw_rt_bad" >:: test_string_raw_rt_bad;
891 "map" >:: test_map;
892 "prefix_mem" >:: test_prefix_mem;
893 "prefix_subset" >:: test_prefix_subset;
894 ]
996 let ships =
997 [
998 (pre "10.0.0.1/32", pre "10.0.0.1/32", true);
999 (pre "10.0.0.1/32", pre "10.0.0.2/32", false);
1000 (pre "10.0.0.3/32", pre "10.0.0.2/31", true);
1001 (pre "10.0.0.2/31", pre "10.0.0.3/32", false);
1002 (pre "10.0.10.0/24", V4 V4.Prefix.private_10, true);
1003 (V4 V4.Prefix.private_10, pre "10.0.10.0/24", false);
1004 ]
1005 in
1006 List.iter
1007 (fun (subnet1, subnet2, is_subset) ->
1008 let msg =
1009 Printf.sprintf "%s is%s subset of %s" (Prefix.to_string subnet1)
1010 (if is_subset then "" else " not")
1011 (Prefix.to_string subnet2)
1012 in
1013 assert_equal ~msg
1014 (Prefix.subset ~subnet:subnet1 ~network:subnet2)
1015 is_subset)
1016 ships
1017
1018 let suite =
1019 "Test Generic Addresses"
1020 >::: [
1021 "string_raw_rt" >:: test_string_raw_rt;
1022 "string_raw_rt_bad" >:: test_string_raw_rt_bad;
1023 "map" >:: test_map;
1024 "prefix_mem" >:: test_prefix_mem;
1025 "prefix_subset" >:: test_prefix_subset;
1026 ]
8951027
8961028 ;;
8971029 let _results = run_test_tt_main Test_v4.suite in
2424 | Error (`Msg e) -> Printf.sprintf "Error `Msg \"%s\"" e
2525 in
2626 let assert_equal = assert_equal ~printer in
27 assert_equal ~msg:":: >> 32"
28 (of_string "::")
27 assert_equal ~msg:":: >> 32" (of_string "::")
2928 (B128.shift_right (of_string_exn "::ffff:ffff") 32);
30 assert_equal ~msg:"::aaaa:bbbb:ffff:ffff >> 32"
31 (of_string "::aaaa:bbbb")
29 assert_equal ~msg:"::aaaa:bbbb:ffff:ffff >> 32" (of_string "::aaaa:bbbb")
3230 (B128.shift_right (of_string_exn "::aaaa:bbbb:ffff:ffff") 32);
33 assert_equal ~msg:"::aaaa:bbbb:ffff:ffff >> 40"
34 (of_string "::aa:aabb")
35 (B128.shift_right (of_string_exn "::aaaa:bbbb:ffff:ffff") 40);
36 assert_equal ~msg:"::ffff >> 2"
37 (of_string "::3fff")
38 (B128.shift_right (of_string_exn "::ffff") 2);
39 assert_equal ~msg:"ffff:: >> 128"
40 (of_string "::")
41 (B128.shift_right (of_string_exn "ffff::") 128);
42 assert_equal ~msg:"aaaa:bbbb:cccc:dddd:: >> 120"
43 (of_string "::aa")
44 (B128.shift_right (of_string_exn "aaaa:bbbb:cccc:dddd::") 120);
31 assert_equal ~msg:"::aaaa:bbbb:ffff:ffff >> 40" (of_string "::aa:aabb")
32 (B128.shift_right (of_string_exn "::aaaa:bbbb:ffff:ffff") 40);
33 assert_equal ~msg:"::ffff >> 2" (of_string "::3fff")
34 (B128.shift_right (of_string_exn "::ffff") 2);
35 assert_equal ~msg:"ffff:: >> 128" (of_string "::")
36 (B128.shift_right (of_string_exn "ffff::") 128);
37 assert_equal ~msg:"aaaa:bbbb:cccc:dddd:: >> 120" (of_string "::aa")
38 (B128.shift_right (of_string_exn "aaaa:bbbb:cccc:dddd::") 120);
4539 assert_equal ~msg:"ffff:: >> 140"
46 (of_string "::")
47 (B128.shift_right (of_string_exn "ffff::") 140);
40 (Error (`Msg "Ipaddr: unexpected argument sz (must be >= 0 and < 128)"))
41 (B128.shift_right (of_string_exn "ffff::") 140);
4842 assert_equal ~msg:"::ffff:ffff >> -8"
49 (of_string "::")
43 (Error (`Msg "Ipaddr: unexpected argument sz (must be >= 0 and < 128)"))
5044 (B128.shift_right (of_string_exn "::ffff:ffff") (-8))
5145
52 let suite = "Test B128 module" >::: [
53 "shift_right" >:: test_shift_right;
54 ]
46 let suite = "Test B128 module" >::: [ "shift_right" >:: test_shift_right ]
5547
5648 ;;
5749 let _results = run_test_tt_main suite in
1818 open Macaddr
1919
2020 let test_string_rt () =
21 let addrs = [
22 "ca:fe:ba:be:ee:ee", ':';
23 "ca-fe-ba-be-ee-ee", '-';
24 ] in
25 List.iter (fun (addr,sep) ->
26 let os = of_string_exn addr in
27 let ts = to_string ~sep os in
28 assert_equal ~msg:(addr ^ " <> " ^ ts) ts addr;
29 let os = Macaddr_sexp.(t_of_sexp (sexp_of_t os)) in
30 let ts = to_string ~sep os in
31 assert_equal ~msg:(addr ^ " <> " ^ ts) ts addr;
32 ) addrs
21 let addrs = [ ("ca:fe:ba:be:ee:ee", ':'); ("ca-fe-ba-be-ee-ee", '-') ] in
22 List.iter
23 (fun (addr, sep) ->
24 let os = of_string_exn addr in
25 let ts = to_string ~sep os in
26 assert_equal ~msg:(addr ^ " <> " ^ ts) ts addr;
27 let os = Macaddr_sexp.(t_of_sexp (sexp_of_t os)) in
28 let ts = to_string ~sep os in
29 assert_equal ~msg:(addr ^ " <> " ^ ts) ts addr)
30 addrs
3331
3432 let assert_result_failure ~msg a =
35 match a with
36 | Ok _ -> assert_failure msg
37 | Error (`Msg _) -> ()
33 match a with Ok _ -> assert_failure msg | Error (`Msg _) -> ()
3834
3935 let test_string_rt_bad () =
40 let addrs = [
41 "ca:fe:ba:be:ee:e";
42 "ca:fe:ba:be:ee:eee";
43 "ca:fe:ba:be:eeee";
44 "ca:fe:ba:be:ee::ee";
45 "ca:fe:ba:be:e:eee";
46 "ca:fe:ba:be:ee-ee";
47 ] in
36 let addrs =
37 [
38 "ca:fe:ba:be:ee:e";
39 "ca:fe:ba:be:ee:eee";
40 "ca:fe:ba:be:eeee";
41 "ca:fe:ba:be:ee::ee";
42 "ca:fe:ba:be:e:eee";
43 "ca:fe:ba:be:ee-ee";
44 ]
45 in
4846 List.iter (fun addr -> assert_result_failure ~msg:addr (of_string addr)) addrs
4947
5048 let test_bytes_rt () =
5250 assert_equal ~msg:(String.escaped addr) (to_octets (of_octets_exn addr)) addr
5351
5452 let test_bytes_rt_bad () =
55 let addrs = [
56 "\254\099\003\128\000";
57 "\254\099\003\128\000\000\233";
58 ] in
59 List.iter (fun addr ->
60 assert_result_failure ~msg:(String.escaped addr) (of_octets addr)) addrs
53 let addrs = [ "\254\099\003\128\000"; "\254\099\003\128\000\000\233" ] in
54 List.iter
55 (fun addr ->
56 assert_result_failure ~msg:(String.escaped addr) (of_octets addr))
57 addrs
6158
6259 let test_cstruct_rt () =
6360 let open Macaddr_cstruct in
6461 let addr = "\254\099\003\128\000\000" in
6562 assert_equal ~msg:(String.escaped addr)
66 (Cstruct.to_string (to_cstruct (of_cstruct_exn (Cstruct.of_string addr)))) addr
63 (Cstruct.to_string (to_cstruct (of_cstruct_exn (Cstruct.of_string addr))))
64 addr
6765
68 let error s = s, Parse_error ("MAC is exactly 6 bytes",s)
66 let error s = (s, Parse_error ("MAC is exactly 6 bytes", s))
6967
7068 let test_cstruct_rt_bad () =
7169 let open Macaddr_cstruct in
72 let addrs = [
73 error "\254\099\003\128\000";
74 error "\254\099\003\128\000\000\233";
75 ] in
76 List.iter (fun (addr,exn) ->
77 assert_raises ~msg:(String.escaped addr) exn (fun () -> of_cstruct_exn (Cstruct.of_string addr))) addrs
70 let addrs =
71 [ error "\254\099\003\128\000"; error "\254\099\003\128\000\000\233" ]
72 in
73 List.iter
74 (fun (addr, exn) ->
75 assert_raises ~msg:(String.escaped addr) exn (fun () ->
76 of_cstruct_exn (Cstruct.of_string addr)))
77 addrs
7878
7979 let test_make_local () =
8080 let () = Random.self_init () in
8383 assert_equal ~msg:"is_local" (is_local local_addr) true;
8484 assert_equal ~msg:"is_unicast" (is_unicast local_addr) true;
8585 assert_equal ~msg:"localize" (to_octets local_addr).[0] (Char.chr 254);
86 for i=1 to 5 do
87 assert_equal ~msg:("addr.["^(string_of_int i)^"]")
88 (to_octets local_addr).[i] (Char.chr (bytegen i))
86 for i = 1 to 5 do
87 assert_equal
88 ~msg:("addr.[" ^ string_of_int i ^ "]")
89 (to_octets local_addr).[i]
90 (Char.chr (bytegen i))
8991 done;
9092 assert_equal ~msg:"get_oui" (get_oui local_addr)
9193 ((254 lsl 16) + (254 lsl 8) + 253)
9294
93 let suite = "Test" >::: [
94 "string_rt" >:: test_string_rt;
95 "string_rt_bad" >:: test_string_rt_bad;
96 "bytes_rt" >:: test_bytes_rt;
97 "bytes_rt_bad" >:: test_bytes_rt_bad;
98 "cstruct_rt" >:: test_cstruct_rt;
99 "cstruct_rt_bad" >:: test_cstruct_rt_bad;
100 "make_local" >:: test_make_local;
101 ]
95 let suite =
96 "Test"
97 >::: [
98 "string_rt" >:: test_string_rt;
99 "string_rt_bad" >:: test_string_rt_bad;
100 "bytes_rt" >:: test_bytes_rt;
101 "bytes_rt_bad" >:: test_bytes_rt_bad;
102 "cstruct_rt" >:: test_cstruct_rt;
103 "cstruct_rt_bad" >:: test_cstruct_rt_bad;
104 "make_local" >:: test_make_local;
105 ]
106
102107 ;;
103108 run_test_tt_main suite
1515 *)
1616
1717 type t = {
18 ip: Ipaddr_sexp.t;
19 ipv6: Ipaddr_sexp.V6.t;
20 ipv6p: Ipaddr_sexp.V6.Prefix.t;
21 ipv4: Ipaddr_sexp.V4.t;
22 ipv4p: Ipaddr_sexp.V4.Prefix.t;
23 scope: Ipaddr_sexp.scope;
24 mac: Macaddr_sexp.t;
25 ipp: Ipaddr_sexp.Prefix.t;
26 } [@@deriving sexp]
18 ip : Ipaddr_sexp.t;
19 ipv6 : Ipaddr_sexp.V6.t;
20 ipv6p : Ipaddr_sexp.V6.Prefix.t;
21 ipv4 : Ipaddr_sexp.V4.t;
22 ipv4p : Ipaddr_sexp.V4.Prefix.t;
23 scope : Ipaddr_sexp.scope;
24 mac : Macaddr_sexp.t;
25 ipp : Ipaddr_sexp.Prefix.t;
26 }
27 [@@deriving sexp]
0 version: "5.0.1"
01 opam-version: "2.0"
12 maintainer: "anil@recoil.org"
23 authors: ["David Sheets" "Anil Madhavapeddy" "Hugo Heuzard"]
89 bug-reports: "https://github.com/mirage/ocaml-ipaddr/issues"
910 depends: [
1011 "ocaml" {>= "4.04.0"}
11 "dune"
12 "macaddr" {=version}
12 "dune" {>= "1.9.0"}
13 "macaddr" {= version}
1314 "cstruct"
1415 ]
1516 build: [
2021 dev-repo: "git+https://github.com/mirage/ocaml-ipaddr.git"
2122 description: """
2223 Cstruct convertions for macaddr
23 """
24 """
0 version: "5.0.1"
01 opam-version: "2.0"
12 maintainer: "anil@recoil.org"
23 authors: ["David Sheets" "Anil Madhavapeddy" "Hugo Heuzard"]
89 bug-reports: "https://github.com/mirage/ocaml-ipaddr/issues"
910 depends: [
1011 "ocaml" {>= "4.04.0"}
11 "dune"
12 "macaddr"
13 "macaddr-cstruct" {with-test}
12 "dune" {>= "1.9.0"}
13 "macaddr" {= version}
14 "macaddr-cstruct" {with-test & = version}
1415 "ounit" {with-test}
1516 "ppx_sexp_conv" {>= "v0.9.0"}
1617 ]
2324 dev-repo: "git+https://github.com/mirage/ocaml-ipaddr.git"
2425 description: """
2526 Sexp convertions for macaddr
26 """
27 """
0 version: "5.0.1"
01 opam-version: "2.0"
12 maintainer: "anil@recoil.org"
23 authors: ["David Sheets" "Anil Madhavapeddy" "Hugo Heuzard"]
89 bug-reports: "https://github.com/mirage/ocaml-ipaddr/issues"
910 depends: [
1011 "ocaml" {>= "4.04.0"}
11 "dune"
12 "dune" {>= "1.9.0"}
1213 "ounit" {with-test}
1314 "ppx_sexp_conv" {with-test & >= "v0.9.0"}
1415 ]
2829 * MAC-48 (Ethernet) address support
2930 * `Macaddr` is a `Map.OrderedType`
3031 * All types have sexplib serializers/deserializers optionally via the `Macaddr_sexp` library.
31 """
32 """