Skip to content

Commit

Permalink
remove durable objects and wirefilter rules due to free plans limitat…
Browse files Browse the repository at this point in the history
…ions

Signed-off-by: Uncle Jack <[email protected]>
  • Loading branch information
unclejacki committed Jun 22, 2024
1 parent defc1ed commit 36cf413
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 338 deletions.
207 changes: 28 additions & 179 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ serde_json = "1.0"
base64 = "0.22"
getrandom = { version = "0.2", features = ["js"] }
worker = "0.0.18"
wirefilter-engine = { git = "https://github.com/unclejacki/wirefilter", branch = "cloudflare" }
cidr = { version = "0.2", features = ["serde"] }
lazy_static = "1.4"
futures-util = "0.3.28"
pin-project-lite = "0.2"
Expand Down
32 changes: 15 additions & 17 deletions config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,20 @@ outbound = "vless"

# forward matched connections to a bepass-relay server
[relay]
match = """
ip in {103.21.244.0/22
103.22.200.0/22
103.31.4.0/22
104.16.0.0/13
104.24.0.0/14
108.162.192.0/18
131.0.72.0/22
141.101.64.0/18
162.158.0.0/15
172.64.0.0/13
173.245.48.0/20
188.114.96.0/20
190.93.240.0/20
197.234.240.0/22
198.41.128.0/17}
"""
match = ["173.245.48.0/20",
"103.21.244.0/22",
"103.22.200.0/22",
"103.31.4.0/22",
"141.101.64.0/18",
"108.162.192.0/18",
"190.93.240.0/20",
"188.114.96.0/20",
"197.234.240.0/22",
"198.41.128.0/17",
"162.158.0.0/15",
"104.16.0.0/13",
"104.24.0.0/14",
"172.64.0.0/13",
"131.0.72.0/22"]
addresses = ["127.0.0.1"]
port = 6666
103 changes: 21 additions & 82 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,8 @@
use std::net::IpAddr;
use std::sync::Arc;

use cidr::IpCidr;
use serde::Deserialize;
use uuid::{self, Uuid};
use wirefilter::{ExecutionContext, Field, Filter, Scheme};
#[cfg(not(test))]
use worker::console_log;

lazy_static::lazy_static! {
static ref SCHEME: Scheme = Scheme! {
ip: Ip,
port: Int,
};
}

pub fn fill_wirefilter_ctx<'a>(
ip: String,
port: u16,
fields: &[Field<'a>],
) -> ExecutionContext<'a> {
let mut ctx = ExecutionContext::new(&SCHEME);

for field in fields.iter() {
match field.name() {
"ip" => {
if let Ok(ip) = ip.parse::<IpAddr>() {
let _ = ctx.set_field_value(*field, ip);
}
}
"port" => {
let _ = ctx.set_field_value(*field, port as i32);
}
_ => {}
}
}

ctx
}

#[derive(Clone)]
pub struct CompiledExpr {
pub filter: Filter<'static>,
pub fields: Arc<Vec<Field<'static>>>,
}

