mirror of
https://github.com/EasyTier/EasyTier.git
synced 2025-10-19 07:05:19 +08:00
fix bug in dhcp (#152)
1. fix dhcp not retry if tun device init failed. 2. forbid dhcp use default ip when no peer.
This commit is contained in:
@@ -199,11 +199,13 @@ impl Instance {
|
|||||||
|
|
||||||
async fn clear_nic_ctx(arc_nic_ctx: ArcNicCtx) {
|
async fn clear_nic_ctx(arc_nic_ctx: ArcNicCtx) {
|
||||||
let _ = arc_nic_ctx.lock().await.take();
|
let _ = arc_nic_ctx.lock().await.take();
|
||||||
|
tracing::debug!("nic ctx cleared.");
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn use_new_nic_ctx(arc_nic_ctx: ArcNicCtx, nic_ctx: NicCtx) {
|
async fn use_new_nic_ctx(arc_nic_ctx: ArcNicCtx, nic_ctx: NicCtx) {
|
||||||
let mut g = arc_nic_ctx.lock().await;
|
let mut g = arc_nic_ctx.lock().await;
|
||||||
*g = Some(nic_ctx);
|
*g = Some(nic_ctx);
|
||||||
|
tracing::debug!("nic ctx updated.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warning, if there is an IP conflict in the network when using DHCP, the IP will be automatically changed.
|
// Warning, if there is an IP conflict in the network when using DHCP, the IP will be automatically changed.
|
||||||
@@ -214,93 +216,92 @@ impl Instance {
|
|||||||
let nic_ctx = self.nic_ctx.clone();
|
let nic_ctx = self.nic_ctx.clone();
|
||||||
let peer_packet_receiver = self.peer_packet_receiver.clone();
|
let peer_packet_receiver = self.peer_packet_receiver.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let default_ipv4_addr = Ipv4Addr::new(10, 0, 0, 0);
|
let default_ipv4_addr = Ipv4Inet::new(Ipv4Addr::new(10, 126, 126, 0), 24).unwrap();
|
||||||
let mut dhcp_ip: Option<Ipv4Inet> = None;
|
let mut current_dhcp_ip: Option<Ipv4Inet> = None;
|
||||||
let mut tries = 6;
|
let mut next_sleep_time = 0;
|
||||||
loop {
|
loop {
|
||||||
let mut ipv4_addr: Option<Ipv4Inet> = None;
|
tokio::time::sleep(std::time::Duration::from_secs(next_sleep_time)).await;
|
||||||
let mut unique_ipv4 = HashSet::new();
|
|
||||||
|
|
||||||
for i in 0..tries {
|
// do not allocate ip if no peer connected
|
||||||
if dhcp_ip.is_none() {
|
let routes = peer_manager_c.list_routes().await;
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
if routes.is_empty() {
|
||||||
|
next_sleep_time = 1;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
next_sleep_time = rand::thread_rng().gen_range(5..10);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut used_ipv4 = HashSet::new();
|
||||||
|
for route in peer_manager_c.list_routes().await {
|
||||||
|
if route.ipv4_addr.is_empty() {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for route in peer_manager_c.list_routes().await {
|
let Ok(peer_ipv4_addr) = route.ipv4_addr.parse::<Ipv4Addr>() else {
|
||||||
if !route.ipv4_addr.is_empty() {
|
continue;
|
||||||
if let Ok(ip) = Ipv4Inet::new(
|
};
|
||||||
if let Ok(ipv4) = route.ipv4_addr.parse::<Ipv4Addr>() {
|
|
||||||
ipv4
|
|
||||||
} else {
|
|
||||||
default_ipv4_addr
|
|
||||||
},
|
|
||||||
24,
|
|
||||||
) {
|
|
||||||
unique_ipv4.insert(ip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if i == tries - 1 && unique_ipv4.is_empty() {
|
let Ok(peer_ipv4_addr) = Ipv4Inet::new(peer_ipv4_addr, 24) else {
|
||||||
unique_ipv4.insert(Ipv4Inet::new(default_ipv4_addr, 24).unwrap());
|
continue;
|
||||||
}
|
};
|
||||||
|
|
||||||
if let Some(ip) = dhcp_ip {
|
used_ipv4.insert(peer_ipv4_addr);
|
||||||
if !unique_ipv4.contains(&ip) {
|
}
|
||||||
ipv4_addr = dhcp_ip;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for net in unique_ipv4.iter().map(|inet| inet.network()).take(1) {
|
let dhcp_inet = used_ipv4.iter().next().unwrap_or(&default_ipv4_addr);
|
||||||
if let Some(ip) = net.iter().find(|ip| {
|
// if old ip is already in this subnet and not conflicted, use it
|
||||||
ip.address() != net.first_address()
|
if let Some(ip) = current_dhcp_ip {
|
||||||
&& ip.address() != net.last_address()
|
if ip.network() == dhcp_inet.network() && !used_ipv4.contains(&ip) {
|
||||||
&& !unique_ipv4.contains(ip)
|
continue;
|
||||||
}) {
|
|
||||||
ipv4_addr = Some(ip);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if dhcp_ip != ipv4_addr {
|
// find an available ip in the subnet
|
||||||
let last_ip = dhcp_ip.map(|p| p.address());
|
let candidate_ipv4_addr = dhcp_inet.network().iter().find(|ip| {
|
||||||
tracing::debug!("last_ip: {:?}", last_ip);
|
ip.address() != dhcp_inet.first_address()
|
||||||
|
&& ip.address() != dhcp_inet.last_address()
|
||||||
|
&& !used_ipv4.contains(ip)
|
||||||
|
});
|
||||||
|
|
||||||
Self::clear_nic_ctx(nic_ctx.clone()).await;
|
if current_dhcp_ip == candidate_ipv4_addr {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(ip) = ipv4_addr {
|
let last_ip = current_dhcp_ip.as_ref().map(Ipv4Inet::address);
|
||||||
let mut new_nic_ctx = NicCtx::new(
|
tracing::debug!(
|
||||||
global_ctx_c.clone(),
|
?current_dhcp_ip,
|
||||||
&peer_manager_c,
|
?candidate_ipv4_addr,
|
||||||
peer_packet_receiver.clone(),
|
"dhcp start changing ip"
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::clear_nic_ctx(nic_ctx.clone()).await;
|
||||||
|
|
||||||
|
if let Some(ip) = candidate_ipv4_addr {
|
||||||
|
let mut new_nic_ctx = NicCtx::new(
|
||||||
|
global_ctx_c.clone(),
|
||||||
|
&peer_manager_c,
|
||||||
|
peer_packet_receiver.clone(),
|
||||||
|
);
|
||||||
|
if let Err(e) = new_nic_ctx.run(ip.address()).await {
|
||||||
|
tracing::error!(
|
||||||
|
?current_dhcp_ip,
|
||||||
|
?candidate_ipv4_addr,
|
||||||
|
?e,
|
||||||
|
"add ip failed"
|
||||||
);
|
);
|
||||||
dhcp_ip = Some(ip);
|
|
||||||
tries = 1;
|
|
||||||
if let Err(e) = new_nic_ctx.run(ip.address()).await {
|
|
||||||
tracing::error!("add ip failed: {:?}", e);
|
|
||||||
global_ctx_c.set_ipv4(None);
|
|
||||||
let sleep: u64 = rand::thread_rng().gen_range(200..500);
|
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(sleep)).await;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
global_ctx_c.set_ipv4(Some(ip.address()));
|
|
||||||
global_ctx_c.issue_event(GlobalCtxEvent::DhcpIpv4Changed(
|
|
||||||
last_ip,
|
|
||||||
Some(ip.address()),
|
|
||||||
));
|
|
||||||
Self::use_new_nic_ctx(nic_ctx.clone(), new_nic_ctx).await;
|
|
||||||
} else {
|
|
||||||
global_ctx_c.set_ipv4(None);
|
global_ctx_c.set_ipv4(None);
|
||||||
global_ctx_c.issue_event(GlobalCtxEvent::DhcpIpv4Conflicted(last_ip));
|
continue;
|
||||||
dhcp_ip = None;
|
|
||||||
tries = 6;
|
|
||||||
}
|
}
|
||||||
|
current_dhcp_ip = Some(ip);
|
||||||
|
global_ctx_c.set_ipv4(Some(ip.address()));
|
||||||
|
global_ctx_c
|
||||||
|
.issue_event(GlobalCtxEvent::DhcpIpv4Changed(last_ip, Some(ip.address())));
|
||||||
|
Self::use_new_nic_ctx(nic_ctx.clone(), new_nic_ctx).await;
|
||||||
|
} else {
|
||||||
|
current_dhcp_ip = None;
|
||||||
|
global_ctx_c.set_ipv4(None);
|
||||||
|
global_ctx_c.issue_event(GlobalCtxEvent::DhcpIpv4Conflicted(last_ip));
|
||||||
}
|
}
|
||||||
|
|
||||||
let sleep: u64 = rand::thread_rng().gen_range(5..10);
|
|
||||||
|
|
||||||
tokio::time::sleep(std::time::Duration::from_secs(sleep)).await;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user