Skip to content

Commit 4943877

Browse files
rossoschwald
authored andcommitted
bytes_and_prefix_to_net detect v4 in v6, within city test
1 parent 5580183 commit 4943877

File tree

2 files changed

+87
-12
lines changed

2 files changed

+87
-12
lines changed

src/maxminddb/lib.rs

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -453,18 +453,42 @@ fn ip_to_bytes(address: IpAddr) -> Vec<u8> {
453453
}
454454

455455
fn bytes_and_prefix_to_net(bytes: &Vec<u8>, prefix: u8) -> Result<IpNetwork, MaxMindDBError> {
456-
let ip = match bytes.len() {
457-
4 => IpAddr::V4(Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3])),
456+
let (ip, pre) = match bytes.len() {
457+
4 => (
458+
IpAddr::V4(Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3])),
459+
prefix,
460+
),
458461
16 => {
459-
let a = (bytes[0] as u16) << 8 | bytes[1] as u16;
460-
let b = (bytes[2] as u16) << 8 | bytes[3] as u16;
461-
let c = (bytes[4] as u16) << 8 | bytes[5] as u16;
462-
let d = (bytes[6] as u16) << 8 | bytes[7] as u16;
463-
let e = (bytes[8] as u16) << 8 | bytes[9] as u16;
464-
let f = (bytes[10] as u16) << 8 | bytes[11] as u16;
465-
let g = (bytes[12] as u16) << 8 | bytes[13] as u16;
466-
let h = (bytes[14] as u16) << 8 | bytes[15] as u16;
467-
IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h))
462+
if bytes[0] == 0
463+
&& bytes[1] == 0
464+
&& bytes[2] == 0
465+
&& bytes[3] == 0
466+
&& bytes[4] == 0
467+
&& bytes[5] == 0
468+
&& bytes[6] == 0
469+
&& bytes[7] == 0
470+
&& bytes[8] == 0
471+
&& bytes[9] == 0
472+
&& bytes[10] == 0
473+
&& bytes[11] == 0
474+
{
475+
// It's actually v4, but in v6 form, convert would be nice if ipnetwork had this
476+
// logic.
477+
(
478+
IpAddr::V4(Ipv4Addr::new(bytes[12], bytes[13], bytes[14], bytes[15])),
479+
prefix - 96,
480+
)
481+
} else {
482+
let a = (bytes[0] as u16) << 8 | bytes[1] as u16;
483+
let b = (bytes[2] as u16) << 8 | bytes[3] as u16;
484+
let c = (bytes[4] as u16) << 8 | bytes[5] as u16;
485+
let d = (bytes[6] as u16) << 8 | bytes[7] as u16;
486+
let e = (bytes[8] as u16) << 8 | bytes[9] as u16;
487+
let f = (bytes[10] as u16) << 8 | bytes[11] as u16;
488+
let g = (bytes[12] as u16) << 8 | bytes[13] as u16;
489+
let h = (bytes[14] as u16) << 8 | bytes[15] as u16;
490+
(IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h)), prefix)
491+
}
468492
}
469493
// This should never happen
470494
_ => {
@@ -473,7 +497,7 @@ fn bytes_and_prefix_to_net(bytes: &Vec<u8>, prefix: u8) -> Result<IpNetwork, Max
473497
))
474498
}
475499
};
476-
IpNetwork::new(ip, prefix).map_err(|e| MaxMindDBError::InvalidNetworkError(e.to_string()))
500+
IpNetwork::new(ip, pre).map_err(|e| MaxMindDBError::InvalidNetworkError(e.to_string()))
477501
}
478502

479503
fn find_metadata_start(buf: &[u8]) -> Result<usize, MaxMindDBError> {

src/maxminddb/reader_test.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,57 @@ fn test_lookup_asn() {
335335
assert_eq!(asn.autonomous_system_organization, Some("Telstra Pty Ltd"));
336336
}
337337

338+
#[test]
339+
fn test_within_city() {
340+
use super::geoip2::City;
341+
use super::Within;
342+
use ipnetwork::IpNetwork;
343+
344+
let _ = env_logger::try_init();
345+
346+
let filename = "test-data/test-data/GeoIP2-City-Test.mmdb";
347+
348+
let reader = Reader::open_readfile(filename).unwrap();
349+
350+
let ip_net = IpNetwork::V6("::/0".parse().unwrap());
351+
352+
let mut iter: Within<City, _> = reader.within(ip_net).unwrap();
353+
354+
// Make sure the first is what we expect it to be
355+
let item = iter.next().unwrap().unwrap();
356+
assert_eq!(
357+
item.ip_net,
358+
IpNetwork::V4("2.125.160.216/29".parse().unwrap())
359+
);
360+
assert_eq!(item.info.continent.unwrap().code, Some("EU"));
361+
assert_eq!(item.info.country.unwrap().iso_code, Some("GB"));
362+
363+
let mut n = 1;
364+
while let Some(_) = iter.next() {
365+
n += 1;
366+
}
367+
368+
// Make sure we had the expected number
369+
assert_eq!(n, 273);
370+
371+
// A second run through this time a specific network
372+
let specific = IpNetwork::V4("81.2.69.0/24".parse().unwrap());
373+
let mut iter: Within<City, _> = reader.within(specific).unwrap();
374+
// Make sure we have the expected blocks/info
375+
let mut expected = vec![
376+
// Note: reversed so we can use pop
377+
IpNetwork::V4("81.2.69.192/28".parse().unwrap()),
378+
IpNetwork::V4("81.2.69.160/27".parse().unwrap()),
379+
IpNetwork::V4("81.2.69.144/28".parse().unwrap()),
380+
IpNetwork::V4("81.2.69.142/31".parse().unwrap()),
381+
];
382+
while expected.len() > 0 {
383+
let e = expected.pop().unwrap();
384+
let item = iter.next().unwrap().unwrap();
385+
assert_eq!(item.ip_net, e);
386+
}
387+
}
388+
338389
fn check_metadata<T: AsRef<[u8]>>(reader: &Reader<T>, ip_version: usize, record_size: usize) {
339390
let metadata = &reader.metadata;
340391

0 commit comments

Comments
 (0)