| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392 |
- pub mod compress;
- pub mod platform;
- pub mod protos;
- pub use bytes;
- use config::Config;
- pub use futures;
- pub use protobuf;
- pub use protos::message as message_proto;
- pub use protos::rendezvous as rendezvous_proto;
- use std::{
- fs::File,
- io::{self, BufRead},
- net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4},
- path::Path,
- time::{self, SystemTime, UNIX_EPOCH},
- };
- pub use tokio;
- pub use tokio_util;
- pub mod socket_client;
- pub mod tcp;
- pub mod udp;
- pub use env_logger;
- pub use log;
- pub mod bytes_codec;
- #[cfg(feature = "quic")]
- pub mod quic;
- pub use anyhow::{self, bail};
- pub use futures_util;
- pub mod config;
- pub mod fs;
- pub use lazy_static;
- #[cfg(not(any(target_os = "android", target_os = "ios")))]
- pub use mac_address;
- pub use rand;
- pub use regex;
- pub use sodiumoxide;
- pub use tokio_socks;
- pub use tokio_socks::IntoTargetAddr;
- pub use tokio_socks::TargetAddr;
- pub mod password_security;
- pub use chrono;
- pub use directories_next;
- pub mod keyboard;
- #[cfg(feature = "quic")]
- pub type Stream = quic::Connection;
- #[cfg(not(feature = "quic"))]
- pub type Stream = tcp::FramedStream;
- #[inline]
- pub async fn sleep(sec: f32) {
- tokio::time::sleep(time::Duration::from_secs_f32(sec)).await;
- }
- #[macro_export]
- macro_rules! allow_err {
- ($e:expr) => {
- if let Err(err) = $e {
- log::debug!(
- "{:?}, {}:{}:{}:{}",
- err,
- module_path!(),
- file!(),
- line!(),
- column!()
- );
- } else {
- }
- };
- ($e:expr, $($arg:tt)*) => {
- if let Err(err) = $e {
- log::debug!(
- "{:?}, {}, {}:{}:{}:{}",
- err,
- format_args!($($arg)*),
- module_path!(),
- file!(),
- line!(),
- column!()
- );
- } else {
- }
- };
- }
- #[inline]
- pub fn timeout<T: std::future::Future>(ms: u64, future: T) -> tokio::time::Timeout<T> {
- tokio::time::timeout(std::time::Duration::from_millis(ms), future)
- }
- pub type ResultType<F, E = anyhow::Error> = anyhow::Result<F, E>;
- /// Certain router and firewalls scan the packet and if they
- /// find an IP address belonging to their pool that they use to do the NAT mapping/translation, so here we mangle the ip address
- pub struct AddrMangle();
- #[inline]
- pub fn try_into_v4(addr: SocketAddr) -> SocketAddr {
- match addr {
- SocketAddr::V6(v6) if !addr.ip().is_loopback() => {
- if let Some(v4) = v6.ip().to_ipv4() {
- SocketAddr::new(IpAddr::V4(v4), addr.port())
- } else {
- addr
- }
- }
- _ => addr,
- }
- }
- impl AddrMangle {
- pub fn encode(addr: SocketAddr) -> Vec<u8> {
- // not work with [:1]:<port>
- let addr = try_into_v4(addr);
- match addr {
- SocketAddr::V4(addr_v4) => {
- let tm = (SystemTime::now()
- .duration_since(UNIX_EPOCH)
- .unwrap()
- .as_micros() as u32) as u128;
- let ip = u32::from_le_bytes(addr_v4.ip().octets()) as u128;
- let port = addr.port() as u128;
- let v = ((ip + tm) << 49) | (tm << 17) | (port + (tm & 0xFFFF));
- let bytes = v.to_le_bytes();
- let mut n_padding = 0;
- for i in bytes.iter().rev() {
- if i == &0u8 {
- n_padding += 1;
- } else {
- break;
- }
- }
- bytes[..(16 - n_padding)].to_vec()
- }
- SocketAddr::V6(addr_v6) => {
- let mut x = addr_v6.ip().octets().to_vec();
- let port: [u8; 2] = addr_v6.port().to_le_bytes();
- x.push(port[0]);
- x.push(port[1]);
- x
- }
- }
- }
- pub fn decode(bytes: &[u8]) -> SocketAddr {
- use std::convert::TryInto;
- if bytes.len() > 16 {
- if bytes.len() != 18 {
- return Config::get_any_listen_addr(false);
- }
- let tmp: [u8; 2] = bytes[16..].try_into().unwrap();
- let port = u16::from_le_bytes(tmp);
- let tmp: [u8; 16] = bytes[..16].try_into().unwrap();
- let ip = std::net::Ipv6Addr::from(tmp);
- return SocketAddr::new(IpAddr::V6(ip), port);
- }
- let mut padded = [0u8; 16];
- padded[..bytes.len()].copy_from_slice(bytes);
- let number = u128::from_le_bytes(padded);
- let tm = (number >> 17) & (u32::max_value() as u128);
- let ip = (((number >> 49) - tm) as u32).to_le_bytes();
- let port = (number & 0xFFFFFF) - (tm & 0xFFFF);
- SocketAddr::V4(SocketAddrV4::new(
- Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]),
- port as u16,
- ))
- }
- }
- pub fn get_version_from_url(url: &str) -> String {
- let n = url.chars().count();
- let a = url.chars().rev().position(|x| x == '-');
- if let Some(a) = a {
- let b = url.chars().rev().position(|x| x == '.');
- if let Some(b) = b {
- if a > b {
- if url
- .chars()
- .skip(n - b)
- .collect::<String>()
- .parse::<i32>()
- .is_ok()
- {
- return url.chars().skip(n - a).collect();
- } else {
- return url.chars().skip(n - a).take(a - b - 1).collect();
- }
- } else {
- return url.chars().skip(n - a).collect();
- }
- }
- }
- "".to_owned()
- }
- pub fn gen_version() {
- println!("cargo:rerun-if-changed=Cargo.toml");
- use std::io::prelude::*;
- let mut file = File::create("./src/version.rs").unwrap();
- for line in read_lines("Cargo.toml").unwrap().flatten() {
- let ab: Vec<&str> = line.split('=').map(|x| x.trim()).collect();
- if ab.len() == 2 && ab[0] == "version" {
- file.write_all(format!("pub const VERSION: &str = {};\n", ab[1]).as_bytes())
- .ok();
- break;
- }
- }
- // generate build date
- let build_date = format!("{}", chrono::Local::now().format("%Y-%m-%d %H:%M"));
- file.write_all(
- format!("#[allow(dead_code)]\npub const BUILD_DATE: &str = \"{build_date}\";\n").as_bytes(),
- )
- .ok();
- file.sync_all().ok();
- }
- fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
- where
- P: AsRef<Path>,
- {
- let file = File::open(filename)?;
- Ok(io::BufReader::new(file).lines())
- }
- pub fn is_valid_custom_id(id: &str) -> bool {
- regex::Regex::new(r"^[a-zA-Z]\w{5,15}$")
- .unwrap()
- .is_match(id)
- }
- pub fn get_version_number(v: &str) -> i64 {
- let mut n = 0;
- for x in v.split('.') {
- n = n * 1000 + x.parse::<i64>().unwrap_or(0);
- }
- n
- }
- pub fn get_modified_time(path: &std::path::Path) -> SystemTime {
- std::fs::metadata(path)
- .map(|m| m.modified().unwrap_or(UNIX_EPOCH))
- .unwrap_or(UNIX_EPOCH)
- }
- pub fn get_created_time(path: &std::path::Path) -> SystemTime {
- std::fs::metadata(path)
- .map(|m| m.created().unwrap_or(UNIX_EPOCH))
- .unwrap_or(UNIX_EPOCH)
- }
- pub fn get_exe_time() -> SystemTime {
- std::env::current_exe().map_or(UNIX_EPOCH, |path| {
- let m = get_modified_time(&path);
- let c = get_created_time(&path);
- if m > c {
- m
- } else {
- c
- }
- })
- }
- pub fn get_uuid() -> Vec<u8> {
- #[cfg(not(any(target_os = "android", target_os = "ios")))]
- if let Ok(id) = machine_uid::get() {
- return id.into();
- }
- Config::get_key_pair().1
- }
- #[inline]
- pub fn get_time() -> i64 {
- std::time::SystemTime::now()
- .duration_since(std::time::UNIX_EPOCH)
- .map(|d| d.as_millis())
- .unwrap_or(0) as _
- }
- #[inline]
- pub fn is_ipv4_str(id: &str) -> bool {
- regex::Regex::new(r"^\d+\.\d+\.\d+\.\d+(:\d+)?$")
- .unwrap()
- .is_match(id)
- }
- #[inline]
- pub fn is_ipv6_str(id: &str) -> bool {
- regex::Regex::new(r"^((([a-fA-F0-9]{1,4}:{1,2})+[a-fA-F0-9]{1,4})|(\[([a-fA-F0-9]{1,4}:{1,2})+[a-fA-F0-9]{1,4}\]:\d+))$")
- .unwrap()
- .is_match(id)
- }
- #[inline]
- pub fn is_ip_str(id: &str) -> bool {
- is_ipv4_str(id) || is_ipv6_str(id)
- }
- #[inline]
- pub fn is_domain_port_str(id: &str) -> bool {
- // modified regex for RFC1123 hostname. check https://stackoverflow.com/a/106223 for original version for hostname.
- // according to [TLD List](https://data.iana.org/TLD/tlds-alpha-by-domain.txt) version 2023011700,
- // there is no digits in TLD, and length is 2~63.
- regex::Regex::new(
- r"(?i)^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z][a-z-]{0,61}[a-z]:\d{1,5}$",
- )
- .unwrap()
- .is_match(id)
- }
- #[cfg(test)]
- mod test {
- use super::*;
- #[test]
- fn test_mangle() {
- let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 16, 32), 21116));
- assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
- let addr = "[2001:db8::1]:8080".parse::<SocketAddr>().unwrap();
- assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
- let addr = "[2001:db8:ff::1111]:80".parse::<SocketAddr>().unwrap();
- assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
- }
- #[test]
- fn test_allow_err() {
- allow_err!(Err("test err") as Result<(), &str>);
- allow_err!(
- Err("test err with msg") as Result<(), &str>,
- "prompt {}",
- "failed"
- );
- }
- #[test]
- fn test_ipv6() {
- assert!(is_ipv6_str("1:2:3"));
- assert!(is_ipv6_str("[ab:2:3]:12"));
- assert!(is_ipv6_str("[ABEF:2a:3]:12"));
- assert!(!is_ipv6_str("[ABEG:2a:3]:12"));
- assert!(!is_ipv6_str("1[ab:2:3]:12"));
- assert!(!is_ipv6_str("1.1.1.1"));
- assert!(is_ip_str("1.1.1.1"));
- assert!(!is_ipv6_str("1:2:"));
- assert!(is_ipv6_str("1:2::0"));
- assert!(is_ipv6_str("[1:2::0]:1"));
- assert!(!is_ipv6_str("[1:2::0]:"));
- assert!(!is_ipv6_str("1:2::0]:1"));
- }
- #[test]
- fn test_hostname_port() {
- assert!(!is_domain_port_str("a:12"));
- assert!(!is_domain_port_str("a.b.c:12"));
- assert!(is_domain_port_str("test.com:12"));
- assert!(is_domain_port_str("test-UPPER.com:12"));
- assert!(is_domain_port_str("some-other.domain.com:12"));
- assert!(!is_domain_port_str("under_score:12"));
- assert!(!is_domain_port_str("a@bc:12"));
- assert!(!is_domain_port_str("1.1.1.1:12"));
- assert!(!is_domain_port_str("1.2.3:12"));
- assert!(!is_domain_port_str("1.2.3.45:12"));
- assert!(!is_domain_port_str("a.b.c:123456"));
- assert!(!is_domain_port_str("---:12"));
- assert!(!is_domain_port_str(".:12"));
- // todo: should we also check for these edge cases?
- // out-of-range port
- assert!(is_domain_port_str("test.com:0"));
- assert!(is_domain_port_str("test.com:98989"));
- }
- #[test]
- fn test_mangle2() {
- let addr = "[::ffff:127.0.0.1]:8080".parse().unwrap();
- let addr_v4 = "127.0.0.1:8080".parse().unwrap();
- assert_eq!(AddrMangle::decode(&AddrMangle::encode(addr)), addr_v4);
- assert_eq!(
- AddrMangle::decode(&AddrMangle::encode("[::127.0.0.1]:8080".parse().unwrap())),
- addr_v4
- );
- assert_eq!(AddrMangle::decode(&AddrMangle::encode(addr_v4)), addr_v4);
- let addr_v6 = "[ef::fe]:8080".parse().unwrap();
- assert_eq!(AddrMangle::decode(&AddrMangle::encode(addr_v6)), addr_v6);
- let addr_v6 = "[::1]:8080".parse().unwrap();
- assert_eq!(AddrMangle::decode(&AddrMangle::encode(addr_v6)), addr_v6);
- }
- }
|