mirror of
https://github.com/house-of-vanity/v2-uri-parser.git
synced 2025-12-16 06:57:52 +00:00
Parse socks
This commit is contained in:
@@ -9,6 +9,12 @@ pub struct VnextUser {
|
|||||||
pub security: Option<String>,
|
pub security: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct SocksUser {
|
||||||
|
pub user: Option<String>,
|
||||||
|
pub pass: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct VnextServerObject {
|
pub struct VnextServerObject {
|
||||||
pub address: Option<String>,
|
pub address: Option<String>,
|
||||||
@@ -33,6 +39,14 @@ pub struct ShadowSocksServerObject {
|
|||||||
pub method: Option<String>,
|
pub method: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct SocksServerObject {
|
||||||
|
pub address: Option<String>,
|
||||||
|
pub port: Option<u16>,
|
||||||
|
pub level: Option<u8>,
|
||||||
|
pub users: Option<Vec<SocksUser>>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct VlessOutboundSettings {
|
pub struct VlessOutboundSettings {
|
||||||
pub vnext: Vec<VnextServerObject>,
|
pub vnext: Vec<VnextServerObject>,
|
||||||
@@ -53,6 +67,11 @@ pub struct ShadowSocksOutboundSettings {
|
|||||||
pub servers: Vec<ShadowSocksServerObject>,
|
pub servers: Vec<ShadowSocksServerObject>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct SocksOutboundSettings {
|
||||||
|
pub servers: Vec<SocksServerObject>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum OutboundSettings {
|
pub enum OutboundSettings {
|
||||||
@@ -60,6 +79,7 @@ pub enum OutboundSettings {
|
|||||||
Vmess(VmessOutboundSettings),
|
Vmess(VmessOutboundSettings),
|
||||||
Trojan(TrojanOutboundSettings),
|
Trojan(TrojanOutboundSettings),
|
||||||
ShadowSocks(ShadowSocksOutboundSettings),
|
ShadowSocks(ShadowSocksOutboundSettings),
|
||||||
|
Socks(SocksOutboundSettings),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@@ -243,4 +263,5 @@ pub struct RawData {
|
|||||||
pub address: Option<String>,
|
pub address: Option<String>,
|
||||||
pub port: Option<u16>,
|
pub port: Option<u16>,
|
||||||
pub server_method: Option<String>,
|
pub server_method: Option<String>,
|
||||||
|
pub username: Option<String>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use crate::config_models::{
|
|||||||
use crate::utils::{inbound_generator, parse_raw_json};
|
use crate::utils::{inbound_generator, parse_raw_json};
|
||||||
|
|
||||||
mod shadow_socks;
|
mod shadow_socks;
|
||||||
|
mod socks;
|
||||||
mod trojan;
|
mod trojan;
|
||||||
mod uri_identifier;
|
mod uri_identifier;
|
||||||
mod vless;
|
mod vless;
|
||||||
@@ -174,6 +175,11 @@ fn get_uri_data(uri: &str) -> (String, RawData, OutboundSettings) {
|
|||||||
let s = shadow_socks::create_outbound_settings(&d);
|
let s = shadow_socks::create_outbound_settings(&d);
|
||||||
(String::from("shadowsocks"), d, s)
|
(String::from("shadowsocks"), d, s)
|
||||||
}
|
}
|
||||||
|
Some(uri_identifier::Protocols::Socks) => {
|
||||||
|
let d = socks::data::get_data(uri);
|
||||||
|
let s = socks::create_outbound_settings(&d);
|
||||||
|
(String::from("socks"), d, s)
|
||||||
|
}
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
panic!("The protocol was recognized but is not supported yet");
|
panic!("The protocol was recognized but is not supported yet");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ pub fn get_data(uri: &str) -> RawData {
|
|||||||
quic_security: None,
|
quic_security: None,
|
||||||
allowInsecure: None,
|
allowInsecure: None,
|
||||||
vnext_security: None,
|
vnext_security: None,
|
||||||
|
username: None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
87
src/parser/socks/data.rs
Normal file
87
src/parser/socks/data.rs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
use http::Uri;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
config_models::RawData,
|
||||||
|
parser::socks::models,
|
||||||
|
utils::{url_decode, url_decode_str},
|
||||||
|
};
|
||||||
|
use base64::{engine::general_purpose, Engine};
|
||||||
|
|
||||||
|
pub fn get_data(uri: &str) -> RawData {
|
||||||
|
let data = uri.split_once("://").unwrap().1;
|
||||||
|
let (raw_data, name) = data.split_once("#").unwrap_or((data, ""));
|
||||||
|
let (raw_uri, _) = raw_data.split_once("?").unwrap_or((raw_data, ""));
|
||||||
|
let parsed_address = parse_socks_address(raw_uri);
|
||||||
|
return RawData {
|
||||||
|
remarks: url_decode(Some(String::from(name))).unwrap_or(String::from("")),
|
||||||
|
username: url_decode(parsed_address.username),
|
||||||
|
address: Some(parsed_address.address),
|
||||||
|
port: Some(parsed_address.port),
|
||||||
|
uuid: url_decode(parsed_address.password),
|
||||||
|
r#type: Some(String::from("tcp")),
|
||||||
|
header_type: None,
|
||||||
|
server_method: None,
|
||||||
|
security: None,
|
||||||
|
fp: None,
|
||||||
|
sni: None,
|
||||||
|
pbk: None,
|
||||||
|
sid: None,
|
||||||
|
key: None,
|
||||||
|
spx: None,
|
||||||
|
flow: None,
|
||||||
|
path: None,
|
||||||
|
host: None,
|
||||||
|
seed: None,
|
||||||
|
mode: None,
|
||||||
|
slpn: None,
|
||||||
|
alpn: None,
|
||||||
|
extra: None,
|
||||||
|
authority: None,
|
||||||
|
encryption: None,
|
||||||
|
service_name: None,
|
||||||
|
quic_security: None,
|
||||||
|
allowInsecure: None,
|
||||||
|
vnext_security: None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_socks_address(raw_data: &str) -> models::SocksAddress {
|
||||||
|
let (maybe_userinfo, raw_address): (Option<String>, &str) = match raw_data.split_once("@") {
|
||||||
|
Some(data) => (Some(String::from(data.0)), data.1),
|
||||||
|
None => (None, raw_data),
|
||||||
|
};
|
||||||
|
let address_wo_slash = raw_address.strip_suffix("/").unwrap_or(raw_address);
|
||||||
|
|
||||||
|
let parsed = address_wo_slash.parse::<Uri>().unwrap();
|
||||||
|
|
||||||
|
return match maybe_userinfo {
|
||||||
|
Some(userinfo) => {
|
||||||
|
let url_decoded = url_decode_str(&userinfo).unwrap_or(userinfo);
|
||||||
|
let a = general_purpose::STANDARD
|
||||||
|
.decode(url_decoded.clone())
|
||||||
|
.map(|a| {
|
||||||
|
String::from(
|
||||||
|
std::str::from_utf8(&a).expect("Base64 did not yield a valid utf-8 string"),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap_or(String::from(url_decoded.clone()));
|
||||||
|
|
||||||
|
let (username, password) = a
|
||||||
|
.split_once(":")
|
||||||
|
.expect("No `:` found in the decoded base64");
|
||||||
|
|
||||||
|
models::SocksAddress {
|
||||||
|
username: Some(String::from(username)),
|
||||||
|
password: Some(String::from(password)),
|
||||||
|
address: parsed.host().unwrap().to_string(),
|
||||||
|
port: parsed.port().unwrap().as_u16(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => models::SocksAddress {
|
||||||
|
username: None,
|
||||||
|
password: None,
|
||||||
|
address: parsed.host().unwrap().to_string(),
|
||||||
|
port: parsed.port().unwrap().as_u16(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
20
src/parser/socks/mod.rs
Normal file
20
src/parser/socks/mod.rs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
pub mod data;
|
||||||
|
mod models;
|
||||||
|
use crate::config_models::*;
|
||||||
|
|
||||||
|
pub fn create_outbound_settings(data: &RawData) -> OutboundSettings {
|
||||||
|
return OutboundSettings::Socks(SocksOutboundSettings {
|
||||||
|
servers: vec![SocksServerObject {
|
||||||
|
users: match (&data.username, &data.uuid) {
|
||||||
|
(Some(username), Some(uuid)) => Some(vec![SocksUser {
|
||||||
|
user: Some(username.clone()),
|
||||||
|
pass: Some(uuid.clone()),
|
||||||
|
}]),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
address: data.address.clone(),
|
||||||
|
port: data.port,
|
||||||
|
level: Some(0),
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
}
|
||||||
6
src/parser/socks/models.rs
Normal file
6
src/parser/socks/models.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
pub struct SocksAddress {
|
||||||
|
pub password: Option<String>,
|
||||||
|
pub username: Option<String>,
|
||||||
|
pub address: String,
|
||||||
|
pub port: u16,
|
||||||
|
}
|
||||||
@@ -41,6 +41,7 @@ pub fn get_data(uri: &str) -> RawData {
|
|||||||
extra: url_decode(get_parameter_value(&query, "extra")),
|
extra: url_decode(get_parameter_value(&query, "extra")),
|
||||||
allowInsecure: get_parameter_value(&query, "allowInsecure"),
|
allowInsecure: get_parameter_value(&query, "allowInsecure"),
|
||||||
server_method: None,
|
server_method: None,
|
||||||
|
username: None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,6 @@ pub enum Protocols {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_uri_protocol(uri: &str) -> Option<Protocols> {
|
pub fn get_uri_protocol(uri: &str) -> Option<Protocols> {
|
||||||
let uri_regex = Regex::new(r"^[a-z]+:\/\/.+$").unwrap();
|
|
||||||
if !uri_regex.is_match(uri) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if uri.starts_with("vmess://") {
|
if uri.starts_with("vmess://") {
|
||||||
return Some(Protocols::Vmess);
|
return Some(Protocols::Vmess);
|
||||||
}
|
}
|
||||||
@@ -23,7 +19,7 @@ pub fn get_uri_protocol(uri: &str) -> Option<Protocols> {
|
|||||||
if uri.starts_with("ss://") {
|
if uri.starts_with("ss://") {
|
||||||
return Some(Protocols::Shadowsocks);
|
return Some(Protocols::Shadowsocks);
|
||||||
}
|
}
|
||||||
if uri.starts_with("socks://") {
|
if uri.starts_with("socks5://") || uri.starts_with("socks4://") || uri.starts_with("socks://") {
|
||||||
return Some(Protocols::Socks);
|
return Some(Protocols::Socks);
|
||||||
}
|
}
|
||||||
if uri.starts_with("http://") {
|
if uri.starts_with("http://") {
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ pub fn get_data(uri: &str) -> RawData {
|
|||||||
extra: url_decode(get_parameter_value(&query, "extra")),
|
extra: url_decode(get_parameter_value(&query, "extra")),
|
||||||
allowInsecure: get_parameter_value(&query, "allowInsecure"),
|
allowInsecure: get_parameter_value(&query, "allowInsecure"),
|
||||||
server_method: None,
|
server_method: None,
|
||||||
|
username:None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ fn get_raw_data_from_base64(decoded_base64: &Vec<u8>) -> RawData {
|
|||||||
// this probably does not exist in vmess uri
|
// this probably does not exist in vmess uri
|
||||||
allowInsecure: None,
|
allowInsecure: None,
|
||||||
server_method: None,
|
server_method: None,
|
||||||
|
username: None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,6 +105,7 @@ fn get_raw_data_from_uri(uri: &str) -> RawData {
|
|||||||
extra: url_decode(get_parameter_value(&query, "extra")),
|
extra: url_decode(get_parameter_value(&query, "extra")),
|
||||||
allowInsecure: get_parameter_value(&query, "allowInsecure"),
|
allowInsecure: get_parameter_value(&query, "allowInsecure"),
|
||||||
server_method: None,
|
server_method: None,
|
||||||
|
username: None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user