Skip to content

Commit 46d97ea

Browse files
committed
Expand CIDR block list to support IPv6 ranges
This refactors the `WEB_PAGE_OFFSET_CIDR_BLOCKLIST` block list to also support IPv6 based CIDR blocks.
1 parent dfe0c87 commit 46d97ea

File tree

3 files changed

+42
-27
lines changed

3 files changed

+42
-27
lines changed

src/config.rs

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use ipnetwork::Ipv4Network;
1+
use ipnetwork::IpNetwork;
22

33
use crate::publish_rate_limit::PublishRateLimit;
44
use crate::{env, env_optional, uploaders::Uploader, Env};
@@ -27,7 +27,7 @@ pub struct Server {
2727
pub blocked_traffic: Vec<(String, Vec<String>)>,
2828
pub max_allowed_page_offset: u32,
2929
pub page_offset_ua_blocklist: Vec<String>,
30-
pub page_offset_cidr_blocklist: Vec<Ipv4Network>,
30+
pub page_offset_cidr_blocklist: Vec<IpNetwork>,
3131
pub excluded_crate_names: Vec<String>,
3232
pub domain_name: String,
3333
pub allowed_origins: Vec<String>,
@@ -166,21 +166,28 @@ pub(crate) fn domain_name() -> String {
166166
/// * Only IPv4 blocks are currently supported.
167167
/// * The minimum number of host prefix bits must be at least 16.
168168
///
169-
fn parse_cidr_blocks(blocks: &[String]) -> Vec<Ipv4Network> {
169+
fn parse_cidr_blocks(blocks: &[String]) -> Vec<IpNetwork> {
170170
blocks
171171
.iter()
172-
.map(|block| match block.parse::<Ipv4Network>() {
173-
Ok(cidr) => {
174-
if cidr.prefix() < 16 {
175-
panic!(
176-
"WEB_PAGE_OFFSET_CIDR_BLOCKLIST must only contain CIDR blocks with \
177-
a host prefix of at least 16 bits."
178-
)
179-
} else {
180-
cidr
181-
}
172+
.map(|block| {
173+
let network = block.parse::<IpNetwork>();
174+
match network {
175+
Ok(cidr) => {
176+
let host_prefix = match cidr {
177+
IpNetwork::V4(_) => 16,
178+
IpNetwork::V6(_) => 64,
179+
};
180+
if cidr.prefix() < host_prefix {
181+
panic!(
182+
"WEB_PAGE_OFFSET_CIDR_BLOCKLIST only allows CIDR blocks with a host prefix \
183+
of at least 16 bits (IPv4) or 64 bits (IPv6)."
184+
);
185+
} else {
186+
cidr
187+
}
188+
},
189+
Err(_) => panic!("WEB_PAGE_OFFSET_CIDR_BLOCKLIST must contain IPv4 or IPv6 CIDR blocks."),
182190
}
183-
Err(_) => panic!("WEB_PAGE_OFFSET_CIDR_BLOCKLIST only allows IPv4 CIDR blocks"),
184191
})
185192
.collect::<Vec<_>>()
186193
}
@@ -232,23 +239,32 @@ fn parse_cidr_block_list_successfully() {
232239
let blocks = parse_cidr_blocks(&cidr_blocks);
233240
assert_eq!(
234241
vec![
235-
"127.0.0.1/24".parse::<Ipv4Network>().unwrap(),
236-
"192.168.0.1/31".parse::<Ipv4Network>().unwrap(),
242+
"127.0.0.1/24".parse::<IpNetwork>().unwrap(),
243+
"192.168.0.1/31".parse::<IpNetwork>().unwrap(),
237244
],
238245
blocks,
239246
);
240247
}
241248

242249
#[test]
243250
#[should_panic]
244-
fn parse_cidr_blocks_panics_when_host_prefix_is_too_low() {
245-
let input = vec!["127.0.0.1/8".to_string()];
246-
parse_cidr_blocks(&input);
251+
fn parse_cidr_blocks_panics_when_host_ipv4_prefix_is_too_low() {
252+
parse_cidr_blocks(&vec!["127.0.0.1/8".to_string()]);
247253
}
248254

249255
#[test]
250256
#[should_panic]
251-
fn parse_cidr_blocks_panics_when_ipv6_is_given() {
252-
let input = vec!["2002::1234:abcd:ffff:c0a8:101/64".to_string()];
253-
parse_cidr_blocks(&input);
257+
fn parse_cidr_blocks_panics_when_host_ipv6_prefix_is_too_low() {
258+
parse_cidr_blocks(&vec![
259+
"2001:0db8:0123:4567:89ab:cdef:1234:5678/56".to_string()
260+
]);
261+
}
262+
263+
#[test]
264+
fn parse_ipv6_based_cidr_blocks() {
265+
let input = vec![
266+
"2002::1234:abcd:ffff:c0a8:101/64".to_string(),
267+
"2001:0db8:0123:4567:89ab:cdef:1234:5678/92".to_string(),
268+
];
269+
assert_eq!(2, parse_cidr_blocks(&input).len());
254270
}

src/controllers/helpers/pagination.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use diesel::query_dsl::LoadQuery;
1212
use diesel::sql_types::BigInt;
1313
use indexmap::IndexMap;
1414
use serde::{Deserialize, Serialize};
15-
use std::net::Ipv4Addr;
15+
use std::net::IpAddr;
1616
use std::str::FromStr;
1717
use std::sync::Arc;
1818

@@ -274,7 +274,7 @@ fn is_useragent_or_ip_blocked(config: &Server, req: &dyn RequestExt) -> bool {
274274
}
275275

276276
// check if client ip is blocked, needs to be an IPv4 address
277-
if let Ok(client_ip) = Ipv4Addr::from_str(client_ip) {
277+
if let Ok(client_ip) = IpAddr::from_str(client_ip) {
278278
if config
279279
.page_offset_cidr_blocklist
280280
.iter()

src/tests/krate/search.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use cargo_registry::models::Category;
55
use cargo_registry::schema::crates;
66
use diesel::{dsl::*, prelude::*, update};
77
use http::StatusCode;
8-
use ipnetwork::Ipv4Network;
8+
use ipnetwork::IpNetwork;
99

1010
#[test]
1111
fn index() {
@@ -829,8 +829,7 @@ fn pagination_blocks_ip_from_cidr_block_list() {
829829
let (app, anon, user) = TestApp::init()
830830
.with_config(|config| {
831831
config.max_allowed_page_offset = 1;
832-
config.page_offset_cidr_blocklist =
833-
vec!["127.0.0.1/24".parse::<Ipv4Network>().unwrap()];
832+
config.page_offset_cidr_blocklist = vec!["127.0.0.1/24".parse::<IpNetwork>().unwrap()];
834833
})
835834
.with_user();
836835
let user = user.as_model();

0 commit comments

Comments
 (0)