X-Forwarded-For parsing and trusted proxy detection for OCaml
1(*---------------------------------------------------------------------------
2 Copyright (c) 2025 Thomas Gazagnaire. All rights reserved.
3 SPDX-License-Identifier: MIT
4 ---------------------------------------------------------------------------*)
5
6(* Crowbar-based fuzz testing for X-Forwarded-For parsing *)
7
8open Crowbar
9
10(* Test that parse_xff never crashes on arbitrary input *)
11let test_parse_xff_no_crash input =
12 ignore (Xff.parse_xff input);
13 check true
14
15(* Test that first_xff_ip never crashes *)
16let test_first_xff_no_crash input =
17 ignore (Xff.first_xff_ip input);
18 check true
19
20(* Test that parse_cidr never crashes *)
21let test_parse_cidr_no_crash input =
22 ignore (Xff.parse_cidr input);
23 check true
24
25(* Test client_ip with various combinations *)
26let test_get_ip_no_crash socket_ip xff_header =
27 let socket = Result.to_option (Ipaddr.of_string socket_ip) in
28 let xff = if xff_header = "" then None else Some xff_header in
29 ignore (Xff.client_ip ~socket_ip:socket ~xff_header:xff ~trusted_proxies:None);
30 check true
31
32(* Test with comma-separated IP addresses *)
33let test_comma_separated ip1 ip2 ip3 =
34 let xff = ip1 ^ ", " ^ ip2 ^ ", " ^ ip3 in
35 ignore (Xff.parse_xff xff);
36 check true
37
38(* Test IPv4-like addresses *)
39let test_ipv4_xff a b c d =
40 let ipv4 =
41 Fmt.str "%d.%d.%d.%d"
42 (abs a mod 256)
43 (abs b mod 256)
44 (abs c mod 256)
45 (abs d mod 256)
46 in
47 ignore (Xff.parse_xff ipv4);
48 check true
49
50(* Test CIDR notation *)
51let test_cidr_notation a b c d prefix =
52 let cidr =
53 Fmt.str "%d.%d.%d.%d/%d"
54 (abs a mod 256)
55 (abs b mod 256)
56 (abs c mod 256)
57 (abs d mod 256)
58 (abs prefix mod 33)
59 in
60 ignore (Xff.parse_cidr cidr);
61 check true
62
63(* Test is_trusted_proxy never crashes *)
64let test_is_trusted_proxy ip_str cidr_str =
65 (match (Ipaddr.of_string ip_str, Xff.parse_cidr cidr_str) with
66 | Ok ip, Ok prefix -> ignore (Xff.is_trusted_proxy ip [ prefix ])
67 | _ -> ());
68 check true
69
70let suite =
71 ( "xff",
72 [
73 test_case "parse_xff no crash" [ bytes ] test_parse_xff_no_crash;
74 test_case "first_xff_ip no crash" [ bytes ] test_first_xff_no_crash;
75 test_case "parse_cidr no crash" [ bytes ] test_parse_cidr_no_crash;
76 test_case "client_ip no crash" [ bytes; bytes ] test_get_ip_no_crash;
77 test_case "comma separated" [ bytes; bytes; bytes ] test_comma_separated;
78 test_case "ipv4" [ int; int; int; int ] test_ipv4_xff;
79 test_case "cidr notation" [ int; int; int; int; int ] test_cidr_notation;
80 test_case "is_trusted_proxy" [ bytes; bytes ] test_is_trusted_proxy;
81 ] )