robinpath_modules/modules/
ip_mod.rs1use robinpath::{RobinPath, Value};
2use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
3
4pub fn register(rp: &mut RobinPath) {
5 rp.register_builtin("ip.isValid", |args, _| {
7 let addr = args.first().map(|v| v.to_display_string()).unwrap_or_default();
8 Ok(Value::Bool(addr.parse::<IpAddr>().is_ok()))
9 });
10
11 rp.register_builtin("ip.isV4", |args, _| {
13 let addr = args.first().map(|v| v.to_display_string()).unwrap_or_default();
14 Ok(Value::Bool(addr.parse::<Ipv4Addr>().is_ok()))
15 });
16
17 rp.register_builtin("ip.isV6", |args, _| {
19 let addr = args.first().map(|v| v.to_display_string()).unwrap_or_default();
20 Ok(Value::Bool(addr.parse::<Ipv6Addr>().is_ok()))
21 });
22
23 rp.register_builtin("ip.toInt", |args, _| {
25 let addr = args.first().map(|v| v.to_display_string()).unwrap_or_default();
26 match addr.parse::<Ipv4Addr>() {
27 Ok(ip) => {
28 let n: u32 = u32::from(ip);
29 Ok(Value::Number(n as f64))
30 }
31 Err(_) => Err(format!("ip.toInt: invalid IPv4 address \"{}\"", addr)),
32 }
33 });
34
35 rp.register_builtin("ip.fromInt", |args, _| {
37 let num = args.first().map(|v| v.to_number()).unwrap_or(0.0) as u32;
38 let ip = Ipv4Addr::from(num);
39 Ok(Value::String(ip.to_string()))
40 });
41
42 rp.register_builtin("ip.isPrivate", |args, _| {
44 let addr_str = args.first().map(|v| v.to_display_string()).unwrap_or_default();
45 match addr_str.parse::<IpAddr>() {
46 Ok(IpAddr::V4(ip)) => {
47 let octets = ip.octets();
48 let is_private =
49 octets[0] == 10 ||
51 (octets[0] == 172 && (16..=31).contains(&octets[1])) ||
53 (octets[0] == 192 && octets[1] == 168) ||
55 octets[0] == 127;
57 Ok(Value::Bool(is_private))
58 }
59 Ok(IpAddr::V6(ip)) => {
60 let segments = ip.segments();
61 let is_private =
62 ip == Ipv6Addr::LOCALHOST ||
64 (segments[0] & 0xfe00) == 0xfc00;
66 Ok(Value::Bool(is_private))
67 }
68 Err(_) => Ok(Value::Bool(false)),
69 }
70 });
71
72 rp.register_builtin("ip.cidrMatch", |args, _| {
74 let addr_str = args.first().map(|v| v.to_display_string()).unwrap_or_default();
75 let cidr_str = args.get(1).map(|v| v.to_display_string()).unwrap_or_default();
76
77 let addr: IpAddr = match addr_str.parse() {
78 Ok(a) => a,
79 Err(_) => return Ok(Value::Bool(false)),
80 };
81
82 let parts: Vec<&str> = cidr_str.split('/').collect();
84 if parts.len() != 2 {
85 return Ok(Value::Bool(false));
86 }
87 let network: IpAddr = match parts[0].parse() {
88 Ok(a) => a,
89 Err(_) => return Ok(Value::Bool(false)),
90 };
91 let prefix_len: u32 = match parts[1].parse() {
92 Ok(n) => n,
93 Err(_) => return Ok(Value::Bool(false)),
94 };
95
96 let result = match (addr, network) {
97 (IpAddr::V4(a), IpAddr::V4(n)) => {
98 if prefix_len > 32 {
99 false
100 } else if prefix_len == 0 {
101 true
102 } else {
103 let mask = if prefix_len == 32 {
104 u32::MAX
105 } else {
106 u32::MAX << (32 - prefix_len)
107 };
108 let a_int = u32::from(a);
109 let n_int = u32::from(n);
110 (a_int & mask) == (n_int & mask)
111 }
112 }
113 (IpAddr::V6(a), IpAddr::V6(n)) => {
114 if prefix_len > 128 {
115 false
116 } else if prefix_len == 0 {
117 true
118 } else {
119 let mask = if prefix_len == 128 {
120 u128::MAX
121 } else {
122 u128::MAX << (128 - prefix_len)
123 };
124 let a_int = u128::from(a);
125 let n_int = u128::from(n);
126 (a_int & mask) == (n_int & mask)
127 }
128 }
129 _ => false, };
131
132 Ok(Value::Bool(result))
133 });
134}