Skip to content

Commit

Permalink
tun: + out_auto_route
Browse files Browse the repository at this point in the history
  • Loading branch information
e1732a364fed committed Jan 1, 2099
1 parent 1753b1e commit 99c651a
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 15 deletions.
4 changes: 4 additions & 0 deletions doc/notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,11 @@ echo net.ipv4.ip_forward=1 >> /etc/sysctl.conf && sysctl -p

该命令确保 /etc/sysctl.conf 文件中 包含 `net.ipv4.ip_forward=1` 且生效

## tun

tun 在 server 端使用时, 也必须要运行上面 tproxy 的 ip_forward 命令

ip_forward 不仅用于转发局域网设备流量, 也用于从 本机的 tun 转发到 本机的 网卡

## 名词

Expand Down
2 changes: 2 additions & 0 deletions resource/local.lua
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,8 @@ end
-- generator, generator 根据参数内容来动态生成 [Map], 如果不想
-- 重复生成以前生成过的Map, 则可以返回一个已创建过的Map (参见其它包含 Infinite 的配置文件中的示例)

-- 完全动态链需要在 ruci-cmd 运行时 加 --infinite 来启用

-- local inspect = require("inspect")

-- my_cid_record = {}
Expand Down
12 changes: 11 additions & 1 deletion resource/remote.lua
Original file line number Diff line number Diff line change
Expand Up @@ -169,14 +169,24 @@ Config = {
--]]

