Skip to content

Commit 0f56740

Browse files
authored
fix: fix net.is_IP_in_CIDR corner cases (#1913)
Signed-off-by: John Gardiner Myers <[email protected]>
1 parent 04504ae commit 0f56740

File tree

1 file changed

+210
-53
lines changed

1 file changed

+210
-53
lines changed

kclvm/runtime/src/net/mod.rs

Lines changed: 210 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -574,71 +574,36 @@ pub extern "C-unwind" fn kclvm_net_is_IP_in_CIDR(
574574
let kwargs = ptr_as_ref(kwargs);
575575

576576
let ip = match get_call_arg_str(args, kwargs, 0, Some("ip")) {
577-
Some(ip) => ip,
578577
None => {
579578
panic!("is_IP_in_CIDR() missing 2 required positional arguments: 'ip' and 'cidr'");
580579
}
580+
Some(ip) => match IpAddr::from_str(ip.as_str()) {
581+
Err(err) => panic!("is_IP_in_CIDR() invalid ip: {}", err),
582+
Ok(ip) => ip,
583+
},
581584
};
582585
let cidr = match get_call_arg_str(args, kwargs, 1, Some("cidr")) {
583-
Some(cidr) => cidr,
584586
None => {
585587
panic!("is_IP_in_CIDR() missing 2 required positional arguments: 'ip' and 'cidr'");
586588
}
589+
Some(cidr) => match IpCidr::from_str(&cidr.as_str()) {
590+
Err(err) => panic!("is_IP_in_CIDR() invalid cidr: {}", err),
591+
Ok(cidr) => cidr,
592+
},
587593
};
588594

589-
let (cidr_ip, mask_bits) = match _parse_cidr(&cidr) {
590-
Some((ip, bits)) => (ip, bits),
591-
None => return kclvm_value_False(ctx),
592-
};
593-
594-
match (_parse_ip(&ip), cidr_ip) {
595-
(Ok(IpAddr::V4(ip)), IpAddr::V4(cidr_ip)) => {
596-
let mask_bits = match mask_bits {
597-
Some(bits) if bits <= 32 => bits,
598-
_ => return kclvm_value_False(ctx),
599-
};
600-
kclvm_value_Bool(ctx, _check_ipv4_cidr(ip, cidr_ip, mask_bits) as i8)
601-
}
602-
(Ok(IpAddr::V6(ip)), IpAddr::V6(cidr_ip)) => {
603-
let mask_bits = match mask_bits {
604-
Some(bits) if bits <= 128 => bits,
605-
_ => return kclvm_value_False(ctx),
606-
};
607-
kclvm_value_Bool(ctx, _check_ipv6_cidr(ip, cidr_ip, mask_bits) as i8)
595+
if cidr.is_ipv6() {
596+
match ip {
597+
IpAddr::V4(ip) => {
598+
return kclvm_value_Bool(
599+
ctx,
600+
cidr.contains(&IpAddr::V6(ip.to_ipv6_mapped())) as i8,
601+
);
602+
}
603+
IpAddr::V6(_ip) => {}
608604
}
609-
_ => kclvm_value_False(ctx),
610-
}
611-
}
612-
613-
fn _parse_cidr(cidr: &str) -> Option<(IpAddr, Option<u32>)> {
614-
let parts: Vec<&str> = cidr.split('/').collect();
615-
if parts.len() != 2 {
616-
return None;
617605
}
618-
let ip = IpAddr::from_str(parts[0]).ok()?;
619-
let mask_bits = parts[1].parse::<u32>().ok();
620-
Some((ip, mask_bits))
621-
}
622-
623-
fn _parse_ip(ip: &str) -> Result<IpAddr, ()> {
624-
IpAddr::from_str(ip).map_err(|_| ())
625-
}
626-
627-
fn _check_ipv4_cidr(ip: Ipv4Addr, cidr_ip: Ipv4Addr, mask_bits: u32) -> bool {
628-
let mask = !((1u32 << (32 - mask_bits)) - 1);
629-
let ip_u32 = u32::from(ip);
630-
let cidr_u32 = u32::from(cidr_ip);
631-
(ip_u32 & mask) == (cidr_u32 & mask)
632-
}
633-
634-
fn _check_ipv6_cidr(ip: Ipv6Addr, cidr_ip: Ipv6Addr, mask_bits: u32) -> bool {
635-
let mask = match 128 - mask_bits {
636-
shift @ 0..=128 => !((1u128 << shift) - 1),
637-
_ => return false,
638-
};
639-
let ip_u128 = u128::from(ip);
640-
let cidr_u128 = u128::from(cidr_ip);
641-
(ip_u128 & mask) == (cidr_u128 & mask)
606+
return kclvm_value_Bool(ctx, cidr.contains(&ip) as i8);
642607
}
643608

644609
#[allow(non_camel_case_types, non_snake_case)]
@@ -1050,4 +1015,196 @@ mod test_net {
10501015
);
10511016
std::panic::set_hook(prev_hook);
10521017
}
1018+
1019+
#[test]
1020+
#[allow(non_snake_case)]
1021+
fn test_is_IP_in_CIDR() {
1022+
let cases = [
1023+
(
1024+
"0.0.0.0/0",
1025+
vec!["0.0.0.0", "255.255.255.255"],
1026+
vec!["::", "2001:db8::"],
1027+
),
1028+
(
1029+
"::/0",
1030+
vec![
1031+
"::",
1032+
"2001:db8::",
1033+
"10.1.2.3",
1034+
"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
1035+
],
1036+
vec![],
1037+
),
1038+
(
1039+
"10.0.0.0/8",
1040+
vec!["10.0.0.0", "10.1.2.3", "10.255.255.255"],
1041+
vec!["9.255.255.255", "11.0.0.0", "a000::"],
1042+
),
1043+
(
1044+
"2001:db8::/56",
1045+
vec!["2001:db8::", "2001:db8:0000:ff:ffff:ffff:ffff:ffff"],
1046+
vec![
1047+
"2001:db7:ffff:ffff:ffff:ffff:ffff:ffff",
1048+
"2001:db8:0:100::",
1049+
"10.1.2.3",
1050+
],
1051+
),
1052+
(
1053+
"10.1.2.3/32",
1054+
vec!["10.1.2.3"],
1055+
vec!["10.1.2.2", "10.1.2.4", "0a01:0203::"],
1056+
),
1057+
(
1058+
"2001:db8:1:2:3:4:5:7/128",
1059+
vec!["2001:db8:1:2:3:4:5:7"],
1060+
vec!["2001:db8:1:2:3:4:5:6", "2001:db8:1:2:3:4:5:8", "10.1.2.3"],
1061+
),
1062+
(
1063+
"10.1.2.3",
1064+
vec!["10.1.2.3"],
1065+
vec!["10.1.2.2", "10.1.2.4", "0a01:0203::"],
1066+
),
1067+
(
1068+
"2001:db8:1:2:3:4:5:7",
1069+
vec!["2001:db8:1:2:3:4:5:7"],
1070+
vec!["2001:db8:1:2:3:4:5:6", "2001:db8:1:2:3:4:5:8", "10.1.2.3"],
1071+
),
1072+
];
1073+
let mut ctx = Context::default();
1074+
for (cidr, expect_in, expect_not_in) in cases.iter() {
1075+
for ip in expect_in.iter() {
1076+
unsafe {
1077+
let actual = &*kclvm_net_is_IP_in_CIDR(
1078+
&mut ctx,
1079+
&ValueRef::list(Some(&[&ValueRef::str(ip), &ValueRef::str(cidr)])),
1080+
&ValueRef::dict(None),
1081+
);
1082+
assert_eq!(
1083+
&ValueRef::bool(true),
1084+
actual,
1085+
"{} in {} positional",
1086+
ip,
1087+
cidr
1088+
);
1089+
}
1090+
unsafe {
1091+
let actual = &*kclvm_net_is_IP_in_CIDR(
1092+
&mut ctx,
1093+
&ValueRef::list(None),
1094+
&ValueRef::dict(Some(&[
1095+
("cidr", &ValueRef::str(cidr)),
1096+
("ip", &ValueRef::str(ip)),
1097+
])),
1098+
);
1099+
assert_eq!(&ValueRef::bool(true), actual, "{} in {} named", ip, cidr);
1100+
}
1101+
}
1102+
for ip in expect_not_in.iter() {
1103+
unsafe {
1104+
let actual = &*kclvm_net_is_IP_in_CIDR(
1105+
&mut ctx,
1106+
&ValueRef::list(Some(&[&ValueRef::str(ip), &ValueRef::str(cidr)])),
1107+
&ValueRef::dict(None),
1108+
);
1109+
assert_eq!(
1110+
&ValueRef::bool(false),
1111+
actual,
1112+
"{} not in {} positional",
1113+
ip,
1114+
cidr
1115+
);
1116+
}
1117+
unsafe {
1118+
let actual = &*kclvm_net_is_IP_in_CIDR(
1119+
&mut ctx,
1120+
&ValueRef::list(None),
1121+
&ValueRef::dict(Some(&[
1122+
("cidr", &ValueRef::str(cidr)),
1123+
("ip", &ValueRef::str(ip)),
1124+
])),
1125+
);
1126+
assert_eq!(
1127+
&ValueRef::bool(false),
1128+
actual,
1129+
"{} not in {} named",
1130+
ip,
1131+
cidr
1132+
);
1133+
}
1134+
}
1135+
}
1136+
}
1137+
1138+
#[test]
1139+
#[allow(non_snake_case)]
1140+
fn test_is_IP_in_CIDR_invalid() {
1141+
let prev_hook = std::panic::take_hook();
1142+
// Disable print panic info in stderr.
1143+
std::panic::set_hook(Box::new(|_| {}));
1144+
assert_panic(
1145+
"is_IP_in_CIDR() missing 2 required positional arguments: 'ip' and 'cidr'",
1146+
|| {
1147+
let mut ctx = Context::new();
1148+
let args = ValueRef::list(None).into_raw(&mut ctx);
1149+
let kwargs = ValueRef::dict(None).into_raw(&mut ctx);
1150+
kclvm_net_is_IP_in_CIDR(ctx.into_raw(), args, kwargs);
1151+
},
1152+
);
1153+
assert_panic(
1154+
"is_IP_in_CIDR() missing 2 required positional arguments: 'ip' and 'cidr'",
1155+
|| {
1156+
let mut ctx = Context::new();
1157+
let args = ValueRef::list(Some(&[&ValueRef::str("10.1.2.3")])).into_raw(&mut ctx);
1158+
let kwargs = ValueRef::dict(None).into_raw(&mut ctx);
1159+
kclvm_net_is_IP_in_CIDR(ctx.into_raw(), args, kwargs);
1160+
},
1161+
);
1162+
assert_panic(
1163+
"is_IP_in_CIDR() missing 2 required positional arguments: 'ip' and 'cidr'",
1164+
|| {
1165+
let mut ctx = Context::new();
1166+
let args = ValueRef::list(None).into_raw(&mut ctx);
1167+
let kwargs =
1168+
ValueRef::dict(Some(&[("ip", &ValueRef::str("10.1.2.3"))])).into_raw(&mut ctx);
1169+
kclvm_net_is_IP_in_CIDR(ctx.into_raw(), args, kwargs);
1170+
},
1171+
);
1172+
assert_panic(
1173+
"is_IP_in_CIDR() missing 2 required positional arguments: 'ip' and 'cidr'",
1174+
|| {
1175+
let mut ctx = Context::new();
1176+
let args = ValueRef::list(None).into_raw(&mut ctx);
1177+
let kwargs = ValueRef::dict(Some(&[("cidr", &ValueRef::str("10.0.0.0/8"))]))
1178+
.into_raw(&mut ctx);
1179+
kclvm_net_is_IP_in_CIDR(ctx.into_raw(), args, kwargs);
1180+
},
1181+
);
1182+
let cases = [
1183+
("10.0.0/8", "10.0.0.1", "is_IP_in_CIDR() invalid cidr: couldn't parse address in network: invalid IP address syntax"),
1184+
("10.0.0.0/33", "10.0.0.1", "is_IP_in_CIDR() invalid cidr: invalid length for network: Network length 33 is too long for Ipv4 (maximum: 32)"),
1185+
("2001:db8:1:2:3:4:5:7/129", "2001:db8::", "is_IP_in_CIDR() invalid cidr: invalid length for network: Network length 129 is too long for Ipv6 (maximum: 128)"),
1186+
("0.0.0.0/256", "10.0.0.1", "is_IP_in_CIDR() invalid cidr: couldn't parse length in network: number too large to fit in target type"),
1187+
("::/256", "2001:db8::", "is_IP_in_CIDR() invalid cidr: couldn't parse length in network: number too large to fit in target type"),
1188+
("10.0.0.0/8/8", "10.0.0.1", "is_IP_in_CIDR() invalid cidr: couldn't parse address in network: invalid IP address syntax"),
1189+
("2001:db8::/56/56", "2001:db8::", "is_IP_in_CIDR() invalid cidr: couldn't parse address in network: invalid IP address syntax"),
1190+
("0.0.0.0/-1", "10.0.0.1", "is_IP_in_CIDR() invalid cidr: couldn't parse length in network: invalid digit found in string"),
1191+
("::/-1", "2001:db8::", "is_IP_in_CIDR() invalid cidr: couldn't parse length in network: invalid digit found in string"),
1192+
("10.128.0.0/8", "10.0.0.1", "is_IP_in_CIDR() invalid cidr: host part of address was not zero"),
1193+
("2001:db8::/16", "2001:db8::", "is_IP_in_CIDR() invalid cidr: host part of address was not zero"),
1194+
("10.1.2.3/31", "10.0.0.1", "is_IP_in_CIDR() invalid cidr: host part of address was not zero"),
1195+
("2001:db8:1:2:3:4:5:7/127", "2001:db8::", "is_IP_in_CIDR() invalid cidr: host part of address was not zero"),
1196+
("10.0.0.0/8", "10.0.0", "is_IP_in_CIDR() invalid ip: invalid IP address syntax"),
1197+
("2001:db8::/56", "2001:db8:::", "is_IP_in_CIDR() invalid ip: invalid IP address syntax"),
1198+
];
1199+
for (cidr, ip, expect_error) in cases.iter() {
1200+
assert_panic(expect_error, || {
1201+
let mut ctx = Context::new();
1202+
let args = ValueRef::list(Some(&[&ValueRef::str(ip), &ValueRef::str(cidr)]))
1203+
.into_raw(&mut ctx);
1204+
let kwargs = ValueRef::dict(None).into_raw(&mut ctx);
1205+
kclvm_net_is_IP_in_CIDR(ctx.into_raw(), args, kwargs);
1206+
});
1207+
}
1208+
std::panic::set_hook(prev_hook);
1209+
}
10531210
}

0 commit comments

Comments
 (0)