Skip to content

Commit

Permalink
feat : Added cidr manipulation functions to net module (#1798)
Browse files Browse the repository at this point in the history
* feat: Add CIDR parsing and IP address functions to net module

Signed-off-by: Akash <akashsingh2210670@gmail.com>

* feat: Refactor CIDR parsing functions for improved value handling and add tests for new functionality

Signed-off-by: Akash <akashsingh2210670@gmail.com>

* chore: run cargo fmt

Signed-off-by: Akash <akashsingh2210670@gmail.com>

---------

Signed-off-by: Akash <akashsingh2210670@gmail.com>
Co-authored-by: Peefy <xpf6677@163.com>
  • Loading branch information
SkySingh04 and Peefy authored Jan 12, 2025
1 parent f368119 commit 420ebcc
Show file tree
Hide file tree
Showing 6 changed files with 234 additions and 0 deletions.
8 changes: 8 additions & 0 deletions kclvm/runtime/src/_kclvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,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);
Expand Down
4 changes: 4 additions & 0 deletions kclvm/runtime/src/_kclvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,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,
Expand Down
4 changes: 4 additions & 0 deletions kclvm/runtime/src/_kclvm_addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,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,
Expand Down
135 changes: 135 additions & 0 deletions kclvm/runtime/src/net/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<u8>() {
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(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::<u8>() {
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()));
}
let hosts_refs: Vec<&ValueRef> = hosts.iter().collect();
return ValueRef::list(Some(&hosts_refs[..])).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::<u8>() {
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(),
));
}
let subnets_refs: Vec<&ValueRef> = subnets.iter().collect();
return ValueRef::list(Some(&subnets_refs)).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::<u8>() {
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
Expand Down
78 changes: 78 additions & 0 deletions kclvm/sema/src/builtin/system_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
}

// ------------------------------
Expand Down
5 changes: 5 additions & 0 deletions test/grammar/builtins/net/is_ip_2/main.k
Original file line number Diff line number Diff line change
Expand Up @@ -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")

0 comments on commit 420ebcc

Please sign in to comment.