fix handle_tun_packet unwrap bug
This commit is contained in:
parent
2774431d49
commit
03b8da17dc
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"rust-analyzer.cargo.target": "x86_64-pc-windows-gnu",
|
// "rust-analyzer.cargo.target": "x86_64-pc-windows-gnu",
|
||||||
// "rust-analyzer.cargo.features": ["tun"]
|
// "rust-analyzer.cargo.features": ["tun"]
|
||||||
}
|
}
|
||||||
@ -2,17 +2,30 @@ use std::{net::SocketAddr, sync::atomic::Ordering, time::Duration};
|
|||||||
|
|
||||||
use num_enum::TryFromPrimitive;
|
use num_enum::TryFromPrimitive;
|
||||||
use punchnet::get_edge;
|
use punchnet::get_edge;
|
||||||
use sdlan_sn_rs::utils::Mac;
|
use sdlan_sn_rs::utils::{Mac, Result, SDLanError};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::{net::UdpSocket, time::sleep};
|
use tokio::{net::UdpSocket, time::sleep};
|
||||||
|
|
||||||
|
|
||||||
|
/// 这里是punchnet list等命令与punchnet主进程通信的消息结构
|
||||||
|
/// data-type: u8
|
||||||
|
/// data-len: u16
|
||||||
|
/// data: json
|
||||||
#[derive(TryFromPrimitive)]
|
#[derive(TryFromPrimitive)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum InfoFuncCode {
|
pub enum InfoFuncCode {
|
||||||
|
// query for info
|
||||||
Info = 0x00,
|
Info = 0x00,
|
||||||
|
// query for exit node list,
|
||||||
|
ExitNodeList = 0x01,
|
||||||
|
|
||||||
InfoFeedback = 0x80,
|
InfoFeedback = 0x80,
|
||||||
|
ExitNodeListFeedback = 0x81,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct ExitNodeListFeedback {
|
||||||
|
pub nodes: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@ -26,79 +39,99 @@ pub struct InfoFeedback {
|
|||||||
pub rx_sup: u64,
|
pub rx_sup: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn query_for_info() {
|
pub async fn do_query<T: serde::de::DeserializeOwned>(data_type: u8, data: &[u8], timeout: Duration) -> Result<T>{
|
||||||
let Ok(udp) = UdpSocket::bind("127.0.0.1:0").await else {
|
let Ok(udp) = UdpSocket::bind("127.0.0.1:0").await else {
|
||||||
eprintln!("failed to create");
|
eprintln!("failed to create");
|
||||||
return;
|
return Err(SDLanError::IOError("failed to create".to_owned()));
|
||||||
};
|
};
|
||||||
|
|
||||||
let remote = format!("127.0.0.1:{}", LOCAL_INFO_UDP_PORT).parse::<SocketAddr>().unwrap();
|
let remote = format!("127.0.0.1:{}", LOCAL_INFO_UDP_PORT).parse::<SocketAddr>().unwrap();
|
||||||
|
|
||||||
let buf = vec![InfoFuncCode::Info as u8, 0, 0];
|
let mut buf = Vec::with_capacity(1+2 + data.len());
|
||||||
|
buf.push(data_type);
|
||||||
|
buf.extend_from_slice(&(data.len() as u16).to_be_bytes());
|
||||||
|
buf.extend_from_slice(data);
|
||||||
|
|
||||||
if let Err(e) = udp.send_to(buf.as_slice(), remote).await {
|
if let Err(e) = udp.send_to(buf.as_slice(), remote).await {
|
||||||
eprintln!("failed to send query info");
|
eprintln!("failed to send query info");
|
||||||
return;
|
return Err(SDLanError::IOError("failed to send query".to_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buf = vec![0;1024];
|
let mut buf = vec![0;1024];
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
data = udp.recv_from(&mut buf) => {
|
data = udp.recv_from(&mut buf) => {
|
||||||
if let Ok((size, from)) = data {
|
if let Ok((size, _from)) = data {
|
||||||
if size < 3 {
|
if size < 3 {
|
||||||
eprintln!("no byte received");
|
eprintln!("no byte received");
|
||||||
return;
|
return Err(SDLanError::IOError("no bytes received".to_owned()));
|
||||||
}
|
}
|
||||||
buf.truncate(size);
|
buf.truncate(size);
|
||||||
|
|
||||||
let Ok(typecode) = InfoFuncCode::try_from_primitive(buf[0]) else {
|
let Ok(_typecode) = InfoFuncCode::try_from_primitive(buf[0]) else {
|
||||||
eprintln!("invalid type: {}", buf[0]);
|
eprintln!("invalid type: {}", buf[0]);
|
||||||
return;
|
return Err(SDLanError::IOError("invalid byte".to_owned()));
|
||||||
};
|
};
|
||||||
|
|
||||||
let size = u16::from_be_bytes([buf[1], buf[2]]);
|
let size = u16::from_be_bytes([buf[1], buf[2]]);
|
||||||
if buf.len() as u16 != size + 3 {
|
if buf.len() as u16 != size + 3 {
|
||||||
eprintln!("info length error: buf.len={}, size={}", buf.len(), size);
|
eprintln!("info length error: buf.len={}, size={}", buf.len(), size);
|
||||||
return;
|
return Err(SDLanError::IOError("info length error".to_owned()));
|
||||||
}
|
|
||||||
|
|
||||||
match typecode {
|
|
||||||
InfoFuncCode::InfoFeedback => {
|
|
||||||
let Ok(data) = serde_json::from_slice::<InfoFeedback>(&buf[3..]) else {
|
|
||||||
eprintln!("failed to marshal to json");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
println!("punchnet info:");
|
|
||||||
let ip = data.ip;
|
|
||||||
println!(" ip: {}.{}.{}.{}",
|
|
||||||
((ip>>24) & 0xff) as u8,
|
|
||||||
((ip>>16) & 0xff) as u8,
|
|
||||||
((ip>>8) & 0xff) as u8,
|
|
||||||
((ip) & 0xff) as u8,
|
|
||||||
);
|
|
||||||
let mac = data.mac;
|
|
||||||
println!(" mac: {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
|
|
||||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
|
|
||||||
);
|
|
||||||
|
|
||||||
println!(" p2p tx: {} bytes", data.tx_p2p);
|
|
||||||
println!(" p2p rx: {} bytes", data.rx_p2p);
|
|
||||||
|
|
||||||
println!(" super tx: {} bytes", data.tx_sup);
|
|
||||||
println!(" super rx: {} bytes", data.rx_sup);
|
|
||||||
}
|
|
||||||
_other => {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let result = serde_json::from_slice::<T>(&buf[3..])?;
|
||||||
|
return Ok(result);
|
||||||
} else {
|
} else {
|
||||||
eprintln!("failed to recv from punchnet");
|
eprintln!("failed to recv from punchnet");
|
||||||
}
|
}
|
||||||
return;
|
return Err(SDLanError::IOError("failed to recv from punchnet".to_owned()));
|
||||||
}
|
}
|
||||||
_ = sleep(Duration::from_secs(3)) => {
|
_ = sleep(timeout) => {
|
||||||
eprintln!("query timed out, is punchnet running?");
|
eprintln!("query timed out, is punchnet running?");
|
||||||
return;
|
return Err(SDLanError::IOError("timed out".to_owned()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn query_for_exit_node_list() {
|
||||||
|
let result = do_query::<ExitNodeListFeedback>(InfoFuncCode::ExitNodeList as u8, &[], Duration::from_secs(3)).await;
|
||||||
|
match result {
|
||||||
|
Ok(data) => {
|
||||||
|
println!("exit nodes:");
|
||||||
|
for node in &data.nodes {
|
||||||
|
println!(" {}", node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("failed to query for exit node list: {}", e.as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn query_for_info() {
|
||||||
|
let result = do_query::<InfoFeedback>(InfoFuncCode::Info as u8, &[], Duration::from_secs(3)).await;
|
||||||
|
match result {
|
||||||
|
Ok(data) => {
|
||||||
|
println!("punchnet info:");
|
||||||
|
let ip = data.ip;
|
||||||
|
println!(" ip: {}.{}.{}.{}",
|
||||||
|
((ip>>24) & 0xff) as u8,
|
||||||
|
((ip>>16) & 0xff) as u8,
|
||||||
|
((ip>>8) & 0xff) as u8,
|
||||||
|
((ip) & 0xff) as u8,
|
||||||
|
);
|
||||||
|
let mac = data.mac;
|
||||||
|
println!(" mac: {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
|
||||||
|
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
|
||||||
|
);
|
||||||
|
|
||||||
|
println!(" p2p tx: {} bytes", data.tx_p2p);
|
||||||
|
println!(" p2p rx: {} bytes", data.rx_p2p);
|
||||||
|
|
||||||
|
println!(" super tx: {} bytes", data.tx_sup);
|
||||||
|
println!(" super rx: {} bytes", data.rx_sup);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("failed to query for info: {}", e.as_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,7 @@ use libc::{SIGTERM, kill};
|
|||||||
use punchnet::CachedLoginInfo;
|
use punchnet::CachedLoginInfo;
|
||||||
use punchnet::CommandLineInput2;
|
use punchnet::CommandLineInput2;
|
||||||
use punchnet::Commands;
|
use punchnet::Commands;
|
||||||
|
use punchnet::ExitNodeCmd;
|
||||||
use punchnet::get_access_token;
|
use punchnet::get_access_token;
|
||||||
use punchnet::get_base_dir;
|
use punchnet::get_base_dir;
|
||||||
use punchnet::get_edge;
|
use punchnet::get_edge;
|
||||||
@ -47,6 +48,7 @@ use crate::api::connect;
|
|||||||
use crate::api::login_with_token;
|
use crate::api::login_with_token;
|
||||||
use crate::api::login_with_user_pass;
|
use crate::api::login_with_user_pass;
|
||||||
use crate::local_udp_info::handle_query_for_info_info;
|
use crate::local_udp_info::handle_query_for_info_info;
|
||||||
|
use crate::local_udp_info::query_for_exit_node_list;
|
||||||
use crate::local_udp_info::query_for_info;
|
use crate::local_udp_info::query_for_info;
|
||||||
|
|
||||||
|
|
||||||
@ -324,6 +326,25 @@ fn main() {
|
|||||||
process::exit(0);
|
process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Commands::ExitNode(cmd) => {
|
||||||
|
let rt = Runtime::new().unwrap();
|
||||||
|
rt.block_on(async move {
|
||||||
|
match cmd {
|
||||||
|
ExitNodeCmd::List => {
|
||||||
|
query_for_exit_node_list().await;
|
||||||
|
}
|
||||||
|
ExitNodeCmd::Start(info) => {
|
||||||
|
|
||||||
|
}
|
||||||
|
ExitNodeCmd::Stop => {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
Commands::Stop => {
|
Commands::Stop => {
|
||||||
match fs::read_to_string("/tmp/punchnet.pid") {
|
match fs::read_to_string("/tmp/punchnet.pid") {
|
||||||
@ -352,7 +373,6 @@ fn main() {
|
|||||||
process::exit(0);
|
process::exit(0);
|
||||||
}
|
}
|
||||||
Commands::Info => {
|
Commands::Info => {
|
||||||
|
|
||||||
let rt = Runtime::new().unwrap();
|
let rt = Runtime::new().unwrap();
|
||||||
rt.block_on(async move {
|
rt.block_on(async move {
|
||||||
query_for_info().await;
|
query_for_info().await;
|
||||||
|
|||||||
@ -77,12 +77,14 @@ pub async fn read_and_parse_packet(
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
buf.truncate(size);
|
buf.truncate(size);
|
||||||
|
println!("handle udp packet");
|
||||||
match handle_packet(eee, from, &buf).await {
|
match handle_packet(eee, from, &buf).await {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("failed to handle_packet: {:?}", e);
|
error!("failed to handle_packet: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
println!("handle udp packet ok");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -888,7 +890,17 @@ async fn handle_tun_packet(
|
|||||||
let protocol = ipv4.protocol;
|
let protocol = ipv4.protocol;
|
||||||
match protocol {
|
match protocol {
|
||||||
ip_number::TCP => {
|
ip_number::TCP => {
|
||||||
let tcp_header = headers.transport.unwrap().tcp().unwrap();
|
|
||||||
|
let Some(transport) = headers.transport else {
|
||||||
|
error!("failed to get transport header");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(tcp_header) = transport.tcp() else {
|
||||||
|
error!("failed to get udp header");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// let tcp_header = headers.transport.unwrap().tcp().unwrap();
|
||||||
let five_tuple = FiveTuple {
|
let five_tuple = FiveTuple {
|
||||||
src_ip: ipv4.destination.into(),
|
src_ip: ipv4.destination.into(),
|
||||||
dst_ip: ipv4.source.into(),
|
dst_ip: ipv4.source.into(),
|
||||||
@ -905,7 +917,16 @@ async fn handle_tun_packet(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ip_number::UDP => {
|
ip_number::UDP => {
|
||||||
let udp_header = headers.transport.unwrap().udp().unwrap();
|
let Some(transport) = headers.transport else {
|
||||||
|
error!("failed to get transport header");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(udp_header) = transport.udp() else {
|
||||||
|
error!("failed to get udp header");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// let udp_header = headers.transport.unwrap().udp().unwrap();
|
||||||
let five_tuple = FiveTuple {
|
let five_tuple = FiveTuple {
|
||||||
src_ip: ipv4.destination.into(),
|
src_ip: ipv4.destination.into(),
|
||||||
dst_ip: ipv4.source.into(),
|
dst_ip: ipv4.source.into(),
|
||||||
|
|||||||
@ -250,7 +250,7 @@ impl TunTapPacketHandler for Iface {
|
|||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
|
||||||
if hdr.ether_type == EtherType::ARP {
|
if hdr.ether_type == EtherType::ARP {
|
||||||
use crate::network::{ARP_REPLY, ARP_REQUEST, ArpHdr};
|
use crate::network::{ARP_REQUEST, ArpHdr};
|
||||||
|
|
||||||
let arp = ArpHdr::from_slice(&data);
|
let arp = ArpHdr::from_slice(&data);
|
||||||
match arp.opcode {
|
match arp.opcode {
|
||||||
@ -287,11 +287,14 @@ impl TunTapPacketHandler for Iface {
|
|||||||
if let Some(ip) = headers.net {
|
if let Some(ip) = headers.net {
|
||||||
match ip {
|
match ip {
|
||||||
etherparse::NetHeaders::Ipv4(ipv4, _) => {
|
etherparse::NetHeaders::Ipv4(ipv4, _) => {
|
||||||
use etherparse::ip_number::{self, ICMP};
|
if u32::from_be_bytes(ipv4.destination) == u32::from_be_bytes([10, 10, 2, 6]) {
|
||||||
|
let raw_data = &data[14..];
|
||||||
|
println!("got packet to 10.10.2.6(size={}): {:?}", raw_data.len(), raw_data);
|
||||||
|
}
|
||||||
|
|
||||||
use crate::FiveTuple;
|
use crate::FiveTuple;
|
||||||
use etherparse::IpNumber;
|
use etherparse::IpNumber;
|
||||||
|
|
||||||
if let Some(transport) = headers.transport {
|
if let Some(transport) = headers.transport {
|
||||||
match ipv4.protocol {
|
match ipv4.protocol {
|
||||||
IpNumber::TCP => {
|
IpNumber::TCP => {
|
||||||
|
|||||||
@ -143,6 +143,7 @@ impl RuleCache {
|
|||||||
if allow_routing {
|
if allow_routing {
|
||||||
return (true, false);
|
return (true, false);
|
||||||
}
|
}
|
||||||
|
return (true, false);
|
||||||
|
|
||||||
error!("is identity ok? {:?}", info);
|
error!("is identity ok? {:?}", info);
|
||||||
if self.session_table.process_packet(&info) {
|
if self.session_table.process_packet(&info) {
|
||||||
|
|||||||
@ -26,6 +26,9 @@ pub enum Commands {
|
|||||||
|
|
||||||
Info,
|
Info,
|
||||||
|
|
||||||
|
#[command(subcommand)]
|
||||||
|
ExitNode(ExitNodeCmd),
|
||||||
|
|
||||||
RouteAdd(RouteCmdInfo),
|
RouteAdd(RouteCmdInfo),
|
||||||
RouteDel(RouteCmdInfo),
|
RouteDel(RouteCmdInfo),
|
||||||
RouteList,
|
RouteList,
|
||||||
@ -34,6 +37,22 @@ pub enum Commands {
|
|||||||
Stop,
|
Stop,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand, Debug)]
|
||||||
|
pub enum ExitNodeCmd {
|
||||||
|
// list current exit node, and the now used exit node,
|
||||||
|
List,
|
||||||
|
|
||||||
|
/// just exit the node, but keep the process running
|
||||||
|
Start(ExitNodeInfo),
|
||||||
|
Stop,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug)]
|
||||||
|
pub struct ExitNodeInfo {
|
||||||
|
#[arg(short, long, default_value="")]
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Args, Debug)]
|
#[derive(Args, Debug)]
|
||||||
pub struct StartArguments {
|
pub struct StartArguments {
|
||||||
#[arg(short, long, default_value="")]
|
#[arg(short, long, default_value="")]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user