---[[
-- 对应 local.lua 使用 tun+IpRelayTest1 的 outbound 配置
-- 对应 local.lua 使用 tun+IpRelayTest1 的 outbound 配置.
-- 注意, 不像 tproxy, tun 示例不能本机自连测试

outbounds = { {
tag = "dial1",
chain = {
{
BindDialer = {
bind_addr = "ip://10.0.0.2:24#utun321",

-- out_auto_route 会自动配置路由表使得 utun321 中的流量走 enp0s1.
-- 注意要确保开启了 ip_forward

out_auto_route = {
tun_dev_name = "utun321",
original_dev_name = "enp0s1",
router_ip = "192.168.0.1",
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions rucimp/src/modes/chain/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ pub struct DialerConfig {
#[cfg(feature = "tun")]
in_auto_route: Option<tun::route::InAutoRouteParams>,

#[cfg(feature = "tun")]
out_auto_route: Option<tun::route::OutAutoRouteParams>,

ext: Option<Ext>,
}
impl ToMapBox for DialerConfig {
Expand All @@ -226,6 +229,7 @@ impl ToMapBox for DialerConfig {
#[cfg(feature = "tun")]
{
d.in_auto_route = self.in_auto_route.clone();
d.out_auto_route = self.out_auto_route.clone();
}
d.ext_fields = self.ext.as_ref().map(|e| e.to_ext_fields());

Expand Down
56 changes: 45 additions & 11 deletions src/map/network/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ impl Map for Direct {
enum AutoRouteState {
#[default]
None,
Up(Option<Vec<String>>),
InUp(Option<Vec<String>>),
OutUp,
Down,
}

Expand All @@ -123,6 +124,9 @@ pub struct BindDialer {
#[cfg(feature = "tun")]
pub in_auto_route: Option<tun::route::InAutoRouteParams>,

#[cfg(feature = "tun")]
pub out_auto_route: Option<tun::route::OutAutoRouteParams>,

auto_route_state: Arc<Mutex<AutoRouteState>>,
}

Expand All @@ -149,13 +153,23 @@ impl BindDialer {
pub fn down_route(&mut self) {
let mut mg = self.auto_route_state.lock();
match &*mg {
AutoRouteState::Up(opt_dns_list) => {
debug!("BindDialer down auto route");
AutoRouteState::InUp(opt_dns_list) => {
debug!("BindDialer down in auto route");

let mut params = self.in_auto_route.take().unwrap();
let mut params = self.in_auto_route.clone().unwrap();
params.dns_list = opt_dns_list.to_owned();
let r = tun::route::in_down_route(&params);
debug!("BindDialer down route {r:?}");
debug!("BindDialer down in auto route {r:?}");
if r.is_ok() {
*mg = AutoRouteState::Down;
}
}
AutoRouteState::OutUp => {
debug!("BindDialer down out auto route");

let params = self.out_auto_route.clone().unwrap();
let r = tun::route::out_down_route(&params);
debug!("BindDialer down out auto route {r:?}");
if r.is_ok() {
*mg = AutoRouteState::Down;
}
Expand All @@ -182,19 +196,39 @@ impl BindDialer {
if let Some(c) = &self.in_auto_route {
let mut mg = self.auto_route_state.lock();
match &*mg {
AutoRouteState::Up(_) => {
info!("BindDialer called after AutoRouteState::Up")
AutoRouteState::InUp(_) => {
info!("BindDialer called after AutoRouteState::InUp")
}
_ => {
let r = tun::route::in_auto_route(c);
match r {
Ok(opt_dns_list) => {
*mg = AutoRouteState::Up(opt_dns_list);
*mg = AutoRouteState::InUp(opt_dns_list);
}
Err(e) => {
return MapResult::from_e(e.context(format!(
"BindDialer in auto_route failed"
)))
}
}
}
}
} else if let Some(c) = &self.out_auto_route {
let mut mg = self.auto_route_state.lock();
match &*mg {
AutoRouteState::OutUp => {
info!("BindDialer called after AutoRouteState::OutUp")
}
_ => {
let r = tun::route::out_auto_route(c);
match r {
Ok(_) => {
*mg = AutoRouteState::OutUp;
}
Err(e) => {
return MapResult::from_e(
e.context(format!("BindDialer auto_route failed")),
)
return MapResult::from_e(e.context(format!(
"BindDialer out auto_route failed"
)))
}
}
}
Expand Down
68 changes: 65 additions & 3 deletions src/net/tun/route.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use tracing::{info, warn};

use crate::{
net::dns::{get_sys_dns, set_sys_dns},
utils::{self, sync_run_command_list_stop},
utils::{self, sync_run_command_list_no_stop, sync_run_command_list_stop},
};

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
Expand All @@ -17,9 +17,71 @@ pub struct InAutoRouteParams {
pub dns_list: Option<Vec<String>>,
}

// const DEFAULT_ROUTER_IP: &str = "192.168.0.1";
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct OutAutoRouteParams {
pub tun_dev_name: Option<String>,
pub original_dev_name: Option<String>,
pub router_ip: Option<String>,
}

const DEFAULT_ROUTER_IP: &str = "192.168.0.1";
const DEFAULT_ORIGINAL_DEV_NAME: &str = "enp0s1";

pub fn out_auto_route(params: &OutAutoRouteParams) -> anyhow::Result<()> {
#[cfg(target_os = "linux")]
{
info!("tun up out auto route for linux...");
let tun_dev_name = params.tun_dev_name.as_deref().unwrap_or("utun321");
let original_dev_name = params
.original_dev_name
.as_deref()
.unwrap_or(DEFAULT_ORIGINAL_DEV_NAME);

let router_ip = params.router_ip.as_deref().unwrap_or(DEFAULT_ROUTER_IP);

let list = format!(
r#"ip route del default
ip route add default via {router_ip} dev enp0s1
iptables -I FORWARD -i {tun_dev_name} -o {original_dev_name} -m conntrack --ctstate NEW -j ACCEPT
iptables -I FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -t nat -I POSTROUTING -o {original_dev_name} -j MASQUERADE"#,
);
let list: Vec<_> = list.split('\n').map(String::from).collect();

let r = sync_run_command_list_stop(list.iter().map(String::as_str).collect());

if let Err(e) = r {
warn!("auto_route run command got e, will down_route: {}", e);

let _ = out_down_route(params);
return Err(e);
}
}
Ok(())
}

pub fn out_down_route(params: &OutAutoRouteParams) -> anyhow::Result<()> {
#[cfg(target_os = "linux")]
{
info!("tun out down auto route for linux...");

let tun_dev_name = params.tun_dev_name.as_deref().unwrap_or("utun321");
let original_dev_name = params
.original_dev_name
.as_deref()
.unwrap_or(DEFAULT_ORIGINAL_DEV_NAME);
let list = format!(
r#"iptables -D FORWARD -i {tun_dev_name} -o {original_dev_name} -m conntrack --ctstate NEW -j ACCEPT
iptables -D FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -t nat -D POSTROUTING -o {original_dev_name} -j MASQUERADE"#,
);
let list: Vec<_> = list.split('\n').map(String::from).collect();

sync_run_command_list_no_stop(list.iter().map(String::as_str).collect(), false)?;
}
Ok(())
}

pub fn in_auto_route(params: &InAutoRouteParams) -> anyhow::Result<Option<Vec<String>>> {
#[cfg(target_os = "linux")]
{
Expand Down Expand Up @@ -92,7 +154,7 @@ pub fn in_down_route(params: &InAutoRouteParams) -> anyhow::Result<()> {
}
}

sync_run_command_list_stop(list.iter().map(String::as_str).collect())?;
sync_run_command_list_no_stop(list.iter().map(String::as_str).collect(), false)?;

if let Some(d) = &params.dns_list {
let d = d.iter().map(String::as_str).collect();
Expand Down

0 comments on commit 99c651a

Please sign in to comment.