diff --git a/src/config_models/mod.rs b/src/config_models/mod.rs index c6f7b49..62f4012 100644 --- a/src/config_models/mod.rs +++ b/src/config_models/mod.rs @@ -20,10 +20,16 @@ pub struct VlessOutboundSettings { pub vnext: Vec, } +#[derive(Serialize, Deserialize)] +pub struct VmessOutboundSettings { + pub vnext: Vec, +} + #[derive(Serialize, Deserialize)] #[serde(untagged)] pub enum OutboundSettings { Vless(VlessOutboundSettings), + Vmess(VmessOutboundSettings), } #[derive(Serialize, Deserialize)] diff --git a/src/parser/mod.rs b/src/parser/mod.rs index a44ed2e..6675b37 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -7,6 +7,7 @@ use crate::utils::{inbound_generator, parse_raw_json}; mod uri_identifier; mod vless; +mod vmess; pub fn create_json_config(uri: &str, socks_port: Option, http_port: Option) -> String { let config = create_config(uri, socks_port, http_port); @@ -40,6 +41,11 @@ pub fn create_outbound_object(uri: &str) -> config_models::Outbound { let s = vless::create_outbound_settings(&d); (String::from("vless"), d, s) } + Some(uri_identifier::Protocols::Vmess) => { + let d = vmess::data::get_data(uri); + let s = vmess::create_outbound_settings(&d); + (String::from("vmess"), d, s) + } Some(_) => { panic!("The protocol was recognized but is not supported yet"); } diff --git a/src/parser/vless/data.rs b/src/parser/vless/data.rs index b39c99d..5c71ba1 100644 --- a/src/parser/vless/data.rs +++ b/src/parser/vless/data.rs @@ -59,33 +59,3 @@ fn parse_vless_address(raw_data: &str) -> models::VlessAddress { port: parsed.port().unwrap().as_u16(), }; } - -fn parse_vless_query(raw_query: &str) -> models::VlessQuery { - let query: Vec<(&str, &str)> = querystring::querify(raw_query); - - let a = models::VlessQuery { - alpn: url_decode(get_parameter_value(&query, "alpn")), - path: url_decode(get_parameter_value(&query, "path")), - authority: url_decode(get_parameter_value(&query, "authority")), - pbk: url_decode(get_parameter_value(&query, "pbk")), - security: get_parameter_value(&query, "security"), - sid: url_decode(get_parameter_value(&query, "sid")), - flow: get_parameter_value(&query, "flow"), - sni: get_parameter_value(&query, "sni"), - fp: url_decode(get_parameter_value(&query, "fp")), - r#type: get_parameter_value(&query, "type"), - encryption: get_parameter_value(&query, "encryption"), - header_type: get_parameter_value(&query, "headerType"), - host: url_decode(get_parameter_value(&query, "host")), - seed: url_decode(get_parameter_value(&query, "seed")), - quic_security: get_parameter_value(&query, "quicSecurity"), - key: get_parameter_value(&query, "key"), - mode: url_decode(get_parameter_value(&query, "mode")), - service_name: url_decode(get_parameter_value(&query, "serviceName")), - slpn: get_parameter_value(&query, "slpn"), - spx: url_decode(get_parameter_value(&query, "spx")), - extra: url_decode(get_parameter_value(&query, "extra")), - allowInsecure: get_parameter_value(&query, "allowInsecure"), - }; - return a; -} diff --git a/src/parser/vmess/data.rs b/src/parser/vmess/data.rs new file mode 100644 index 0000000..7314ca7 --- /dev/null +++ b/src/parser/vmess/data.rs @@ -0,0 +1,61 @@ +use crate::config_models::RawData; +use crate::parser::vmess::models::{self, VmessAddress}; +use crate::utils::{get_parameter_value, url_decode}; +use http::Uri; + +pub fn get_data(uri: &str) -> RawData { + let data = uri.split_once("vmess://").unwrap().1; + let query_and_name = uri.split_once("?").unwrap().1; + let raw_query = query_and_name + .split_once("#") + .unwrap_or((query_and_name, "")) + .0; + let parsed_address = parse_vmess_address(data.split_once("?").unwrap().0); + let query: Vec<(&str, &str)> = querystring::querify(raw_query); + + return RawData { + uuid: Some(parsed_address.uuid), + port: Some(parsed_address.port), + address: Some(parsed_address.address), + alpn: url_decode(get_parameter_value(&query, "alpn")), + path: url_decode(get_parameter_value(&query, "path")), + authority: url_decode(get_parameter_value(&query, "authority")), + pbk: url_decode(get_parameter_value(&query, "pbk")), + security: get_parameter_value(&query, "security"), + sid: url_decode(get_parameter_value(&query, "sid")), + flow: get_parameter_value(&query, "flow"), + sni: get_parameter_value(&query, "sni"), + fp: url_decode(get_parameter_value(&query, "fp")), + r#type: get_parameter_value(&query, "type"), + encryption: get_parameter_value(&query, "encryption"), + header_type: get_parameter_value(&query, "headerType"), + host: url_decode(get_parameter_value(&query, "host")), + seed: url_decode(get_parameter_value(&query, "seed")), + quic_security: get_parameter_value(&query, "quicSecurity"), + key: get_parameter_value(&query, "key"), + mode: url_decode(get_parameter_value(&query, "mode")), + service_name: url_decode(get_parameter_value(&query, "serviceName")), + slpn: get_parameter_value(&query, "slpn"), + spx: url_decode(get_parameter_value(&query, "spx")), + extra: url_decode(get_parameter_value(&query, "extra")), + allowInsecure: get_parameter_value(&query, "allowInsecure"), + }; +} + +fn parse_vmess_address(raw_data: &str) -> VmessAddress { + let (uuid, raw_address): (String, &str) = match raw_data.split_once("@") { + None => { + panic!("Wrong vmess format, no `@` found in the address"); + } + Some(data) => (String::from(data.0), data.1), + }; + let address_wo_slash = raw_address.strip_suffix("/").unwrap_or(raw_address); + + let parsed = address_wo_slash.parse::().unwrap(); + + return VmessAddress { + uuid: url_decode(Some(uuid)).unwrap(), + address: parsed.host().unwrap().to_string(), + port: parsed.port().unwrap().as_u16(), + }; +} diff --git a/src/parser/vmess/mod.rs b/src/parser/vmess/mod.rs new file mode 100644 index 0000000..94f30fe --- /dev/null +++ b/src/parser/vmess/mod.rs @@ -0,0 +1,18 @@ +pub mod data; +mod models; +use crate::{config_models::*, utils::parse_raw_json}; + +pub fn create_outbound_settings(data: &RawData) -> OutboundSettings { + return OutboundSettings::Vmess(VmessOutboundSettings { + vnext: vec![VlessServerObject { + port: data.port, + address: data.address.clone(), + users: Some(vec![VlessUser { + id: data.uuid.clone(), + flow: data.flow.clone(), + encryption: Some(data.encryption.clone().unwrap_or(String::from("none"))), + level: Some(0), + }]), + }], + }); +} diff --git a/src/parser/vmess/models.rs b/src/parser/vmess/models.rs new file mode 100644 index 0000000..6cf317b --- /dev/null +++ b/src/parser/vmess/models.rs @@ -0,0 +1,5 @@ +pub struct VmessAddress { + pub uuid: String, + pub address: String, + pub port: u16, +}