From 53a8e183daaadcb71b2af933e1070af73598e85f Mon Sep 17 00:00:00 2001 From: Akash Date: Sun, 22 Dec 2024 01:19:55 +0530 Subject: [PATCH 1/3] feat: Add CIDR parsing and IP address functions to net module Signed-off-by: Akash --- kclvm/runtime/src/_kclvm.h | 8 ++ kclvm/runtime/src/_kclvm.rs | 4 + kclvm/runtime/src/_kclvm_addr.rs | 4 + kclvm/runtime/src/net/mod.rs | 135 ++++++++++++++++++++++++ kclvm/sema/src/builtin/system_module.rs | 78 ++++++++++++++ 5 files changed, 229 insertions(+) diff --git a/kclvm/runtime/src/_kclvm.h b/kclvm/runtime/src/_kclvm.h index cff0e8c81..ad154bfcb 100644 --- a/kclvm/runtime/src/_kclvm.h +++ b/kclvm/runtime/src/_kclvm.h @@ -423,6 +423,14 @@ kclvm_value_ref_t* kclvm_net_is_IPv4(kclvm_context_t* ctx, kclvm_value_ref_t* ar kclvm_value_ref_t* kclvm_net_is_global_unicast_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_net_parse_CIDR (kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); + +kclvm_value_ref_t* kclvm_net_hosts_in_CIDR (kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); + +kclvm_value_ref_t* kclvm_net_subnets_from_CIDR (kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); + +kclvm_value_ref_t* kclvm_net_is_IP_in_CIDR (kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); + kclvm_value_ref_t* kclvm_net_is_interface_local_multicast_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); kclvm_value_ref_t* kclvm_net_is_link_local_multicast_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); diff --git a/kclvm/runtime/src/_kclvm.rs b/kclvm/runtime/src/_kclvm.rs index 0e45fb162..6a900a4f2 100644 --- a/kclvm/runtime/src/_kclvm.rs +++ b/kclvm/runtime/src/_kclvm.rs @@ -204,6 +204,10 @@ pub enum ApiFunc { kclvm_net_is_IP, kclvm_net_is_IPv4, kclvm_net_is_global_unicast_IP, + kclvm_net_parse_CIDR, + kclvm_net_hosts_in_CIDR, + kclvm_net_subnets_from_CIDR, + kclvm_net_is_IP_in_CIDR, kclvm_net_is_interface_local_multicast_IP, kclvm_net_is_link_local_multicast_IP, kclvm_net_is_link_local_unicast_IP, diff --git a/kclvm/runtime/src/_kclvm_addr.rs b/kclvm/runtime/src/_kclvm_addr.rs index 25012b473..4d0a84abf 100644 --- a/kclvm/runtime/src/_kclvm_addr.rs +++ b/kclvm/runtime/src/_kclvm_addr.rs @@ -223,6 +223,10 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_net_is_loopback_IP" => crate::kclvm_net_is_loopback_IP as *const () as u64, "kclvm_net_is_multicast_IP" => crate::kclvm_net_is_multicast_IP as *const () as u64, "kclvm_net_is_unspecified_IP" => crate::kclvm_net_is_unspecified_IP as *const () as u64, + "kclvm_net_parse_CIDR" => crate::kclvm_net_parse_CIDR as *const () as u64, + "kclvm_net_hosts_in_CIDR" => crate::kclvm_net_hosts_in_CIDR as *const () as u64, + "kclvm_net_subnets_from_CIDR" => crate::kclvm_net_subnets_from_CIDR as *const () as u64, + "kclvm_net_is_IP_in_CIDR" => crate::kclvm_net_is_IP_in_CIDR as *const () as u64, "kclvm_net_join_host_port" => crate::kclvm_net_join_host_port as *const () as u64, "kclvm_net_parse_IP" => crate::kclvm_net_parse_IP as *const () as u64, "kclvm_net_split_host_port" => crate::kclvm_net_split_host_port as *const () as u64, diff --git a/kclvm/runtime/src/net/mod.rs b/kclvm/runtime/src/net/mod.rs index 5446d1bab..d58294c40 100644 --- a/kclvm/runtime/src/net/mod.rs +++ b/kclvm/runtime/src/net/mod.rs @@ -396,6 +396,141 @@ pub extern "C" fn kclvm_net_is_global_unicast_IP( panic!("is_global_unicast_IP() missing 1 required positional argument: 'ip'"); } +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_parse_CIDR( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(cidr) = get_call_arg_str(args, kwargs, 0, Some("cidr")) { + let parts: Vec<&str> = cidr.split('/').collect(); + if parts.len() == 2 { + let ip = parts[0]; + let mask = parts[1]; + if let Ok(ip) = Ipv4Addr::from_str(ip) { + if let Ok(mask) = mask.parse::() { + return ValueRef::dict( + vec![ + ("ip", ValueRef::str(ip.to_string().as_str())), + ("mask", ValueRef::i_int(mask as i64)), + ], + None, + ) + .into_raw(ctx); + } + } + } + return ValueRef::dict(vec![], None).into_raw(ctx); + } + + panic!("parse_CIDR() missing 1 required positional argument: 'cidr'"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_hosts_in_CIDR ( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(cidr) = get_call_arg_str(args, kwargs, 0, Some("cidr")) { + let parts: Vec<&str> = cidr.split('/').collect(); + if parts.len() == 2 { + let ip = parts[0]; + let mask = parts[1]; + if let Ok(ip) = Ipv4Addr::from_str(ip) { + if let Ok(mask) = mask.parse::() { + let mask = u32::from_be_bytes(ip.octets()) & !((1 << (32 - mask)) - 1); + let mut hosts = vec![]; + for i in 1..(1 << (32 - mask)) - 1 { + let ip = u32::from_be_bytes(ip.octets()) + i; + hosts.push(ValueRef::str(Ipv4Addr::from(ip).to_string().as_str())); + } + return ValueRef::list(Some(hosts)).into_raw(ctx); + } + } + } + return ValueRef::list(None).into_raw(ctx); + } + + panic!("hosts_in_CIDR() missing 1 required positional argument: 'cidr'"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_subnets_from_CIDR ( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + let ctx = mut_ptr_as_ref(ctx); + + if let Some(cidr) = get_call_arg_str(args, kwargs, 0, Some("cidr")) { + let parts: Vec<&str> = cidr.split('/').collect(); + if parts.len() == 2 { + let ip = parts[0]; + let mask = parts[1]; + if let Ok(ip) = Ipv4Addr::from_str(ip) { + if let Ok(mask) = mask.parse::() { + let mask = u32::from_be_bytes(ip.octets()) & !((1 << (32 - mask)) - 1); + let mut subnets = vec![]; + for i in 1..(1 << (32 - mask)) - 1 { + let ip = u32::from_be_bytes(ip.octets()) + i; + subnets.push(ValueRef::str(format!("{}/{}", Ipv4Addr::from(ip), mask).as_str())); + } + return ValueRef::list(Some(subnets)).into_raw(ctx); + } + } + } + return ValueRef::list(None).into_raw(ctx); + } + + panic!("subnets_from_CIDR() missing 1 required positional argument: 'cidr'"); +} + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_net_is_IP_in_CIDR ( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(ip) = get_call_arg_str(args, kwargs, 0, Some("ip")) { + if let Some(cidr) = get_call_arg_str(args, kwargs, 1, Some("cidr")) { + let parts: Vec<&str> = cidr.split('/').collect(); + if parts.len() == 2 { + let ip = parts[0]; + let mask = parts[1]; + if let Ok(ip) = Ipv4Addr::from_str(ip) { + if let Ok(mask) = mask.parse::() { + let mask = u32::from_be_bytes(ip.octets()) & !((1 << (32 - mask)) - 1); + let ip = u32::from_be_bytes(ip.octets()); + let x = (ip & mask) == mask; + return kclvm_value_Bool(ctx, x as i8); + } + } + } + } + return kclvm_value_False(ctx); + } + + panic!("is_IP_in_CIDR() missing 2 required positional arguments: 'ip' and 'cidr'"); +} + #[allow(non_camel_case_types, non_snake_case)] fn Ipv4Addr_is_global(_self: &std::net::Ipv4Addr) -> bool { // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two diff --git a/kclvm/sema/src/builtin/system_module.rs b/kclvm/sema/src/builtin/system_module.rs index af2e3bc62..ceda2b74a 100644 --- a/kclvm/sema/src/builtin/system_module.rs +++ b/kclvm/sema/src/builtin/system_module.rs @@ -345,6 +345,84 @@ register_net_member! { false, None, ) + parse_CIDR => Type::function( + None, + Type::dict_ref(Type::str_ref(), Type::str_ref()), + &[ + Parameter { + name: "cidr".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Parse a CIDR block into network, prefix, minHost, and maxHost."#, + false, + None, + ) + hosts_in_CIDR => Type::function( + None, + Type::list_ref(Type::str_ref()), + &[ + Parameter { + name: "cidr".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Generate a list of all IP addresses in a CIDR block."#, + false, + None, + ) + subnets_from_CIDR => Type::function( + None, + Type::list_ref(Type::str_ref()), + &[ + Parameter { + name: "cidr".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "new_prefix".to_string(), + ty: Type::int_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Split a CIDR block into smaller subnets with a given prefix."#, + false, + None, + ) + is_IP_in_CIDR => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + Parameter { + name: "cidr".to_string(), + ty: Type::str_ref(), + has_default: false, + default_value: None, + range: dummy_range(), + }, + ], + r#"Check if an IP address is within a given CIDR block."#, + false, + None, + ) } // ------------------------------ From cbe3cc6ceb53eeb5b098aa26b53b6e154bc1510c Mon Sep 17 00:00:00 2001 From: Akash Date: Sun, 22 Dec 2024 01:26:55 +0530 Subject: [PATCH 2/3] feat: Refactor CIDR parsing functions for improved value handling and add tests for new functionality Signed-off-by: Akash --- kclvm/runtime/src/net/mod.rs | 21 +++++++++++---------- test/grammar/builtins/net/is_ip_2/main.k | 5 +++++ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/kclvm/runtime/src/net/mod.rs b/kclvm/runtime/src/net/mod.rs index d58294c40..4abce8758 100644 --- a/kclvm/runtime/src/net/mod.rs +++ b/kclvm/runtime/src/net/mod.rs @@ -414,18 +414,17 @@ pub extern "C" fn kclvm_net_parse_CIDR( let mask = parts[1]; if let Ok(ip) = Ipv4Addr::from_str(ip) { if let Ok(mask) = mask.parse::() { - return ValueRef::dict( - vec![ - ("ip", ValueRef::str(ip.to_string().as_str())), - ("mask", ValueRef::i_int(mask as i64)), - ], - None, - ) + let ip_value = ValueRef::str(ip.to_string().as_str()); + let mask_value = ValueRef::int(mask as i64); + return ValueRef::dict(Some(&[ + ("ip", &ip_value), + ("mask", &mask_value), + ])) .into_raw(ctx); } } } - return ValueRef::dict(vec![], None).into_raw(ctx); + return ValueRef::dict(None).into_raw(ctx); } panic!("parse_CIDR() missing 1 required positional argument: 'cidr'"); @@ -455,7 +454,8 @@ pub extern "C" fn kclvm_net_hosts_in_CIDR ( let ip = u32::from_be_bytes(ip.octets()) + i; hosts.push(ValueRef::str(Ipv4Addr::from(ip).to_string().as_str())); } - return ValueRef::list(Some(hosts)).into_raw(ctx); + let hosts_refs: Vec<&ValueRef> = hosts.iter().collect(); + return ValueRef::list(Some(&hosts_refs[..])).into_raw(ctx); } } } @@ -489,7 +489,8 @@ pub extern "C" fn kclvm_net_subnets_from_CIDR ( let ip = u32::from_be_bytes(ip.octets()) + i; subnets.push(ValueRef::str(format!("{}/{}", Ipv4Addr::from(ip), mask).as_str())); } - return ValueRef::list(Some(subnets)).into_raw(ctx); + let subnets_refs: Vec<&ValueRef> = subnets.iter().collect(); + return ValueRef::list(Some(&subnets_refs)).into_raw(ctx); } } } diff --git a/test/grammar/builtins/net/is_ip_2/main.k b/test/grammar/builtins/net/is_ip_2/main.k index d215848d3..bed34c0c5 100644 --- a/test/grammar/builtins/net/is_ip_2/main.k +++ b/test/grammar/builtins/net/is_ip_2/main.k @@ -6,3 +6,8 @@ isip2 = net.is_link_local_multicast_IP("224.0.0.0") isip3 = net.is_link_local_unicast_IP("fe80::2012:1") isip4 = net.is_global_unicast_IP("220.181.108.89") isip5 = net.is_unspecified_IP("0.0.0.0") +isip6 = net.parse_CIDR("192.168.1.0/24") +isip7 = net.hosts_in_CIDR("192.168.1.0/24") +isip8 = net.subnets_from_CIDR("192.168.1.0/24") +isip9 = net.is_IP_in_CIDR("192.168.1.1", "192.168.1.0/24") + From c8ffa8f7a192f37cbe6e4c0c4f5d13b7552c2f39 Mon Sep 17 00:00:00 2001 From: Akash Date: Tue, 24 Dec 2024 18:59:18 +0530 Subject: [PATCH 3/3] chore: run cargo fmt Signed-off-by: Akash --- kclvm/runtime/src/net/mod.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/kclvm/runtime/src/net/mod.rs b/kclvm/runtime/src/net/mod.rs index 4abce8758..168fbec97 100644 --- a/kclvm/runtime/src/net/mod.rs +++ b/kclvm/runtime/src/net/mod.rs @@ -416,11 +416,8 @@ pub extern "C" fn kclvm_net_parse_CIDR( if let Ok(mask) = mask.parse::() { let ip_value = ValueRef::str(ip.to_string().as_str()); let mask_value = ValueRef::int(mask as i64); - return ValueRef::dict(Some(&[ - ("ip", &ip_value), - ("mask", &mask_value), - ])) - .into_raw(ctx); + return ValueRef::dict(Some(&[("ip", &ip_value), ("mask", &mask_value)])) + .into_raw(ctx); } } } @@ -432,7 +429,7 @@ pub extern "C" fn kclvm_net_parse_CIDR( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_net_hosts_in_CIDR ( +pub extern "C" fn kclvm_net_hosts_in_CIDR( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, @@ -467,7 +464,7 @@ pub extern "C" fn kclvm_net_hosts_in_CIDR ( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_net_subnets_from_CIDR ( +pub extern "C" fn kclvm_net_subnets_from_CIDR( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t, @@ -487,7 +484,9 @@ pub extern "C" fn kclvm_net_subnets_from_CIDR ( let mut subnets = vec![]; for i in 1..(1 << (32 - mask)) - 1 { let ip = u32::from_be_bytes(ip.octets()) + i; - subnets.push(ValueRef::str(format!("{}/{}", Ipv4Addr::from(ip), mask).as_str())); + subnets.push(ValueRef::str( + format!("{}/{}", Ipv4Addr::from(ip), mask).as_str(), + )); } let subnets_refs: Vec<&ValueRef> = subnets.iter().collect(); return ValueRef::list(Some(&subnets_refs)).into_raw(ctx); @@ -502,7 +501,7 @@ pub extern "C" fn kclvm_net_subnets_from_CIDR ( #[no_mangle] #[runtime_fn] -pub extern "C" fn kclvm_net_is_IP_in_CIDR ( +pub extern "C" fn kclvm_net_is_IP_in_CIDR( ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, kwargs: *const kclvm_value_ref_t,