Refactor: Fully migrated parser to full prost crate, auto-fmt; Fix: Remove no more needed tests
This commit is contained in:
parent
c1bf670152
commit
0d81bae32a
8 changed files with 75 additions and 96 deletions
|
|
@ -8,9 +8,10 @@ use std::net::IpAddr;
|
||||||
// TODO: V2Ray protobuf parsing && Test 4 ts
|
// TODO: V2Ray protobuf parsing && Test 4 ts
|
||||||
|
|
||||||
/// Interface enum for `dst_addr` info
|
/// Interface enum for `dst_addr` info
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub enum RouteType {
|
pub enum RouteType {
|
||||||
/// GeoSite MMDB type, like `category-ads-all`
|
/// GeoSite type, like `category-ads-all`
|
||||||
GeoSite(String),
|
GeoSite(String),
|
||||||
/// Result with GeoCode like "RU"
|
/// Result with GeoCode like "RU"
|
||||||
GeoIp(String),
|
GeoIp(String),
|
||||||
|
|
@ -18,6 +19,7 @@ pub enum RouteType {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Routing actions
|
/// Routing actions
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub enum RouteAction {
|
pub enum RouteAction {
|
||||||
#[serde(alias = "block")]
|
#[serde(alias = "block")]
|
||||||
|
|
|
||||||
40
src/geoparsers/geosite.rs
Normal file
40
src/geoparsers/geosite.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
use crate::geoparsers::v2ray::parsing::decode_geosite_stream;
|
||||||
|
use crate::geoparsers::v2ray::types::{GeoSite, GeoSiteList};
|
||||||
|
|
||||||
|
use std::fs;
|
||||||
|
use std::io::{BufReader, Read};
|
||||||
|
|
||||||
|
pub struct GeoSiteService {
|
||||||
|
index: GeoSiteList,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GeoSiteService {
|
||||||
|
// TODO: Make more smart memory mapping; geosite files can be > 70MB
|
||||||
|
pub fn new(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
|
let file = fs::File::open(path)?;
|
||||||
|
let reader = BufReader::new(file);
|
||||||
|
let geosite_list = decode_geosite_stream(reader)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
index: geosite_list,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Idk but i think it can work
|
||||||
|
pub fn lookup(&self, value: &str) -> Option<&GeoSite> {
|
||||||
|
self.index
|
||||||
|
.entry
|
||||||
|
.iter()
|
||||||
|
.find(|site| site.domain.iter().any(|d| d.value == value))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of GeoSite entries in the list
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.index.entry.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the GeoSite list is empty
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.index.entry.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
pub mod geoip2;
|
pub mod geoip2;
|
||||||
|
pub mod geosite;
|
||||||
pub mod toml;
|
pub mod toml;
|
||||||
pub mod v2ray;
|
pub mod v2ray;
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
pub mod parsing;
|
pub(crate) mod parsing;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
|
||||||
|
|
@ -1,79 +1,15 @@
|
||||||
use crate::geoparsers::v2ray::types::{Domain, GeoSite, GeoSiteList};
|
use crate::geoparsers::v2ray::types::GeoSiteList;
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
use prost::bytes::Buf;
|
use std::io::Read;
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
pub struct GeoSiteService {
|
/// Decodes full geosite protobuf; TODO: MMAP
|
||||||
index: GeoSiteList,
|
pub fn decode_geosite_stream<R: Read>(
|
||||||
}
|
mut reader: R,
|
||||||
|
) -> Result<GeoSiteList, Box<dyn std::error::Error>> {
|
||||||
impl GeoSiteService {
|
let mut buf = Vec::new();
|
||||||
// TODO: Make more smart memory mapping; geosite files can be > 70MB
|
reader.read_to_end(&mut buf)?;
|
||||||
pub fn new(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
|
||||||
let bytes = fs::read(path)?;
|
let list = GeoSiteList::decode(&buf[..])?;
|
||||||
let geosite_list = decode_geosite_stream(&bytes)?;
|
|
||||||
|
Ok(list)
|
||||||
Ok(Self {
|
|
||||||
index: geosite_list,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Idk but i think it can work
|
|
||||||
pub fn lookup(&self, value: &str) -> Option<&GeoSite> {
|
|
||||||
self.index
|
|
||||||
.entry
|
|
||||||
.iter()
|
|
||||||
.find(|site| site.domain.iter().any(|d| d.value == value))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the number of GeoSite entries in the list
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.index.entry.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the GeoSite list is empty
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.index.entry.is_empty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Decode a stream of length-delimited GeoSite messages
|
|
||||||
/// `geosite.dat` ts is not one protobuf-message, stream of length-delimited messages
|
|
||||||
/// so we need ts helper
|
|
||||||
fn decode_geosite_stream(bytes: &[u8]) -> Result<GeoSiteList, Box<dyn std::error::Error>> {
|
|
||||||
let mut buf = bytes;
|
|
||||||
let mut entries = Vec::new();
|
|
||||||
|
|
||||||
while buf.has_remaining() {
|
|
||||||
// Read tag (0x0a field 1, wire type 2)
|
|
||||||
let tag = buf.get_u8();
|
|
||||||
if tag != 0x0a {
|
|
||||||
return Err(format!("Unexpected tag: {:#04x}", tag).into());
|
|
||||||
}
|
|
||||||
// varint
|
|
||||||
let mut len = 0usize;
|
|
||||||
let mut shift = 0;
|
|
||||||
loop {
|
|
||||||
if !buf.has_remaining() {
|
|
||||||
return Err("Unexpected end of buffer while reading varint".into());
|
|
||||||
}
|
|
||||||
let b = buf.get_u8();
|
|
||||||
len |= ((b & 0x7f) as usize) << shift;
|
|
||||||
if b & 0x80 == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
shift += 7;
|
|
||||||
if shift >= 70 {
|
|
||||||
return Err("Varint too long".into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let entry_bytes = &buf[..len];
|
|
||||||
let site = GeoSite::decode(entry_bytes)?;
|
|
||||||
entries.push(site);
|
|
||||||
|
|
||||||
buf.advance(len);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(GeoSiteList { entry: entries })
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,17 +33,7 @@ pub mod domain {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Type of domain value.
|
/// Type of domain value.
|
||||||
#[derive(
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||||
Clone,
|
|
||||||
Copy,
|
|
||||||
Debug,
|
|
||||||
PartialEq,
|
|
||||||
Eq,
|
|
||||||
Hash,
|
|
||||||
PartialOrd,
|
|
||||||
Ord,
|
|
||||||
::prost::Enumeration
|
|
||||||
)]
|
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
/// The value is used as is.
|
/// The value is used as is.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use nsc::geoparsers::v2ray::parsing::GeoSiteService;
|
use nsc::geoparsers::geosite::GeoSiteService;
|
||||||
use nsc::geoparsers::v2ray::types::Domain;
|
use nsc::geoparsers::v2ray::types::{Domain, domain};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
|
@ -7,11 +7,11 @@ fn download_geosite() -> Result<PathBuf, Box<dyn std::error::Error>> {
|
||||||
let tmp_dir = std::env::temp_dir().join("seccontrol_test");
|
let tmp_dir = std::env::temp_dir().join("seccontrol_test");
|
||||||
fs::create_dir_all(&tmp_dir)?;
|
fs::create_dir_all(&tmp_dir)?;
|
||||||
|
|
||||||
let geosite_path = tmp_dir.join("geosite.dat");
|
let geosite_path = tmp_dir.join("dlc.dat");
|
||||||
|
|
||||||
if !geosite_path.exists() {
|
if !geosite_path.exists() {
|
||||||
// Use v2fly domain-list-community which has standard protobuf format
|
// Use v2fly domain-list-community which has standard protobuf format
|
||||||
let url = "https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat";
|
let url = "https://github.com/v2fly/domain-list-community/releases/download/20260330021310/dlc.dat";
|
||||||
let response = ureq::get(url).call()?;
|
let response = ureq::get(url).call()?;
|
||||||
let mut file = fs::File::create(&geosite_path)?;
|
let mut file = fs::File::create(&geosite_path)?;
|
||||||
let mut reader = response.into_reader();
|
let mut reader = response.into_reader();
|
||||||
|
|
@ -41,6 +41,16 @@ fn geosite_service_creation() {
|
||||||
fn lookup_existing_domain() {
|
fn lookup_existing_domain() {
|
||||||
let service = get_geosite_service().expect("Failed to create service");
|
let service = get_geosite_service().expect("Failed to create service");
|
||||||
|
|
||||||
|
let domain = Domain {
|
||||||
|
r#type: nsc::geoparsers::v2ray::types::domain::Type::Full as i32,
|
||||||
|
value: "google.com".to_string(),
|
||||||
|
attribute: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = service.lookup(domain.value.as_str());
|
||||||
|
assert!(result.is_some(), "Should return GeoSite categs");
|
||||||
|
println!("{:?}", result);
|
||||||
|
|
||||||
assert!(!service.is_empty(), "Service should have entries");
|
assert!(!service.is_empty(), "Service should have entries");
|
||||||
println!("Loaded {} GeoSite entries", service.len());
|
println!("Loaded {} GeoSite entries", service.len());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue