Skip to content

Commit de8ecb2

Browse files
committed
feat: split by lib and main
1 parent 7baa834 commit de8ecb2

17 files changed

+564
-150
lines changed

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "zerodns"
3-
version = "0.1.0-alpha.2"
3+
version = "0.1.0-alpha.3"
44
edition = "2021"
55
license = "MIT"
66
readme = "README.md"
@@ -42,6 +42,7 @@ regex = "1.10.3"
4242
hex = "0.4.3"
4343
strum = { version = "0.26.1", default-features = false, features = ["strum_macros", "derive"] }
4444
strum_macros = "0.26.1"
45+
deadpool = "0.10.0"
4546

4647
[dev-dependencies]
4748
hex = "0.4.3"

README.md

+67
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,71 @@ run an example:
2626

2727
```shell
2828
$ just r
29+
$ dig @127.0.0.1 -p5454 www.youtube.com
30+
```
31+
32+
## Configuration
33+
34+
Here's an example configuration file:
35+
36+
```toml
37+
38+
# The settings of server
39+
[server]
40+
# will listen on tcp+udp
41+
listen = "0.0.0.0:5454"
42+
# use LRU cache with 1000 capacity
43+
cache_size = 1000
44+
45+
##### FILTERS BEGIN #####
46+
47+
# alidns over udp
48+
[filters.alidns]
49+
kind = "proxyby"
50+
props = { servers = ["223.5.5.5", "223.6.6.6"] }
51+
52+
# opendns over tcp
53+
[filters.opendns]
54+
kind = "proxyby"
55+
props = { servers = ["tcp://208.67.222.222:443", "tcp://208.67.220.220:443"] }
56+
57+
# a chinadns filter:
58+
# - use trusted dns servers for oversea domain
59+
# - use mistrusted dns servers for Chinese domain
60+
# NOTICE: require 'geoip_database', you can download from https://git.io/GeoLite2-Country.mmdb
61+
[filters.chinadns]
62+
kind = "chinadns"
63+
props = { trusted = ["tcp://208.67.222.222:443", "tcp://208.67.220.220:443"], mistrusted = ["223.5.5.5", "223.6.6.6"], geoip_database = "GeoLite2-Country.mmdb" }
64+
65+
##### FILTERS END #####
66+
67+
##### RULES BEGIN #####
68+
69+
# NOTICE:
70+
# - will check rules below one by one
71+
# - the 'domain' field follows the glob syntax
72+
73+
# for domain of '*.cn', use alidns filter
74+
[[rules]]
75+
domain = "*.cn"
76+
filter = "alidns"
77+
78+
# for domain of '*apple.com', use alidns filter
79+
[[rules]]
80+
domain = "*.apple.com"
81+
filter = "alidns"
82+
83+
# for domain of '*google*', use opendns filter
84+
[[rules]]
85+
domain = "*google*"
86+
filter = "opendns"
87+
88+
# FINAL: use chinadns for others
89+
[[rules]]
90+
domain = "*"
91+
filter = "chinadns"
92+
93+
##### RULES END #####
94+
95+
2996
```

config.toml

+17-26
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,31 @@
11
[server]
22
listen = "0.0.0.0:5454"
3-
# cache_size = 1000
3+
cache_size = 1000
44

5-
[filters.test]
6-
kind = "proxyby"
7-
props = { servers = ["tcp://223.5.5.5"] }
8-
9-
[filters.china]
5+
[filters.alidns]
106
kind = "proxyby"
117
props = { servers = ["223.5.5.5", "223.6.6.6"] }
128

13-
[filters.google]
9+
[filters.opendns]
1410
kind = "proxyby"
15-
props = { servers = ["8.8.8.8", "8.8.4.4"] }
16-
17-
[filters.tcpgoogle]
18-
kind = "proxyby"
19-
props = { servers = ["tcp://8.8.8.8", "tcp://8.8.4.4"] }
20-
11+
props = { servers = ["tcp://208.67.222.222:443", "tcp://208.67.220.220:443"] }
2112

