Skip to content

Commit 305df42

Browse files
authored
Merge pull request #4825 from Turbo87/simplify-cidr
Simplify CIDR parsing code
2 parents 3aabc79 + cfb6734 commit 305df42

File tree

1 file changed

+46
-45
lines changed

1 file changed

+46
-45
lines changed

src/config.rs

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use anyhow::{anyhow, Context};
12
use ipnetwork::IpNetwork;
23

34
use crate::publish_rate_limit::PublishRateLimit;
@@ -94,7 +95,11 @@ impl Default for Server {
9495
match env_optional::<String>("WEB_PAGE_OFFSET_CIDR_BLOCKLIST") {
9596
None => vec![],
9697
Some(s) if s.is_empty() => vec![],
97-
Some(s) => s.split(',').map(String::from).collect(),
98+
Some(s) => s
99+
.split(',')
100+
.map(parse_cidr_block)
101+
.collect::<Result<_, _>>()
102+
.unwrap(),
98103
};
99104

100105
let base = Base::from_environment();
@@ -116,7 +121,7 @@ impl Default for Server {
116121
blocked_traffic: blocked_traffic(),
117122
max_allowed_page_offset: env_optional("WEB_MAX_ALLOWED_PAGE_OFFSET").unwrap_or(200),
118123
page_offset_ua_blocklist,
119-
page_offset_cidr_blocklist: parse_cidr_blocks(&page_offset_cidr_blocklist),
124+
page_offset_cidr_blocklist,
120125
excluded_crate_names,
121126
domain_name: domain_name(),
122127
allowed_origins,
@@ -158,7 +163,7 @@ pub(crate) fn domain_name() -> String {
158163
dotenv::var("DOMAIN_NAME").unwrap_or_else(|_| "crates.io".into())
159164
}
160165

161-
/// Parses list of CIDR block strings to valid `IpNetwork` structs.
166+
/// Parses a CIDR block string to a valid `IpNetwork` struct.
162167
///
163168
/// The purpose is to be able to block IP ranges that overload the API that uses pagination.
164169
///
@@ -167,30 +172,21 @@ pub(crate) fn domain_name() -> String {
167172
/// * at least 16 for IPv4 based CIDRs.
168173
/// * at least 64 for IPv6 based CIDRs
169174
///
170-
fn parse_cidr_blocks(blocks: &[String]) -> Vec<IpNetwork> {
171-
blocks
172-
.iter()
173-
.map(|block| {
174-
let network = block.parse::<IpNetwork>();
175-
match network {
176-
Ok(cidr) => {
177-
let host_prefix = match cidr {
178-
IpNetwork::V4(_) => 16,
179-
IpNetwork::V6(_) => 64,
180-
};
181-
if cidr.prefix() < host_prefix {
182-
panic!(
183-
"WEB_PAGE_OFFSET_CIDR_BLOCKLIST only allows CIDR blocks with a host prefix \
184-
of at least 16 bits (IPv4) or 64 bits (IPv6)."
185-
);
186-
} else {
187-
cidr
188-
}
189-
},
190-
Err(_) => panic!("WEB_PAGE_OFFSET_CIDR_BLOCKLIST must contain IPv4 or IPv6 CIDR blocks."),
191-
}
192-
})
193-
.collect::<Vec<_>>()
175+
fn parse_cidr_block(block: &str) -> anyhow::Result<IpNetwork> {
176+
let cidr = block
177+
.parse()
178+
.context("WEB_PAGE_OFFSET_CIDR_BLOCKLIST must contain IPv4 or IPv6 CIDR blocks.")?;
179+
180+
let host_prefix = match cidr {
181+
IpNetwork::V4(_) => 16,
182+
IpNetwork::V6(_) => 64,
183+
};
184+
185+
if cidr.prefix() < host_prefix {
186+
return Err(anyhow!("WEB_PAGE_OFFSET_CIDR_BLOCKLIST only allows CIDR blocks with a host prefix of at least 16 bits (IPv4) or 64 bits (IPv6)."));
187+
}
188+
189+
Ok(cidr)
194190
}
195191

196192
fn blocked_traffic() -> Vec<(String, Vec<String>)> {
@@ -235,35 +231,40 @@ fn parse_traffic_patterns_splits_on_comma_and_looks_for_equal_sign() {
235231

236232
#[test]
237233
fn parse_cidr_block_list_successfully() {
238-
let cidr_blocks = vec!["127.0.0.1/24".to_string(), "192.168.0.1/31".to_string()];
239-
240-
let blocks = parse_cidr_blocks(&cidr_blocks);
241-
assert_eq!(
242-
vec![
243-
"127.0.0.1/24".parse::<IpNetwork>().unwrap(),
244-
"192.168.0.1/31".parse::<IpNetwork>().unwrap(),
245-
],
246-
blocks,
234+
assert_ok_eq!(
235+
parse_cidr_block("127.0.0.1/24"),
236+
"127.0.0.1/24".parse::<IpNetwork>().unwrap()
237+
);
238+
assert_ok_eq!(
239+
parse_cidr_block("192.168.0.1/31"),
240+
"192.168.0.1/31".parse::<IpNetwork>().unwrap()
247241
);
248242
}
249243

250244
#[test]
251-
#[should_panic]
252245
fn parse_cidr_blocks_panics_when_host_ipv4_prefix_is_too_low() {
253-
parse_cidr_blocks(&["127.0.0.1/8".to_string()]);
246+
assert_err!(parse_cidr_block("127.0.0.1/8"));
254247
}
255248

256249
#[test]
257-
#[should_panic]
258250
fn parse_cidr_blocks_panics_when_host_ipv6_prefix_is_too_low() {
259-
parse_cidr_blocks(&["2001:0db8:0123:4567:89ab:cdef:1234:5678/56".to_string()]);
251+
assert_err!(parse_cidr_block(
252+
"2001:0db8:0123:4567:89ab:cdef:1234:5678/56"
253+
));
260254
}
261255

262256
#[test]
263257
fn parse_ipv6_based_cidr_blocks() {
264-
let input = vec![
265-
"2002::1234:abcd:ffff:c0a8:101/64".to_string(),
266-
"2001:0db8:0123:4567:89ab:cdef:1234:5678/92".to_string(),
267-
];
268-
assert_eq!(2, parse_cidr_blocks(&input).len());
258+
assert_ok_eq!(
259+
parse_cidr_block("2002::1234:abcd:ffff:c0a8:101/64"),
260+
"2002::1234:abcd:ffff:c0a8:101/64"
261+
.parse::<IpNetwork>()
262+
.unwrap()
263+
);
264+
assert_ok_eq!(
265+
parse_cidr_block("2001:0db8:0123:4567:89ab:cdef:1234:5678/92"),
266+
"2001:0db8:0123:4567:89ab:cdef:1234:5678/92"
267+
.parse::<IpNetwork>()
268+
.unwrap()
269+
);
269270
}

0 commit comments

Comments
 (0)