#[derive(Debug, PartialEq, Clone, Deserialize)]
#[serde(rename_all = "lowercase")]
Expand All @@ -59,9 +19,8 @@ impl Default for Outbound {

#[derive(Default, Clone, Deserialize)]
pub struct RelayConfig {
pub r#match: String,
pub r#match: Vec<IpCidr>,
pub addresses: Vec<String>,
// TODO: remove this and only use addresses field
pub port: u16,
}

Expand All @@ -70,50 +29,17 @@ pub struct Config {
pub uuid: Uuid,
pub outbound: Outbound,
pub relay: RelayConfig,
// store the rules' AST because it's heavy to create them per every request
#[serde(skip)]
pub compiled_expr: Option<CompiledExpr>,
}

impl Config {
pub fn new(buf: &str) -> Self {
// TODO: notify the user in case of having an invalid config format
let mut config: Self = toml::from_str(buf).unwrap_or_default();

config.compiled_expr = match SCHEME.parse(&config.relay.r#match) {
Ok(ast) => {
let mut fields = vec![];
SCHEME
.iter()
.filter(|(n, _)| ast.uses(n).unwrap_or(false))
.filter_map(|(n, _)| SCHEME.get_field(n).ok())
.for_each(|f| {
if !fields.contains(&f) {
fields.push(f);
}
});
let filter = ast.compile();

Some(CompiledExpr {
filter,
fields: Arc::new(fields),
})
}
Err(_e) => {
#[cfg(not(test))]
console_log!("{_e}");

None
}
};

config
toml::from_str(buf).unwrap_or_default()
}

pub fn is_relay_request(&self, addr: String, port: u16) -> bool {
if let Some(expr) = &self.compiled_expr {
let ctx = fill_wirefilter_ctx(addr, port, &expr.fields);
return expr.filter.execute(&ctx).unwrap_or_default();
pub fn is_relay_request(&self, ip: String) -> bool {
if let Ok(ip) = ip.parse::<IpAddr>() {
return self.relay.r#match.iter().any(|cidr| cidr.contains(&ip));
}
false
}
Expand All @@ -135,7 +61,21 @@ mod tests {
outbound = "vless"
[relay]
match = "ip == 4.2.2.4 && port == 53"
match = ["173.245.48.0/20",
"103.21.244.0/22",
"103.22.200.0/22",
"103.31.4.0/22",
"141.101.64.0/18",
"108.162.192.0/18",
"190.93.240.0/20",
"188.114.96.0/20",
"197.234.240.0/22",
"198.41.128.0/17",
"162.158.0.0/15",
"104.16.0.0/13",
"104.24.0.0/14",
"172.64.0.0/13",
"131.0.72.0/22"]
addresses = ["1.1.1.1"]
port = 6666
"#;
Expand All @@ -146,7 +86,6 @@ mod tests {
config.uuid,
uuid::uuid!("0fbf4f81-2598-4b6a-a623-0ead4cb9efa8")
);
assert_eq!(config.relay.r#match, "ip == 4.2.2.4 && port == 53");
assert_eq!(config.relay.addresses, vec!["1.1.1.1"]);
}
}
75 changes: 27 additions & 48 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use crate::config::{Config, Outbound};
use crate::link::generate_link;
use crate::proxy::*;

use wirefilter::Type;
use worker::*;

lazy_static::lazy_static! {
Expand All @@ -16,58 +15,38 @@ lazy_static::lazy_static! {
};
}

#[durable_object]
struct Tunl {
config: Config,
}

impl Tunl {
async fn tunnel(&self) -> Result<Response> {
let config = self.config.clone();
let WebSocketPair { server, client } = WebSocketPair::new()?;

server.accept()?;
wasm_bindgen_futures::spawn_local(async move {
let events = server.events().unwrap();

if let Err(e) = match config.outbound {
Outbound::Vless => VlessStream::new(config, &server, events).process().await,
Outbound::Vmess => VmessStream::new(config, &server, events).process().await,
} {
console_log!("[tunnel]: {}", e);
}
});

Response::from_websocket(client)
}
#[event(fetch)]
async fn main(req: Request, env: Env, _: Context) -> Result<Response> {
let config = Config::new(&CONFIG);

fn link(&self, req: Request) -> Result<Response> {
let host = req.url()?.host().map(|x| x.to_string()).unwrap_or_default();
Response::from_json(&generate_link(&self.config, &host))
}
Router::with_data(config)
.on_async("/", tunnel)
.on("/link", link)
.run(req, env)
.await
}

// TODO: make sure about durable objects persistence.
// it's heavy to build the config per every request, so we use durable objects
// to make the config once and use it in every request.
#[durable_object]
impl DurableObject for Tunl {
fn new(state: State, _: Env) -> Self {
let config = Config::new(&CONFIG);
Self { config }
}
async fn tunnel(_: Request, cx: RouteContext<Config>) -> Result<Response> {
let WebSocketPair { server, client } = WebSocketPair::new()?;

server.accept()?;
wasm_bindgen_futures::spawn_local(async move {
let config = cx.data;
let events = server.events().unwrap();

async fn fetch(&mut self, req: Request) -> Result<Response> {
match req.path().as_str() {
"/link" => self.link(req),
_ => self.tunnel().await,
if let Err(e) = match config.outbound {
Outbound::Vless => VlessStream::new(config, &server, events).process().await,
Outbound::Vmess => VmessStream::new(config, &server, events).process().await,
} {
console_log!("[tunnel]: {}", e);
}
}
});

Response::from_websocket(client)
}

#[event(fetch)]
async fn main(req: Request, env: Env, _: Context) -> Result<Response> {
let namespace = env.durable_object("TUNL")?;
let stub = namespace.id_from_name("TUNL")?.get_stub()?;
stub.fetch_with_request(req).await
fn link(req: Request, cx: RouteContext<Config>) -> Result<Response> {
let config = cx.data;
let host = req.url()?.host().map(|x| x.to_string()).unwrap_or_default();
Response::from_json(&generate_link(&config, &host))
}
2 changes: 1 addition & 1 deletion src/proxy/vless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl<'a> VlessStream<'a> {
let mut port = u16::from_be_bytes(port);
let mut addr = crate::common::parse_addr(self).await?;

let use_relay = self.config.is_relay_request(addr.clone(), port);
let use_relay = self.config.is_relay_request(addr.clone());
let mut relay_header = vec![];
if use_relay {
relay_header = format!("tcp@{addr}${port}\r\n").as_bytes().to_vec();
Expand Down
2 changes: 1 addition & 1 deletion src/proxy/vmess.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ impl<'a> VmessStream<'a> {
};
let mut addr = crate::common::parse_addr(&mut buf).await?;

let use_relay = self.config.is_relay_request(addr.clone(), port);
let use_relay = self.config.is_relay_request(addr.clone());
let mut relay_header = vec![];
if use_relay {
relay_header = format!("tcp@{addr}${port}\r\n").as_bytes().to_vec();
Expand Down
9 changes: 0 additions & 9 deletions wrangler.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,3 @@ command = "cargo install -q worker-build && worker-build --release"

[env.dev]
build = { command = "cargo install -q worker-build && worker-build --dev" }

[durable_objects]
bindings = [
{ name = "TUNL", class_name = "Tunl" }
]

[[migrations]]
tag = "v1"
new_classes = ["Tunl"]

0 comments on commit 36cf413

Please sign in to comment.