2213
[filters.chinadns]
2314
kind = "chinadns"
24-
props = { trusted = ["tcp://8.8.8.8", "tcp://8.8.4.4"], mistrusted = ["223.5.5.5", "223.6.6.6"], geoip_database = "GeoLite2-Country.mmdb" }
15+
props = { trusted = ["tcp://208.67.222.222:443", "tcp://208.67.220.220:443"], mistrusted = ["223.5.5.5", "223.6.6.6"], geoip_database = "GeoLite2-Country.mmdb" }
2516

26-
#[[rules]]
27-
#domain = "*bing*"
28-
#filter = "test"
29-
#
30-
#[[rules]]
31-
#domain = "*.cn"
32-
#filter = "china"
33-
#
34-
#[[rules]]
35-
#domain = "*google.com"
36-
#filter = "google"
17+
[[rules]]
18+
domain = "*.cn"
19+
filter = "alidns"
20+
21+
[[rules]]
22+
domain = "*.apple.com"
23+
filter = "alidns"
24+
25+
[[rules]]
26+
domain = "*google*"
27+
filter = "opendns"
3728

3829
[[rules]]
3930
domain = "*"
40-
filter = "tcpgoogle"
31+
filter = "chinadns"

docker-compose.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ services:
1212
- ./GeoLite2-Country.mmdb:/app/GeoLite2-Country.mmdb
1313
- ./config.toml:/app/config.toml
1414
ports:
15-
- 15454:5454/udp
16-
- 15454:5454/tcp
15+
- 5454:5454/udp
16+
- 5454:5454/tcp
1717
networks:
1818
- local
1919

src/bootstrap.rs

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use std::sync::Arc;
2+
3+
use tokio::net::{TcpListener, UdpSocket};
4+
use tokio::sync::Notify;
5+
6+
use crate::cache::InMemoryCache;
7+
use crate::config::Config;
8+
use crate::handler::RuledHandler;
9+
use crate::server::{TcpServer, UdpServer};
10+
11+
pub async fn run(c: Config, closer: Arc<Notify>) -> anyhow::Result<()> {
12+
let mut rb = RuledHandler::builder();
13+
14+
for (k, v) in c.filters.iter() {
15+
rb = rb.filter(k, v)?;
16+
}
17+
18+
for next in c.rules.iter() {
19+
rb = rb.rule(next)?;
20+
}
21+
22+
let h = rb.build();
23+
24+
let cs = match &c.server.cache_size {
25+
None => None,
26+
Some(size) => {
27+
if *size == 0 {
28+
None
29+
} else {
30+
Some(Arc::new(InMemoryCache::builder().capacity(*size).build()))
31+
}
32+
}
33+
};
34+
35+
let udp_server = {
36+
let socket = UdpSocket::bind(&c.server.listen).await?;
37+
38+
UdpServer::new(
39+
socket,
40+
Clone::clone(&h),
41+
Clone::clone(&cs),
42+
Clone::clone(&closer),
43+
)
44+
};
45+
46+
let tcp_server = {
47+
TcpServer::new(
48+
TcpListener::bind(&c.server.listen).await?,
49+
Clone::clone(&h),
50+
Clone::clone(&cs),
51+
Clone::clone(&closer),
52+
)
53+
};
54+
55+
let (_first, _second) = tokio::join!(udp_server.listen(), tcp_server.listen());
56+
57+
Ok(())
58+
}

src/builtin.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::filter::{
33
ProxyByFilterFactory,
44
};
55

