v0.31.8
This commit is contained in:
1 parent
68ada6680d
commit
180a0e4877
56 files changed
+9866
-205
No files matched your search
+13
-9
@@ -29,8 +29,10 @@ struct V4Range {
|
||||
}
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct V6Range {
|
||||
start: u128,
|
||||
end: u128,
|
||||
// Network byte order preserves the numeric ordering of IPv6 addresses
|
||||
// without the 16-byte alignment/padding of u128 fields.
|
||||
start: [u8; 16],
|
||||
end: [u8; 16],
|
||||
country: [u8; 2],
|
||||
}
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
@@ -48,7 +50,7 @@ impl Default for DatabaseFormat {
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Backend {
|
||||
Csv { ipv4: Vec<V4Range>, ipv6: Vec<V6Range> },
|
||||
Csv { ipv4: Box<[V4Range]>, ipv6: Box<[V6Range]> },
|
||||
Mmdb(mmdb::Database),
|
||||
}
|
||||
|
||||
@@ -66,7 +68,7 @@ pub struct View {
|
||||
}
|
||||
impl Database {
|
||||
pub fn empty() -> Self {
|
||||
Self { backend: Backend::Csv { ipv4: Vec::new(), ipv6: Vec::new() } }
|
||||
Self { backend: Backend::Csv { ipv4: Box::new([]), ipv6: Box::new([]) } }
|
||||
}
|
||||
pub fn load(directory: &Path) -> Result<Self> {
|
||||
if directory.join("country.mmdb").is_file() {
|
||||
@@ -81,7 +83,9 @@ impl Database {
|
||||
let ipv4 = parse_v4(&directory.join("user-country-ipv4.csv"))?;
|
||||
let ipv6 = parse_v6(&directory.join("user-country-ipv6.csv"))?;
|
||||
ensure!(!ipv4.is_empty() && !ipv6.is_empty(), "GeoIP country database is empty");
|
||||
Ok(Self { backend: Backend::Csv { ipv4, ipv6 } })
|
||||
// Convert to exactly sized immutable slices: the CSV parser may have
|
||||
// doubled Vec capacity many times during loading.
|
||||
Ok(Self { backend: Backend::Csv { ipv4: ipv4.into_boxed_slice(), ipv6: ipv6.into_boxed_slice() } })
|
||||
}
|
||||
DatabaseFormat::Mmdb => Ok(Self {
|
||||
backend: Backend::Mmdb(mmdb::Database::load(&directory.join("country.mmdb"), MAX_FILE_BYTES)?),
|
||||
@@ -118,7 +122,7 @@ impl Database {
|
||||
Backend::Csv { ipv4, ipv6 } => {
|
||||
let code = match ip {
|
||||
IpAddr::V4(ip) => find_v4(ipv4, u32::from(ip)),
|
||||
IpAddr::V6(ip) => find_v6(ipv6, u128::from(ip)),
|
||||
IpAddr::V6(ip) => find_v6(ipv6, u128::from(ip).to_be_bytes()),
|
||||
}?;
|
||||
Some(String::from_utf8_lossy(&code).into_owned())
|
||||
}
|
||||
@@ -227,8 +231,8 @@ fn parse_v6(path: &Path) -> Result<Vec<V6Range>> {
|
||||
previous_end = Some(end);
|
||||
if let Some(country) = normalize_country_code(country) {
|
||||
result.push(V6Range {
|
||||
start,
|
||||
end,
|
||||
start: start.to_be_bytes(),
|
||||
end: end.to_be_bytes(),
|
||||
country,
|
||||
});
|
||||
ensure!(result.len() <= MAX_RANGES, "too many GeoIP IPv6 ranges");
|
||||
@@ -243,7 +247,7 @@ fn find_v4(ranges: &[V4Range], ip: u32) -> Option<[u8; 2]> {
|
||||
let item = ranges.get(index)?;
|
||||
(ip <= item.end).then_some(item.country)
|
||||
}
|
||||
fn find_v6(ranges: &[V6Range], ip: u128) -> Option<[u8; 2]> {
|
||||
fn find_v6(ranges: &[V6Range], ip: [u8; 16]) -> Option<[u8; 2]> {
|
||||
let index = ranges
|
||||
.partition_point(|item| item.start <= ip)
|
||||
.checked_sub(1)?;
|
||||
|
||||
Reference in new issue
Block a user