6-
pub(crate) fn init() {
6+
pub fn init() {
77
register("noop", |opts: &Options| NoopFilterFactory::try_from(opts));
88
register("proxyby", |opts: &Options| {
99
ProxyByFilterFactory::try_from(opts)
@@ -16,9 +16,10 @@ pub(crate) fn init() {
1616

1717
#[cfg(test)]
1818
mod tests {
19-
use super::*;
2019
use crate::filter::{load, Options};
2120

21+
use super::*;
22+
2223
#[test]
2324
fn test_init() {
2425
pretty_env_logger::try_init_timed().ok();

src/cache.rs src/cache/memory.rs

+14-8
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,34 @@
1+
use super::CacheStore;
12
use std::ops::Add;
23
use std::time::{Duration, Instant};
34

5+
use async_trait::async_trait;
46
use moka::future::Cache;
57

68
use crate::protocol::Message;
79

810
#[derive(Clone)]
9-
pub(crate) struct CacheStore {
11+
pub(crate) struct InMemoryCache {
1012
ttl: Duration,
1113
cache: Cache<Message, (Instant, Message)>,
1214
}
1315

14-
impl CacheStore {
16+
impl InMemoryCache {
1517
pub(crate) fn builder() -> CacheStoreBuilder {
1618
CacheStoreBuilder {
1719
ttl: Duration::from_secs(3600),
1820
capacity: 1000,
1921
}
2022
}
23+
}
2124

22-
pub(crate) async fn get(&self, req: &Message) -> Option<(Instant, Message)> {
25+
#[async_trait]
26+
impl CacheStore for InMemoryCache {
27+
async fn get(&self, req: &Message) -> Option<(Instant, Message)> {
2328
self.cache.get(req).await
2429
}
2530

26-
pub(crate) async fn set(&self, req: &Message, resp: &Message) {
31+
async fn set(&self, req: &Message, resp: &Message) {
2732
let key = Clone::clone(req);
2833
let val = Clone::clone(resp);
2934

@@ -54,19 +59,20 @@ impl CacheStoreBuilder {
5459
self
5560
}
5661

57-
pub(crate) fn build(self) -> CacheStore {
62+
pub(crate) fn build(self) -> InMemoryCache {
5863
let Self { ttl, capacity } = self;
5964
let cache = Cache::builder().max_capacity(capacity as u64).build();
6065

61-
CacheStore { ttl, cache }
66+
InMemoryCache { ttl, cache }
6267
}
6368
}
6469

6570
#[cfg(test)]
6671
mod tests {
67-
use super::*;
6872
use tokio::time::{sleep, Duration};
6973

74+
use super::*;
75+
7076
fn init() {
7177
pretty_env_logger::try_init_timed().ok();
7278
}
@@ -88,7 +94,7 @@ mod tests {
8894
Message::from(raw)
8995
};
9096

91-
let cs = CacheStore::builder().ttl(2).capacity(100).build();
97+
let cs = InMemoryCache::builder().ttl(2).capacity(100).build();
9298
assert!(cs.get(&req).await.is_none());
9399

94100
cs.set(&req, &res).await;

src/cache/mod.rs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use std::time::Instant;
2+
3+
use async_trait::async_trait;
4+
5+
pub(crate) use memory::InMemoryCache;
6+
7+
use crate::protocol::Message;
8+
9+
mod memory;
10+
11+
#[async_trait]
12+
pub trait CacheStore: Send + Sync + 'static {
13+
async fn get(&self, req: &Message) -> Option<(Instant, Message)>;
14+
15+
async fn set(&self, req: &Message, resp: &Message);
16+
}

src/client/mod.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
mod tcp;
2+
mod udp;
3+
4+
use async_trait::async_trait;
5+
6+
use crate::protocol::Message;
7+
use crate::Result;
8+
9+
#[async_trait]
10+
pub trait Client {
11+
async fn request(&self, req: &Message) -> Result<Option<Message>>;
12+
}
13+
14+
pub use tcp::{TcpClient, TcpClientBuilder};
15+
pub use udp::{UdpClient, UdpClientBuilder};

0 commit comments

Comments
 (0)