Compare commits

...

42 Commits

Author SHA1 Message Date
d9b1329e6a changed dependencies to gitea.s5s8, and added network_code in register super 2025-10-22 16:27:45 +08:00
ec68a54957 changed the .a to .so, for cross compile fails in release mode 2025-10-10 15:36:48 +08:00
9a72c29870 punchnet renamed 2025-09-30 11:31:05 +08:00
7fa2ffa04d changed mode 2025-05-12 10:37:16 +08:00
6e8f4583d6 fix warning 2025-02-06 10:50:49 +08:00
3f6da7c65e changed back to log 2025-02-06 10:16:37 +08:00
7e5792e190 updated win's mtu 2025-02-06 10:13:43 +08:00
4aa33a4e26 tap-test 2025-02-05 16:19:37 +08:00
4fdcfa5bee is mtu's bug 2025-01-28 15:47:24 +08:00
c070d345ad fix nat probe bug 2024-12-30 10:15:44 +08:00
51c323008a nat-simulator.sh is still on work, now, it simulates the fullcone(nat1), ip restricted cone(nat2) 2024-12-27 00:25:13 +08:00
63805d9a47 fix nat probe's bug 2024-12-27 00:23:30 +08:00
240a3d263e ipv6 p2p is ok 2024-11-28 16:09:49 +08:00
c098a3c421 changed the message's proto, added nat_type for send_register event 2024-11-25 15:50:55 +08:00
b51c78bdfb guess port at -10 to 10 2024-11-13 19:24:33 +08:00
966f054a63 BROADCAST ip to BROADCAST_MAC 2024-10-30 10:30:58 +08:00
f3cbc1def2 register with local peers, broadcast mac 2024-10-26 11:33:15 +08:00
7a75c1d171 stdout's info 2024-10-26 11:22:02 +08:00
93f3dbdcf9 self mac print 2024-10-26 11:17:46 +08:00
c28c9e2911 fix features typo 2024-10-26 10:56:11 +08:00
2b8a536151 skip REGISTER SUPER and REGISTER from self 2024-10-26 10:53:58 +08:00
e32c640466 init wait list 2024-10-26 09:48:16 +08:00
07c6536d5a linux add to arp-list 2024-10-25 16:47:29 +08:00
d1e30370fc win arp wait list 2024-10-25 16:43:05 +08:00
69255d7907 add arp to waitlist 2024-10-25 16:41:02 +08:00
e7352c7b67 fix some warning 2024-10-25 11:24:50 +08:00
c4c1f109b1 tun win fix warning 2024-10-25 11:19:46 +08:00
cb71c53102 fix warning 2024-10-25 11:01:02 +08:00
06d7819fd1 linux 2024-10-24 18:46:21 +08:00
220cee4a89 win tun 2024-10-24 18:38:17 +08:00
9b1710e590 message 2024-10-23 20:36:51 +08:00
7c4bb64bd4 changed to handle_packet 2024-10-23 16:22:52 +08:00
6dd3d8694c added crc after the ether packet 2024-10-23 11:29:41 +08:00
1a5e1d8be3 tap is ok 2024-10-22 21:05:46 +08:00
c130dcc83e srcmac reply 2024-10-22 16:14:34 +08:00
53b0be35a7 src changed to dst 2024-10-22 16:09:31 +08:00
893eef5871 packet 2024-10-22 15:48:10 +08:00
32bbdc4f78 arp reply encrypt 2024-10-22 15:14:03 +08:00
af56edd331 dst mac 2024-10-22 11:01:52 +08:00
3e4fe82a59 changed arp 2024-10-22 11:00:44 +08:00
302300294a tap mac 2024-10-22 10:12:08 +08:00
56d6a35fea fix all error 2024-10-21 09:23:29 +08:00
38 changed files with 3422 additions and 931 deletions

13
.cargo/config.toml Executable file
View File

@ -0,0 +1,13 @@
[target.x86_64-unknown-linux-musl]
linker = "x86_64-linux-musl-gcc"
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
ar = "aarch64-linux-gnu-ar"
# ranlib = "aarch64-linux-gnu-ranlib"
[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"
# [build]
# target = "x86_64-unknown-linux-gnu"

8
.gitignore vendored Normal file → Executable file
View File

@ -4,3 +4,11 @@
.client .client
.output .output
sdlan sdlan
sdlan.exe
*.bak
*.a
*.o
*.tar
*.tar.gz
*.tgz
/punchnet

1325
Cargo.lock generated Normal file → Executable file

File diff suppressed because it is too large Load Diff

17
Cargo.toml Normal file → Executable file
View File

@ -1,9 +1,11 @@
[package] [package]
name = "sdlan-rs" name = "punchnet"
version = "0.1.0" version = "1.0.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
crc = "3.2.1"
crc32fast = "1.4.2"
dashmap = "6.0.1" dashmap = "6.0.1"
dns-lookup = "2.0.4" dns-lookup = "2.0.4"
etherparse = "0.15.0" etherparse = "0.15.0"
@ -13,13 +15,20 @@ num_enum = "0.7.2"
once_cell = "1.19.0" once_cell = "1.19.0"
prost = "0.12.6" prost = "0.12.6"
prost-build = "0.12.6" prost-build = "0.12.6"
rand = "0.8.5"
rsa = "0.9.6" rsa = "0.9.6"
sdlan-sn-rs = { git = "ssh://git@git.asxalex.pw/sdlan-v2/sdlan-rs.git" } # sdlan-sn-rs = { git = "ssh://git@git2.asxalex.pw/sdlan-v2/sdlan-rs.git" }
sdlan-sn-rs = {git = "https://gitea.s5s8.com/punchnet/sdlan-rs.git"}
# sdlan-sn-rs = {path = "../sdlan-rs"}
# sdlan-sn-rs = { git = "https://git.asxalex.pw/sdlan-v2/sdlan-rs.git" } # sdlan-sn-rs = { git = "https://git.asxalex.pw/sdlan-v2/sdlan-rs.git" }
structopt = "0.3.26" structopt = "0.3.26"
tokio = { version = "1.38.0", futures = ["full"] } tokio = { version = "1.38.0", features = ["full"] }
tokio-util = "0.7.11" tokio-util = "0.7.11"
tracing = "0.1.40" tracing = "0.1.40"
# rolling-file = { path = "../rolling-file" }
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
wintun = "0.4.0" wintun = "0.4.0"
[features]
tun = []

26
Makefile Normal file → Executable file
View File

@ -1,9 +1,31 @@
linux: self:
RUSTFLAGS="-L ." cargo build --release RUSTFLAGS="-L ." cargo build --release
linux:
RUSTFLAGS="-L ." cargo build --release --target x86_64-unknown-linux-musl
aarch64:
RUSTFLAGS="-L ." cargo build --release --target aarch64-unknown-linux-gnu
linux-tun:
RUSTFLAGS="-L ." cargo build --features "tun" --release
win:
cargo build --release --target x86_64-pc-windows-gnu
pb: pb:
cargo run --bin build_pb cargo run --bin build_pb
mv src/pb/_.rs src/pb/message.rs mv src/pb/_.rs src/pb/message.rs
libtun-so-clang:
cd src/network && clang -fPIC -shared -o libtuntap.so tuntap.c && cd -
libtun-so: libtun-so:
cd src/network && gcc -fPIC -shared -o libtuntap.so tuntap.c && cd - cd src/network && gcc -fPIC -shared -o libtuntap.so tuntap.c && cp libtuntap.so ../.. && cd -
libtun-so-aarch64:
cd src/network && aarch64-linux-gnu-gcc -fPIC -shared -o libtuntap.so tuntap.c && cp libtuntap.so ../.. && cd -
pack:
tar -czvf punchnet.tar.gz punchnet punchnet.service libtuntap.so install.sh

13
install.sh Normal file
View File

@ -0,0 +1,13 @@
uid=`id -u`
if [ "$uid" != "0" ]; then
echo "need to be root"
exit -1
fi
mkdir -p /usr/local/punchnet
cp punchnet /usr/local/punchnet
cp libtuntap.so /usr/lib/
cp punchnet.service /etc/systemd/system
systemctl enable punchnet
systemctl start punchnet

View File

@ -16,8 +16,9 @@ message SDLV6Info {
// //
message SDLDevAddr { message SDLDevAddr {
uint32 network_id = 1; uint32 network_id = 1;
uint32 net_addr = 2; bytes mac = 2;
uint32 net_bit_len = 3; uint32 net_addr = 3;
uint32 net_bit_len = 4;
} }
// tcp通讯消息 // tcp通讯消息
@ -32,15 +33,15 @@ message SDLRegisterSuper {
SDLDevAddr dev_addr = 4; SDLDevAddr dev_addr = 4;
string pub_key = 5; string pub_key = 5;
string token = 6; string token = 6;
string network_code = 7;
} }
message SDLRegisterSuperAck { message SDLRegisterSuperAck {
SDLDevAddr dev_addr = 1; SDLDevAddr dev_addr = 1;
bytes aes_key = 2; bytes aes_key = 2;
bytes known_ips = 3; uint32 upgrade_type = 3;
uint32 upgrade_type = 4; optional string upgrade_prompt = 4;
optional string upgrade_prompt = 5; optional string upgrade_address = 5;
optional string upgrade_address = 6;
} }
message SDLRegisterSuperNak { message SDLRegisterSuperNak {
@ -51,34 +52,28 @@ message SDLRegisterSuperNak {
// //
message SDLQueryInfo { message SDLQueryInfo {
uint32 dst_ip = 1; bytes dst_mac = 1;
} }
message SDLPeerInfo { message SDLPeerInfo {
uint32 dst_ip = 1; bytes dst_mac = 1;
SDLV4Info v4_info = 2; SDLV4Info v4_info = 2;
optional SDLV6Info v6_info = 3; optional SDLV6Info v6_info = 3;
} }
// //
message SDLKnownIpEvent {
uint32 ip = 1;
}
message SDLDropIpEvent {
uint32 ip = 1;
}
message SDLNatChangedEvent { message SDLNatChangedEvent {
uint32 ip = 1; bytes mac = 1;
uint32 ip = 2;
} }
message SDLSendRegisterEvent { message SDLSendRegisterEvent {
uint32 dst_ip = 1; bytes dst_mac = 1;
uint32 nat_ip = 2; uint32 nat_ip = 2;
uint32 nat_port = 3; uint32 nat_port = 3;
optional SDLV6Info v6_info = 4; uint32 nat_type = 4;
optional SDLV6Info v6_info = 5;
} }
message SDLNetworkShutdownEvent { message SDLNetworkShutdownEvent {
@ -90,7 +85,6 @@ message SDLNetworkShutdownEvent {
message SDLChangeNetworkCommand { message SDLChangeNetworkCommand {
SDLDevAddr dev_addr = 1; SDLDevAddr dev_addr = 1;
bytes aes_key = 2; bytes aes_key = 2;
bytes known_ips = 3;
} }
message SDLCommandAck { message SDLCommandAck {
@ -114,9 +108,10 @@ message SDLStunRequest {
uint32 cookie = 1; uint32 cookie = 1;
string client_id = 2; string client_id = 2;
uint32 network_id = 3; uint32 network_id = 3;
uint32 ip = 4; bytes mac = 4;
uint32 nat_type = 5; uint32 ip = 5;
optional SDLV6Info v6_info = 6; uint32 nat_type = 6;
optional SDLV6Info v6_info = 7;
} }
message SDLStunReply { message SDLStunReply {
@ -125,8 +120,8 @@ message SDLStunReply {
message SDLData { message SDLData {
uint32 network_id = 1; uint32 network_id = 1;
uint32 src_ip = 2; bytes src_mac = 2;
uint32 dst_ip = 3; bytes dst_mac = 3;
bool is_p2p = 4; bool is_p2p = 4;
uint32 ttl = 5; uint32 ttl = 5;
bytes data = 6; bytes data = 6;
@ -134,14 +129,14 @@ message SDLData {
message SDLRegister { message SDLRegister {
uint32 network_id = 1; uint32 network_id = 1;
uint32 src_ip = 2; bytes src_mac = 2;
uint32 dst_ip = 3; bytes dst_mac = 3;
} }
message SDLRegisterAck { message SDLRegisterAck {
uint32 network_id = 1; uint32 network_id = 1;
uint32 src_ip = 2; bytes src_mac = 2;
uint32 dst_ip = 3; bytes dst_mac = 3;
} }
// //

216
nat-simulator.sh Executable file
View File

@ -0,0 +1,216 @@
#!/bin/bash
## check for root
NAT_TYPE=
UDP_PORT=
IP=
DELETE=0
OUTER_INTERFACE=eth0
OUTER_IP=`ifconfig ${OUTER_INTERFACE} | grep -e "\binet\b" | awk '{print $2}'`
options=$(getopt -o t:p:i: --long type:,port:,ip:,delete -- "$@")
eval set -- "$options"
while true; do
case "$1" in
-t|--type)
NAT_TYPE=$2
shift 2
;;
-p|--port)
PORT=$2
shift 2
;;
-i|--ip)
IP=$2
shift 2
;;
--delete)
DELETE=1
shift
;;
--)
shift
break
;;
*)
echo "invalid option: $1"
exit -1;
;;
esac
done
port=$PORT
ip=$IP
is_number() {
re="^[1-9][0-9]*$"
if [[ $1 =~ $re ]]; then
return 0;
fi
return 1;
}
is_valid_ip() {
re="^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$"
if [[ $1 =~ $re ]]; then
return 0
fi
return 1
}
if ! is_number $port; then
echo "invalid port: $port"
exit -1;
fi
if ! is_valid_ip $ip; then
echo "invalid ip: $ip"
exit -1;
fi
PUNCHNET_TCP_PORT=18083
## iptables' tcp POSTROUTING chain name
POST_TCP=PUNCHNET-TCP
PRE_UDP=PUNCHNET-PRE-UDP
IPSET_GROUP=allowed_ip_${ip}
add_ipset_group() {
ipset destroy ${IPSET_GROUP}
ipset create ${IPSET_GROUP} hash:ip hashsize 4096
}
add_ipset_group
ensure_rule() {
table_name=$1
chain_name=$2
arguments=$3
## create table
# iptables -t ${table_name} -N ${chain_name} > /dev/null 2>&1
## add the rule
if ! iptables -t ${table_name} -C ${chain_name} ${arguments} > /dev/null 2>&1; then
echo "executing: iptables -t ${table_name} -A ${chain_name} ${arguments} > /dev/null 2>&1"
iptables -t ${table_name} -A ${chain_name} ${arguments} > /dev/null 2>&1
fi
}
clear_rule() {
table_name=$1
chain_name=$2
arguments=$3
iptables -t ${table_name} -D ${chain_name} ${arguments} > /dev/null 2>&1
}
drop_user_chian() {
table_name=$1
chain_name=$2
iptables -t ${table_name} -F ${chain_name}
iptables -t ${table_name} -X ${chain_name}
}
ensure_tcp_connection() {
# create table anyhow
iptables -t nat -N ${POST_TCP} > /dev/null 2>&1
ensure_rule "nat" "${POST_TCP}" "-p tcp --dport ${PUNCHNET_TCP_PORT} -j MASQUERADE"
ensure_rule "nat" "${POST_TCP}" "-j RETURN"
ensure_rule "nat" "POSTROUTING" "-p tcp -s ${ip} -j ${POST_TCP}"
}
fullcone() {
ensure_tcp_connection
# POSTROUTING for udp ports
ensure_rule "nat" "POSTROUTING" "-o ${OUTER_INTERFACE} -p udp --sport ${port} -j SNAT --to-source ${OUTER_IP}:${port}"
# prerouting for udp to the very host
ensure_rule "nat" "PREROUTING" "-p udp -i ${OUTER_INTERFACE} --dport ${port} -j DNAT --to-destination ${ip}:${port}"
}
fullcone_clear() {
clear_rule "nat" "POSTROUTING" "-o ${OUTER_INTERFACE} -p udp --sport ${port} -j MASQUERADE"
clear_rule "nat" "PREROUTING" "-i ${OUTER_INTERFACE} -p udp --dport ${port} -j DNAT --to-destination ${ip}"
}
restricted_cone() {
fullcone
# ensure_rule "filter" "FORWARD" "-i ${OUTER_INTERFACE} -p udp --dport ${port} -m state --state ESTABLISHED,RELATED -j LOG --log-prefix \\\"accept INPUT: \\\""
ensure_rule "filter" "FORWARD" "-i ${OUTER_INTERFACE} -p udp --dport ${port} -m state --state ESTABLISHED,RELATED -j SET --add-set ${IPSET_GROUP} src"
ensure_rule "filter" "FORWARD" "-i ${OUTER_INTERFACE} -p udp --dport ${port} -m state --state ESTABLISHED,RELATED -j ACCEPT"
# ensure_rule "filter" "FORWARD" "-i ${OUTER_INTERFACE} -p udp --dport ${port} -m state --state ESTABLISHED,RELATED -j ACCEPT"
# ensure_rule "filter" "FORWARD" "-i ${OUTER_INTERFACE} -p udp --dport ${port} -m state --state NEW -j LOG --log-prefix \"drop INPUT\""
# ensure_rule "filter" "FORWARD" "-i ${OUTER_INTERFACE} -p udp --dport ${port} -m state --state NEW -m set ! --match-set allowed_ip src -j LOG"
ensure_rule "filter" "FORWARD" "-i ${OUTER_INTERFACE} -p udp --dport ${port} -m state --state NEW -m set ! --match-set ${IPSET_GROUP} src -j DROP"
ensure_rule "filter" "FORWARD" "-i ${OUTER_INTERFACE} -p udp --dport ${port} -m state --state NEW -m set --match-set ${IPSET_GROUP} src -j ACCEPT"
}
restricted_cone_clear() {
fullcone_clear
clear_rule "filter" "FORWARD" "-i ${OUTER_INTERFACE} -p udp --dport ${port} -m state --state ESTABLISHED,RELATED -j ACCEPT"
clear_rule "filter" "FORWARD" "-i ${OUTER_INTERFACE} -p udp --dport ${port} -m state --state NEW -j DROP"
}
port_restricted_cone() {
ensure_tcp_connection
ensure_rule "nat" "POSTROUTING" "-o ${OUTER_INTERFACE} -p udp --sport ${port} -j MASQUERADE"
}
port_restricted_cone_clear() {
clear_rule "nat" "POSTROUTING" "-o ${OUTER_INTERFACE} -p udp --sport ${port} -j MASQUERADE"
}
symmetric() {
ensure_rule "nat" "POSTROUTING" "-o ${OUTER_INTERFACE} -p udp --sport ${port} -j MASQUERADE --random"
}
symmetric_clear() {
clear_rule "nat" "POSTROUTING" "-o ${OUTER_INTERFACE} -p udp --sport ${port} -j MASQUERADE --random"
}
case $NAT_TYPE in
"nat1")
fullcone
echo "full cone"
;;
"nat2")
restricted_cone
echo "restricted cone"
;;
"nat3")
port_restricted_cone
echo "port restricted cone"
;;
"nat4")
symmetric
echo "symmetric nat"
;;
*)
echo "invalid nat type"
;;
esac
# iptables -t nat -C POSTROUTING -p tcp -j ${POST_TCP} > /dev/null 2>&1
#
#
# iptables -t nat -F ${POST_TCP} > /dev/null 2&>1
# iptables -t nat -N ${POST_TCP}
# iptables -t nat -A POSTROUTING -p tcp -j ${POST_TCP}
# iptables -t nat -A ${POST_TCP} -p tcp --dport ${PUNCHNET_TCP_PORT}
# iptables -t nat -A ${POST_TCP} -j RETURN
#
# iptables -t nat -D POSTROUTING -p udp -j ${POST_UDP} > /dev/null 2&>1
# iptables -t nat -F ${POST_UDP} > /dev/null 2&>1
# iptables -t nat -N ${POST_UDP}
#
# iptables -t nat -A POSTROUTING -o eth0 -p tcp --dport 18083 -j MASQUERADE
# iptables -t nat -A POSTROUTING -o eth0 -p udp --sport 7890 -j MASQUERADE
# iptables -t nat -A PREROUTING -i eth0 -p udp --dport 7890 -j DNAT --to-destination 172.17.0.2

12
punchnet.service Normal file
View File

@ -0,0 +1,12 @@
[Unit]
Description=punchnet client
Before=network.target network.service
Wants=network.target
[Service]
Type=simple
WorkingDirectory=/usr/local/punchnet
ExecStart=/usr/local/punchnet/punchnet
[Install]
WantedBy=multi-user.target

4
remote.record Normal file
View File

@ -0,0 +1,4 @@
origin git@git.asxalex.pw:rust/sdlan-lib-rs.git (fetch)
origin git@git.asxalex.pw:rust/sdlan-lib-rs.git (push)
origin2 http://101.43.184.190:3000/xlf/sdlan-lib-rs.git (fetch)
origin2 http://101.43.184.190:3000/xlf/sdlan-lib-rs.git (push)

1
run.sh Executable file
View File

@ -0,0 +1 @@
LD_LIBRARY_PATH=. ./sdlan

0
src/bin/build_pb/main.rs Normal file → Executable file
View File

53
src/bin/sdlan/main.rs → src/bin/punchnet/main.rs Normal file → Executable file
View File

@ -1,36 +1,51 @@
use sdlan_rs::get_edge; use punchnet::get_edge;
use sdlan_rs::run_sdlan; use punchnet::run_sdlan;
use sdlan_rs::CommandLine; use punchnet::CommandLine;
use sdlan_rs::CommandLineInput; use punchnet::CommandLineInput;
use sdlan_sn_rs::log; use sdlan_sn_rs::log;
use std::process::exit; use tracing::error;
use std::time::Duration; use std::time::Duration;
use structopt::StructOpt; use structopt::StructOpt;
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
// let _guard = rolling_file::new_log(
// "./.output",
// 7,
// rolling_file::PeriodGap::Daily,
// tracing::Level::DEBUG,
// true,
// true,
// );
let _guard = log::init_log(); let _guard = log::init_log();
let cmd = CommandLineInput::from_args(); let cmd = CommandLineInput::from_args();
// println!("port is {}", cmd.port);
let (tx, rx) = std::sync::mpsc::channel(); let (tx, rx) = std::sync::mpsc::channel();
let server = "punchnet.aioe.tech".to_owned();
let _ = run_sdlan( let _ = run_sdlan(
CommandLine { CommandLine {
sn: "39.98.184.67:1265".to_owned(), sn: server.clone()+":1265",
tcp: "39.98.184.67:18083".to_owned(), tcp: server.clone()+":18083",
nat_server1: "39.98.184.67:1265".to_owned(), nat_server1: server.clone() +":1265",
nat_server2: "47.98.178.3:1265".to_owned(), nat_server2: "47.98.178.3:1265".to_owned(),
_allow_routing: true, _allow_routing: true,
_drop_multicast: true,
register_ttl: 1, register_ttl: 1,
mtu: 1290, mtu: 1400,
name: "tau".to_owned(), name: "tau".to_owned(),
tos: 0, tos: 0,
token: "".to_owned(), local_port: cmd.port,
token: cmd.token.clone(),
network_code: cmd.network_code.clone(),
allow_p2p: true, allow_p2p: true,
}, },
tx, tx,
&sdlan_rs::get_install_channel(), &punchnet::get_install_channel(),
None, None,
) )
.await; .await;
@ -39,14 +54,20 @@ async fn main() {
let edge = get_edge(); let edge = get_edge();
// let res = edge.start_without_feedback(cmd.token).await; // let res = edge.start_without_feedback(cmd.token).await;
let Ok(res) = edge /*
let res = match edge
.start_with_feedback(cmd.token, Duration::from_secs(3)) .start_with_feedback(cmd.token, Duration::from_secs(3))
.await .await
else { {
println!("failed to start1"); Ok(res) => res,
Err(e) => {
error!("failed to start: {:?}", e);
exit(0); exit(0);
}
}; };
debug!("here1");
if res.result != 0 { if res.result != 0 {
println!("failed to start: {}", res.message); println!("failed to start: {}", res.message);
if res.should_exit { if res.should_exit {
@ -55,6 +76,10 @@ async fn main() {
// edge.stop().await; // edge.stop().await;
// exit(0); // exit(0);
} }
*/
if let Err(e) = edge.start_without_feedback(cmd.token).await {
error!("failed to start: {:?}", e);
}
/* /*
tokio::time::sleep(Duration::from_secs(20)).await; tokio::time::sleep(Duration::from_secs(20)).await;

6
src/config/mod.rs Normal file → Executable file
View File

@ -1,4 +1,6 @@
pub const REGISTER_INTERVAL: u8 = 20; use sdlan_sn_rs::utils::Mac;
pub const REGISTER_INTERVAL: u8 = 3;
pub const REGISTER_SUPER_INTERVAL: u16 = 20; pub const REGISTER_SUPER_INTERVAL: u16 = 20;
pub const MULITCAST_V4: [u8; 4] = [224, 0, 0, 69]; pub const MULITCAST_V4: [u8; 4] = [224, 0, 0, 69];
@ -7,3 +9,5 @@ pub const MULTICAST_PORT: u16 = 1970;
// pub const SUPER_ATTEMPTS_DEFAULT: u8 = 3; // pub const SUPER_ATTEMPTS_DEFAULT: u8 = 3;
pub const TCP_PING_TIME: u64 = 7; pub const TCP_PING_TIME: u64 = 7;
pub const NULL_MAC: Mac = [0, 0, 0, 0, 0, 0];

28
src/lib.rs Normal file → Executable file
View File

@ -9,12 +9,12 @@ use std::{sync::atomic::AtomicU8, time::Duration};
use std::net::{SocketAddr, ToSocketAddrs}; use std::net::{SocketAddr, ToSocketAddrs};
pub use network::get_edge; pub use network::get_edge;
use network::{async_main, init_edge, NodeConfig}; pub use network::get_install_channel;
use network::{async_main, init_arp, init_edge, NodeConfig};
use tokio::sync::mpsc::{channel, Sender}; use tokio::sync::mpsc::{channel, Sender};
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use tracing::{debug, error}; use tracing::{debug, error};
pub use utils::{CommandLine, CommandLineInput}; pub use utils::{CommandLine, CommandLineInput};
pub use network::get_install_channel;
use sdlan_sn_rs::{ use sdlan_sn_rs::{
peer::SdlanSock, peer::SdlanSock,
@ -34,15 +34,25 @@ pub async fn run_sdlan(
sender: std::sync::mpsc::Sender<bool>, sender: std::sync::mpsc::Sender<bool>,
install_channel: &str, install_channel: &str,
connecting_chan: Option<Sender<ConnectionState>> connecting_chan: Option<Sender<ConnectionState>>, // start_stop_sender: Sender<String>,
// start_stop_sender: Sender<String>,
// start_stop_receiver: Receiver<String>, // start_stop_receiver: Receiver<String>,
) -> Result<()> { ) -> Result<()> {
let (start_stop_sender, start_stop_chan) = channel(20); let (start_stop_sender, start_stop_chan) = channel(20);
let edge_uuid = create_or_load_uuid("")?; let edge_uuid = create_or_load_uuid("")?;
let node_conf = parse_config(edge_uuid, &args).await?; let node_conf = parse_config(edge_uuid, &args).await?;
if let Err(e) = init_edge(&args.token, node_conf, args.tos, start_stop_sender).await { init_arp();
if let Err(e) = init_edge(
&args.token,
&args.network_code,
node_conf,
args.tos,
start_stop_sender,
args.mtu,
)
.await
{
panic!("failed to init edge: {:?}", e); panic!("failed to init edge: {:?}", e);
} }
let _ = sender.send(true); let _ = sender.send(true);
@ -51,7 +61,9 @@ pub async fn run_sdlan(
let cancel = CancellationToken::new(); let cancel = CancellationToken::new();
let install_chan = install_channel.to_owned(); let install_chan = install_channel.to_owned();
tokio::spawn(async move { tokio::spawn(async move {
if let Err(e) = async_main(install_chan, args, start_stop_chan, cancel, connecting_chan).await { if let Err(e) =
async_main(install_chan, args, start_stop_chan, cancel, connecting_chan).await
{
error!("failed to run async main: {}", e.as_str()); error!("failed to run async main: {}", e.as_str());
} }
}); });
@ -109,13 +121,13 @@ async fn parse_config(uuid: String, args: &CommandLine) -> Result<NodeConfig> {
let node_conf = NodeConfig { let node_conf = NodeConfig {
name: args.name.to_owned(), name: args.name.to_owned(),
allow_routing: true, allow_routing: true,
_drop_multicast: false, _drop_multicast: true,
allow_p2p: args.allow_p2p, allow_p2p: args.allow_p2p,
mtu: args.mtu, mtu: args.mtu,
_tos: 0, _tos: 0,
_register_super_interval: config::REGISTER_SUPER_INTERVAL, _register_super_interval: config::REGISTER_SUPER_INTERVAL,
register_ttl, register_ttl,
_local_port: 0, _local_port: args.local_port as u16,
node_uuid: uuid, node_uuid: uuid,
super_nodes: sockaddr, super_nodes: sockaddr,
super_node_index: AtomicU8::new(0), super_node_index: AtomicU8::new(0),

416
src/network/arp.rs Executable file
View File

@ -0,0 +1,416 @@
use std::{
collections::HashMap,
sync::atomic::{AtomicU8, Ordering},
time::Duration,
};
use tracing::error;
use once_cell::sync::OnceCell;
use sdlan_sn_rs::utils::{net_bit_len_to_mask, Mac, BROADCAST_MAC, MULTICAST_MAC};
use tokio::sync::{
mpsc::{channel, Receiver, Sender},
oneshot,
};
use super::{get_edge, get_route_table, init_arp_wait_list, init_route};
static GLOBAL_ARP: OnceCell<ArpActor> = OnceCell::new();
pub fn init_arp() {
init_route();
init_arp_wait_list();
let actor = ArpActor::new();
GLOBAL_ARP.set(actor).unwrap();
}
pub fn get_arp() -> &'static ArpActor {
GLOBAL_ARP.get().unwrap()
}
const ETHER_TYPE_ARP: u16 = 0x0806;
const ETHER_TYPE_IP: u16 = 0x0800;
#[allow(unused)]
const ETHER_TYPE_IP6: u16 = 0x86dd;
const ARP_MAX_AGE: u8 = 128;
const ARP_HWTYPE_ETH: u16 = 1;
pub const ARP_REQUEST: u16 = 1;
pub const ARP_REPLY: u16 = 2;
#[repr(C)]
pub struct EthHdr {
pub dest: [u8; 6],
pub src: [u8; 6],
pub eth_type: u16,
}
#[repr(C)]
pub struct ArpHdr {
pub ethhdr: EthHdr,
pub hwtype: u16,
pub protocol: u16,
pub hwlen: u8,
pub protolen: u8,
pub opcode: u16,
pub shwaddr: [u8; 6],
pub sipaddr: [u16; 2],
pub dhwaddr: [u8; 6],
pub dipaddr: [u16; 2],
}
impl ArpHdr {
pub fn from_slice(data: &[u8]) -> Self {
if data.len() < 42 {
panic!("data size error");
}
Self {
ethhdr: EthHdr {
dest: data[0..6].try_into().unwrap(),
src: data[6..12].try_into().unwrap(),
eth_type: u16::from_be_bytes(data[12..14].try_into().unwrap()),
},
hwtype: u16::from_be_bytes(data[14..16].try_into().unwrap()),
protocol: u16::from_be_bytes(data[16..18].try_into().unwrap()),
hwlen: data[18],
protolen: data[19],
opcode: u16::from_be_bytes(data[20..22].try_into().unwrap()),
shwaddr: data[22..28].try_into().unwrap(),
sipaddr: [
u16::from_be_bytes(data[28..30].try_into().unwrap()),
u16::from_be_bytes(data[30..32].try_into().unwrap()),
],
dhwaddr: data[32..38].try_into().unwrap(),
dipaddr: [
u16::from_be_bytes(data[38..40].try_into().unwrap()),
u16::from_be_bytes(data[40..42].try_into().unwrap()),
],
}
}
pub fn marshal_to_bytes(&self) -> Vec<u8> {
let mut result = Vec::with_capacity(64);
result.extend_from_slice(&self.ethhdr.dest);
result.extend_from_slice(&self.ethhdr.src);
result.extend_from_slice(&self.ethhdr.eth_type.to_be_bytes());
result.extend_from_slice(&self.hwtype.to_be_bytes());
result.extend_from_slice(&self.protocol.to_be_bytes());
result.push(self.hwlen);
result.push(self.protolen);
result.extend_from_slice(&self.opcode.to_be_bytes());
result.extend_from_slice(&self.shwaddr);
result.extend_from_slice(&self.sipaddr[0].to_be_bytes());
result.extend_from_slice(&self.sipaddr[1].to_be_bytes());
result.extend_from_slice(&self.dhwaddr);
result.extend_from_slice(&self.dipaddr[0].to_be_bytes());
result.extend_from_slice(&self.dipaddr[1].to_be_bytes());
// result.extend_from_slice(&[0; 18]);
// let crc = CRC_HASH.checksum(&result).to_be_bytes();
// result.extend_from_slice(&crc);
result
}
pub fn new() -> Self {
Self {
ethhdr: EthHdr {
dest: [0; 6],
src: [0; 6],
eth_type: ETHER_TYPE_ARP,
},
hwtype: ARP_HWTYPE_ETH,
protocol: ETHER_TYPE_IP,
hwlen: 6,
protolen: 4,
opcode: ARP_REQUEST,
shwaddr: [0; 6],
sipaddr: [0; 2],
dhwaddr: [0; 6],
dipaddr: [0; 2],
}
}
}
// const ARP_TABLE_SIZE: usize = 8;
static ARPTIME: AtomicU8 = AtomicU8::new(0);
const BROADCAST_IPADDR: u32 = 0xffffffff;
#[derive(Debug)]
#[allow(unused)]
pub struct ArpEntry {
ip_addr: u32,
arptime: u8,
hw_addr: [u8; 6],
}
/*
impl ArpEntry {
pub fn new() -> Self {
Self {
ip_addr: 0,
arptime: 0,
hw_addr: [0; 6],
}
}
}
*/
pub struct ArpInfo {
// host_ip: AtomicU32,
// ip representation of mask
// host_netmask: AtomicU32,
entry: HashMap<u32, ArpEntry>,
// entry: [ArpEntry; ARP_TABLE_SIZE],
}
impl ArpInfo {
fn lookup_ip_mac(&self, ip: u32) -> ([u8; 6], u32, bool) {
if ip == BROADCAST_IPADDR {
return (BROADCAST_MAC, ip, false);
}
let edge = get_edge();
let netbit = edge.device_config.get_net_bit();
let host_netmask = net_bit_len_to_mask(netbit);
let host_netmask_reverse = !host_netmask;
if (ip & host_netmask_reverse) == host_netmask_reverse {
return (BROADCAST_MAC, ip, false);
}
let first_ip = (ip >> 24) as u8 & 0xff;
if first_ip >= 224 && first_ip <= 239 {
let mut multi = MULTICAST_MAC;
multi[3] = (ip >> 16) as u8 & 0x7f;
multi[4] = (ip >> 8) as u8 & 0xff;
multi[5] = (ip) as u8 & 0xff;
return (multi, ip, false);
}
let mut target_ip = 0;
let host_ip = edge.device_config.get_ip();
if (ip & host_netmask) == (host_ip & host_netmask) {
target_ip = ip;
}
if target_ip == 0 {
let route_table = get_route_table();
if let Some(gateway_ip) = route_table.get_gateway_ip(ip) {
target_ip = gateway_ip;
}
}
if target_ip == 0 {
panic!("target should not route to me");
}
if let Some(entry) = self.entry.get(&target_ip) {
return (entry.hw_addr, target_ip, false);
}
/*
for i in 0..ARP_TABLE_SIZE {
let item = &self.entry[i];
if item.ip_addr == target_ip {
return (item.hw_addr, target_ip, false);
}
}
*/
return (BROADCAST_MAC, target_ip, true);
}
fn set_arp(&mut self, mac: [u8; 6], ip: u32) {
// println!("setting ip: {:?} is at {:?}", ip.to_be_bytes(), mac);
let nowage = ARPTIME.load(Ordering::Relaxed);
self.entry.insert(
ip,
ArpEntry {
ip_addr: ip,
hw_addr: mac,
arptime: nowage,
},
);
/*
for i in 0..ARP_TABLE_SIZE {
let item = &mut self.entry[i];
if item.ip_addr != 0 {
if item.ip_addr == ip {
item.hw_addr = mac;
let nowage = ARPTIME.load(Ordering::Relaxed);
item.arptime = nowage;
return;
}
}
}
*/
/*
println!("set_arp 1");
let mut itemindex = ARP_TABLE_SIZE;
for i in 0..ARP_TABLE_SIZE {
let temp = &self.entry[i];
println!("set arp 2");
if temp.ip_addr == 0 {
itemindex = i;
println!("set arp 3: itemindex = {}", itemindex);
break;
}
}
let arptime = ARPTIME.load(Ordering::Relaxed);
if itemindex == ARP_TABLE_SIZE {
println!("set_arp 4");
let mut tmpage = 0;
let mut idx = 0;
for i in 0..ARP_TABLE_SIZE {
let temp = &self.entry[i];
if (arptime - temp.arptime) > tmpage {
tmpage = arptime - temp.arptime;
idx = i;
}
}
itemindex = idx;
}
println!("set_arp 5");
let temp = &mut self.entry[itemindex];
temp.arptime = arptime;
temp.ip_addr = ip;
temp.hw_addr = mac;
println!("set arp 6: idx={} => {:?}", itemindex, temp);
*/
}
fn timer(&mut self) {
let timer = ARPTIME.fetch_add(1, Ordering::Relaxed);
let mut todelete = vec![];
for (ip, entry) in &self.entry {
if (timer - entry.arptime) >= ARP_MAX_AGE {
todelete.push(*ip);
}
}
for ip in todelete {
self.entry.remove(&ip);
}
/*
for i in 0..ARP_TABLE_SIZE {
let item = &mut self.entry[i];
if item.ip_addr != 0 && (timer - item.arptime) >= ARP_MAX_AGE {
item.ip_addr = 0;
}
}
*/
}
}
pub enum ArpRequestInfo {
Lookup { ip: u32 },
Set { ip: u32, mac: Mac },
}
pub struct ArpRequest {
req: ArpRequestInfo,
tx: oneshot::Sender<ArpResponse>,
}
#[derive(Debug)]
#[allow(unused)]
pub enum ArpResponse {
LookupResp {
mac: Mac,
ip: u32,
do_arp_request: bool,
},
SetResp {
ok: bool,
},
ArpRespError {
msg: String,
},
}
#[derive(Debug)]
pub struct ArpActor {
pub tx: Sender<ArpRequest>,
}
impl ArpActor {
pub fn new() -> Self {
let (tx, rx) = channel(20);
tokio::spawn(loop_arp_info(rx));
Self { tx }
}
}
async fn loop_arp_info(mut rx: Receiver<ArpRequest>) {
let mut arp = ArpInfo {
// entry: array::from_fn(|_i| ArpEntry::new()),
entry: HashMap::new(),
};
loop {
tokio::select! {
data = rx.recv() => {
if let Some(d) = data {
match d.req {
ArpRequestInfo::Lookup{ip} => {
let mac = arp.lookup_ip_mac(ip);
if let Err(e) = d.tx.send(ArpResponse::LookupResp {
mac: mac.0, ip: mac.1, do_arp_request: mac.2 }
) {
error!("failed to send back arp lookup feedback: {:?}", e);
};
}
ArpRequestInfo::Set{ip, mac} => {
arp.set_arp(mac, ip);
if let Err(e) = d.tx.send(ArpResponse::SetResp { ok: true }) {
error!("failed to send back arp set feedback: {:?}", e);
}
}
}
}
}
_ = tokio::time::sleep(Duration::from_secs(10)) => {
arp.timer();
}
}
}
}
pub async fn send_arp_request(data: ArpRequestInfo) -> ArpResponse {
let (tx, rx) = oneshot::channel();
let arp = get_arp();
if let Err(e) = arp.tx.send(ArpRequest { tx, req: data }).await {
error!("failed to send arp request: {}", e);
return ArpResponse::ArpRespError {
msg: "failed to send arp request".to_owned(),
};
}
match rx.await {
Ok(res) => res,
Err(e) => ArpResponse::ArpRespError { msg: e.to_string() },
}
}
pub fn generate_arp_request(srcmac: [u8; 6], dstip: u32, srcip: u32) -> Vec<u8> {
let mut arphdr = ArpHdr::new();
arphdr.ethhdr.dest = [0xff; 6];
arphdr.dhwaddr = [0; 6];
arphdr.ethhdr.src = srcmac;
arphdr.shwaddr = srcmac;
arphdr.dipaddr = [(dstip >> 16) as u16, (dstip & 0xffff) as u16];
arphdr.sipaddr = [(srcip >> 16) as u16, (srcip & 0xffff) as u16];
/*
println!(
"arphdr.sipaddr: {:?}, {:?}",
arphdr.sipaddr[0].to_be_bytes(),
arphdr.sipaddr[1].to_be_bytes()
);
println!(
"arphdr.dipaddr: {:?}, {:?}",
arphdr.dipaddr[0].to_be_bytes(),
arphdr.dipaddr[1].to_be_bytes()
);
*/
arphdr.marshal_to_bytes()
}

187
src/network/async_main.rs Normal file → Executable file
View File

@ -3,23 +3,22 @@ use std::sync::atomic::Ordering;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use crate::config::TCP_PING_TIME; use crate::config::{NULL_MAC, TCP_PING_TIME};
use crate::network::ipv6::run_ipv6; use crate::network::ipv6::run_ipv6;
use crate::network::{get_edge, ping_to_sn, read_and_parse_packet, RegisterSuperFeedback}; use crate::network::{
get_edge, ping_to_sn, read_and_parse_packet, RegisterSuperFeedback, TunTapPacketHandler,
};
use crate::pb::{ use crate::pb::{
encode_to_tcp_message, encode_to_udp_message, SdlData, SdlDevAddr, SdlRegisterSuper, encode_to_tcp_message, encode_to_udp_message, SdlDevAddr, SdlRegisterSuper,
SdlRegisterSuperAck, SdlRegisterSuperNak, SdlSendRegisterEvent, SdlStunRequest, Sdlv6Info, SdlRegisterSuperAck, SdlRegisterSuperNak, SdlSendRegisterEvent, SdlStunRequest, Sdlv6Info,
}; };
use crate::tcp::{init_tcp_conn, EventType, NakMsgCode, PacketType, SdlanTcp}; use crate::tcp::{init_tcp_conn, EventType, NakMsgCode, NatType, PacketType, SdlanTcp};
use crate::utils::{send_to_sock, CommandLine}; use crate::utils::{send_to_sock, CommandLine};
use crate::ConnectionState; use crate::ConnectionState;
use etherparse::IpHeaders; use sdlan_sn_rs::config::AF_INET;
use sdlan_sn_rs::config::{AF_INET, AF_INET6, SDLAN_DEFAULT_TTL};
use sdlan_sn_rs::peer::{SdlanSock, V6Info}; use sdlan_sn_rs::peer::{SdlanSock, V6Info};
use sdlan_sn_rs::utils::Result; use sdlan_sn_rs::utils::{get_current_timestamp, ip_to_string, is_multi_broadcast, rsa_decrypt};
use sdlan_sn_rs::utils::{ use sdlan_sn_rs::utils::{Mac, Result, gen_rsa_keys};
aes_encrypt, get_current_timestamp, ip_to_string, is_multi_broadcast, rsa_decrypt,
};
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
use tokio::sync::mpsc::{channel, Receiver, Sender}; use tokio::sync::mpsc::{channel, Receiver, Sender};
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
@ -28,7 +27,7 @@ use super::{check_peer_registration_needed, packet, Node, StartStopInfo};
use crate::utils::Socket; use crate::utils::Socket;
use prost::Message; use prost::Message;
use tracing::{debug, error, info}; use tracing::{debug, error};
async fn handle_tcp_message(msg: SdlanTcp) { async fn handle_tcp_message(msg: SdlanTcp) {
let edge = get_edge(); let edge = get_edge();
@ -62,11 +61,19 @@ async fn handle_tcp_message(msg: SdlanTcp) {
}; };
let ip = ip_to_string(&dev.net_addr); let ip = ip_to_string(&dev.net_addr);
debug!("aes key is {:?}, ip is {}/{}", aes, ip, dev.net_bit_len,); // debug!("aes key is {:?}, ip is {}/{}", aes, ip, dev.net_bit_len,);
println!("assigned ip: {}", ip);
edge.device_config edge.device_config
.ip .ip
.net_addr .net_addr
.store(dev.net_addr, Ordering::Relaxed); .store(dev.net_addr, Ordering::Relaxed);
/*
let mac = match dev.mac.try_into() {
Err(_) => NULL_MAC,
Ok(m) => m,
};
*/
// *edge.device_config.mac.write().unwrap() = mac;
edge.device_config edge.device_config
.ip .ip
.net_bit_len .net_bit_len
@ -78,7 +85,7 @@ async fn handle_tcp_message(msg: SdlanTcp) {
send_stun_request(edge).await; send_stun_request(edge).await;
tokio::spawn(async { tokio::spawn(async {
let nattype = edge.probe_nat_type().await; let nattype = edge.probe_nat_type().await;
println!("nat type is: {:?}", nattype); // println!("nat type is: {:?}", nattype);
}); });
} }
PacketType::RegisterSuperNAK => { PacketType::RegisterSuperNAK => {
@ -183,7 +190,7 @@ async fn handle_tcp_message(msg: SdlanTcp) {
async fn handle_tcp_command(_edge: &Node, _cmdtype: u8, _cmdprotobuf: &[u8]) {} async fn handle_tcp_command(_edge: &Node, _cmdtype: u8, _cmdprotobuf: &[u8]) {}
async fn handle_tcp_event(edge: &Node, eventtype: EventType, eventprotobuf: &[u8]) { async fn handle_tcp_event(edge: &'static Node, eventtype: EventType, eventprotobuf: &[u8]) {
match eventtype { match eventtype {
EventType::SendRegister => { EventType::SendRegister => {
let Ok(reg) = SdlSendRegisterEvent::decode(eventprotobuf) else { let Ok(reg) = SdlSendRegisterEvent::decode(eventprotobuf) else {
@ -200,11 +207,24 @@ async fn handle_tcp_event(edge: &Node, eventtype: EventType, eventprotobuf: &[u8
}); });
} }
} }
let dst_mac = match reg.dst_mac.try_into() {
Ok(m) => m,
Err(_e) => NULL_MAC,
};
let remote_nat_byte = reg.nat_type as u8;
let remote_nat = match remote_nat_byte.try_into() {
Ok(t) => t,
Err(_) => NatType::NoNat,
};
check_peer_registration_needed( check_peer_registration_needed(
edge, edge,
true, false,
reg.dst_ip, dst_mac,
// &v6_sock, // &v6_sock,
remote_nat,
&v6_sock, &v6_sock,
&SdlanSock { &SdlanSock {
family: AF_INET, family: AF_INET,
@ -231,7 +251,7 @@ pub async fn async_main(
// let _ = PidRecorder::new(".pid"); // let _ = PidRecorder::new(".pid");
// // gen public key // // gen public key
// gen_rsa_keys(".client"); gen_rsa_keys(".client");
// let mut pubkey = String::new(); // let mut pubkey = String::new();
// File::open(".client/id_rsa.pub")?.read_to_string(&mut pubkey)?; // File::open(".client/id_rsa.pub")?.read_to_string(&mut pubkey)?;
// let privatekey = load_private_key_file(".client/id_rsa")?; // let privatekey = load_private_key_file(".client/id_rsa")?;
@ -270,6 +290,7 @@ pub async fn async_main(
let installed_channel = install_channel.to_owned(); let installed_channel = install_channel.to_owned();
Box::pin(async move { Box::pin(async move {
let token = edge._token.lock().unwrap().clone(); let token = edge._token.lock().unwrap().clone();
let code = edge.network_code.lock().unwrap().clone();
// let edge = get_edge(); // let edge = get_edge();
// let edge = get_edge(); // let edge = get_edge();
// let token = args.token.clone(); // let token = args.token.clone();
@ -288,12 +309,14 @@ pub async fn async_main(
installed_channel, installed_channel,
client_id: edge.config.node_uuid.clone(), client_id: edge.config.node_uuid.clone(),
dev_addr: Some(SdlDevAddr { dev_addr: Some(SdlDevAddr {
mac: Vec::from(edge.device_config.get_mac()),
net_addr: 0, net_addr: 0,
network_id: 0, network_id: 0,
net_bit_len: 0, net_bit_len: 0,
}), }),
pub_key: edge.rsa_pubkey.clone(), pub_key: edge.rsa_pubkey.clone(),
token, token,
network_code: code,
}; };
// debug!("send register super: {:?}", register_super); // debug!("send register super: {:?}", register_super);
let packet_id = match pkt_id { let packet_id = match pkt_id {
@ -404,9 +427,9 @@ async fn run_edge_loop(eee: &'static Node, cancel: CancellationToken) {
tokio::spawn(async move { tokio::spawn(async move {
loop_socket_v4(eee, &eee.udp_sock_v4, cancel, false).await; loop_socket_v4(eee, &eee.udp_sock_v4, cancel, false).await;
}); });
tokio::spawn(async move { if let Some(ref multicast) = eee.udp_sock_multicast {
loop_socket_v4(eee, &eee.udp_sock_multicast, cancel2, true).await; loop_socket_v4(eee, &multicast, cancel2, true).await;
}); }
} }
{ {
@ -429,6 +452,7 @@ async fn send_stun_request(eee: &Node) {
client_id: eee.config.node_uuid.clone(), client_id: eee.config.node_uuid.clone(),
network_id: eee.network_id.load(Ordering::Relaxed), network_id: eee.network_id.load(Ordering::Relaxed),
ip: eee.device_config.get_ip(), ip: eee.device_config.get_ip(),
mac: Vec::from(eee.device_config.get_mac()),
nat_type: eee.get_nat_type() as u32, nat_type: eee.get_nat_type() as u32,
v6_info: sdl_v6_info, v6_info: sdl_v6_info,
}; };
@ -445,7 +469,7 @@ async fn send_stun_request(eee: &Node) {
} }
} }
pub async fn loop_socket_v6(eee: &Node, socket: Arc<Socket>, cancel: CancellationToken) { pub async fn loop_socket_v6(eee: &'static Node, socket: Arc<Socket>, cancel: CancellationToken) {
debug!("loop sock v6"); debug!("loop sock v6");
loop { loop {
tokio::select! { tokio::select! {
@ -473,35 +497,34 @@ pub async fn loop_socket_v6(eee: &Node, socket: Arc<Socket>, cancel: Cancellatio
} }
pub async fn loop_socket_v4( pub async fn loop_socket_v4(
eee: &Node, eee: &'static Node,
socket: &Socket, socket: &Socket,
cancel: CancellationToken, cancel: CancellationToken,
is_multicast_sock: bool, is_multicast_sock: bool,
) { ) {
debug!("loop sock v4"); debug!("loop sock v4");
let cancel_clone = cancel.clone();
tokio::spawn(async move {
loop {
tokio::select! {
_ = cancel_clone.cancelled() => {
break;
}
_ = tokio::time::sleep(Duration::from_secs(10)) => {
if !is_multicast_sock {
send_stun_request(eee).await;
}
}
}
}
});
loop { loop {
tokio::select! { tokio::select! {
_ = cancel.cancelled() => { _ = cancel.cancelled() => {
break; break;
} }
_ = read_and_parse_packet(eee, socket, Some(Duration::from_secs(10)), is_multicast_sock) => { } _ = read_and_parse_packet(eee, socket, Some(Duration::from_secs(10)), is_multicast_sock) => { }
_ = tokio::time::sleep(Duration::from_secs(10)) => {
if !is_multicast_sock {
send_stun_request(eee).await;
}
/*
let req = SdlStunRequest {
cookie: 0,
client_id: eee.config.node_uuid.clone(),
network_id: eee.network_id.load(Ordering::Relaxed),
ip: eee.device_config.get_ip(),
nat_type: 0,
};
let msg = encode_to_udp_message(Some(req), PacketType::StunRequest as u8).unwrap();
if let Err(e) = send_to_sock(eee, &msg, &eee.config.super_nodes[eee.config.super_node_index.load(Ordering::Relaxed) as usize]).await {
error!("failed to send to sock: {:?}", e);
}*/
}
} }
} }
debug!("loop_socket_v4 exited"); debug!("loop_socket_v4 exited");
@ -534,7 +557,7 @@ async fn loop_tap(eee: &'static Node, cancel: CancellationToken) {
async fn get_tun_flow(eee: &'static Node, tx: Sender<Vec<u8>>) { async fn get_tun_flow(eee: &'static Node, tx: Sender<Vec<u8>>) {
loop { loop {
let buf = tokio::task::spawn_blocking(|| { let buf = tokio::task::spawn_blocking(|| {
let mut buf = vec![0; 1800]; let mut buf = vec![0; 1500];
let Ok(size) = eee.device.recv(&mut buf) else { let Ok(size) = eee.device.recv(&mut buf) else {
return vec![]; return vec![];
}; };
@ -569,71 +592,33 @@ async fn read_and_parse_tun_packet(eee: &'static Node, buf: Vec<u8>) {
*/ */
// buf.truncate(size); // buf.truncate(size);
edge_send_packet_to_net(eee, &buf).await; edge_send_packet_to_net(eee, buf).await;
} }
async fn edge_send_packet_to_net(eee: &Node, data: &[u8]) { async fn edge_send_packet_to_net(eee: &Node, data: Vec<u8>) {
debug!("edge send packet to net({} bytes): {:?}", data.len(), data); // debug!("edge send packet to net({} bytes): {:?}", data.len(), data);
match IpHeaders::from_slice(&data) {
Ok((iphdr, _payload)) => {
let Some(ipv4hdr) = iphdr.ipv4() else {
debug!("ipv6 packet ignored");
return;
};
let dstip = u32::from_be_bytes(ipv4hdr.0.destination);
debug!("packet dst ip: {:?}", ipv4hdr.0.destination);
let src = u32::from_be_bytes(ipv4hdr.0.source);
debug!("packet src ip: {:?}", ipv4hdr.0.source);
// packet should be sent to dev
debug!("got {} bytes from tun", data.len());
if (!eee.config.allow_routing) && (src != eee.device_config.get_ip()) {
info!("dropping routed packet");
return;
}
if !eee.is_authorized() {
debug!("drop tun packet due to not authed");
return;
}
let encrypt_key = eee.get_encrypt_key(); let encrypt_key = eee.get_encrypt_key();
if encrypt_key.len() == 0 { if encrypt_key.len() == 0 {
error!("drop tun packet due to encrypt key len is 0"); error!("drop tun packet due to encrypt key len is 0");
return; return;
} }
let msg_size = data.len() as u64; if let Err(e) = eee
let Ok(encrypted_flow) = aes_encrypt(encrypt_key.as_slice(), data) else { .device
error!("failed to encrypt flow"); .handle_packet_from_device(data, encrypt_key.as_slice())
return; .await
}; {
error!("failed to handle packet from device: {}", e.to_string());
let message = SdlData {
// TODO: network id should be stored in
network_id: eee.network_id.load(Ordering::Relaxed),
src_ip: eee.device_config.get_ip(),
dst_ip: dstip,
is_p2p: true,
ttl: SDLAN_DEFAULT_TTL as u32,
data: encrypted_flow,
};
debug!("sending SdlData: {:?}", message);
let Ok(flow) = encode_to_udp_message(Some(message), PacketType::Data as u8) else {
error!("failed to encode to udp message");
return;
};
send_packet_to_net(eee, dstip, &flow, msg_size).await;
}
Err(e) => {
error!("failed to parse ip packet: {}", e.to_string());
}
} }
} }
async fn send_packet_to_net(eee: &Node, dst_ip: u32, pkt: &[u8], size: u64) { pub async fn send_packet_to_net(eee: &'static Node, dst_mac: Mac, pkt: &[u8], size: u64) {
let (dest_sock, is_p2p) = find_peer_destination(eee, dst_ip).await; let (dest_sock, is_p2p) = find_peer_destination(eee, dst_mac).await;
if is_p2p { if is_p2p {
eee.stats.tx_p2p.fetch_add(size, Ordering::Relaxed); eee.stats.tx_p2p.fetch_add(size, Ordering::Relaxed);
} else { } else {
eee.stats.tx_sup.fetch_add(size, Ordering::Relaxed); eee.stats.tx_sup.fetch_add(size, Ordering::Relaxed);
if is_multi_broadcast(dst_ip) { if is_multi_broadcast(&dst_mac) {
eee.stats.tx_broadcast.fetch_add(size, Ordering::Relaxed); eee.stats.tx_broadcast.fetch_add(size, Ordering::Relaxed);
} }
} }
@ -643,8 +628,8 @@ async fn send_packet_to_net(eee: &Node, dst_ip: u32, pkt: &[u8], size: u64) {
} }
} }
async fn find_peer_destination(eee: &Node, dst_ip: u32) -> (SdlanSock, bool) { async fn find_peer_destination(eee: &'static Node, dst_mac: Mac) -> (SdlanSock, bool) {
if is_multi_broadcast(dst_ip) { if is_multi_broadcast(&dst_mac) {
return ( return (
eee.config.super_nodes[eee.config.super_node_index.load(Ordering::Relaxed) as usize] eee.config.super_nodes[eee.config.super_node_index.load(Ordering::Relaxed) as usize]
.deepcopy(), .deepcopy(),
@ -653,28 +638,36 @@ async fn find_peer_destination(eee: &Node, dst_ip: u32) -> (SdlanSock, bool) {
} }
let mut is_p2p = false; let mut is_p2p = false;
let result: SdlanSock; let result: SdlanSock;
if let Some(dst) = eee.known_peers.get_peer(&dst_ip) { let mut need_delete_from_known_peers = false;
if let Some(dst) = eee.known_peers.peers.get_mut(&dst_mac) {
let now = get_current_timestamp(); let now = get_current_timestamp();
if now - dst.last_p2p.load(Ordering::Relaxed) >= ((dst.timeout / 2) as u64) { if now - dst.last_p2p.load(Ordering::Relaxed) >= ((dst.timeout / 2) as u64) {
// too much time elapsed since we saw the peer, need to register again // too much time elapsed since we saw the peer, need to register again
eee.known_peers.delete_peer_with_ip(&dst_ip); error!("last p2p is too old, deleting from known_peers");
need_delete_from_known_peers = true;
// eee.known_peers.delete_peer_with_mac(&dst_mac);
debug!("deleted from known");
result = eee.config.super_nodes result = eee.config.super_nodes
[eee.config.super_node_index.load(Ordering::Relaxed) as usize] [eee.config.super_node_index.load(Ordering::Relaxed) as usize]
.deepcopy(); .deepcopy();
} else { } else {
// dst.last_seen.store(now, Ordering::Relaxed); // dst.last_seen.store(now, Ordering::Relaxed);
is_p2p = true; is_p2p = true;
result = dst.sock.read().unwrap().deepcopy(); result = dst.sock.deepcopy();
} }
} else { } else {
result = eee.config.super_nodes result = eee.config.super_nodes
[eee.config.super_node_index.load(Ordering::Relaxed) as usize] [eee.config.super_node_index.load(Ordering::Relaxed) as usize]
.deepcopy(); .deepcopy();
} }
if need_delete_from_known_peers {
eee.known_peers.delete_peer_with_mac(&dst_mac);
}
// println!("find peer_destination: {}", is_p2p); // println!("find peer_destination: {}", is_p2p);
if !is_p2p { if !is_p2p {
debug!("check_query_peer_info"); debug!("check_query_peer_info");
super::packet::check_query_peer_info(eee, dst_ip).await; super::packet::check_query_peer_info(eee, dst_mac).await;
} }
return (result, is_p2p); return (result, is_p2p);
} }

22
src/network/device.rs Normal file → Executable file
View File

@ -1,12 +1,25 @@
use sdlan_sn_rs::peer::IpSubnet; use std::sync::RwLock;
use crate::utils::mac_to_string;
use sdlan_sn_rs::{peer::IpSubnet, utils::Mac};
use tracing::debug;
use crate::utils::generate_mac_address;
pub struct DeviceConfig { pub struct DeviceConfig {
pub mtu: u32,
pub mac: RwLock<Mac>,
pub ip: IpSubnet, pub ip: IpSubnet,
} }
impl DeviceConfig { impl DeviceConfig {
pub fn new() -> Self { pub fn new(mtu: u32) -> Self {
let mac = generate_mac_address();
println!("self mac: {}", mac_to_string(&mac));
debug!("self mac: {}", mac_to_string(&mac));
DeviceConfig { DeviceConfig {
mtu,
mac: RwLock::new(mac),
ip: IpSubnet::new(0, 0), ip: IpSubnet::new(0, 0),
} }
} }
@ -28,6 +41,11 @@ impl DeviceConfig {
pub fn get_net_bit(&self) -> u8 { pub fn get_net_bit(&self) -> u8 {
self.ip.net_bit_len() self.ip.net_bit_len()
} }
pub fn get_mac(&self) -> Mac {
let mac = *self.mac.read().unwrap();
mac
}
} }
/// The mode in which open the virtual network adapter. /// The mode in which open the virtual network adapter.

23
src/network/ipv6.rs Normal file → Executable file
View File

@ -1,13 +1,16 @@
use std::{net::{IpAddr, Ipv6Addr}, time::Duration};
use std::sync::Mutex; use std::sync::Mutex;
use std::{
net::{IpAddr, Ipv6Addr},
time::Duration,
};
use sdlan_sn_rs::{config::AF_INET6, peer::SdlanSock}; use sdlan_sn_rs::{config::AF_INET6, peer::SdlanSock};
use std::sync::Arc;
use tokio::{net::UdpSocket, sync::mpsc::Receiver}; use tokio::{net::UdpSocket, sync::mpsc::Receiver};
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use tracing::error; use tracing::error;
use std::sync::Arc;
use crate::{network::{loop_socket_v4, loop_socket_v6}, utils::Socket}; use crate::{network::loop_socket_v6, utils::Socket};
use super::Node; use super::Node;
@ -15,11 +18,16 @@ pub async fn run_ipv6(edge: &'static Node, mut v6_may_change: Receiver<bool>) {
v6_may_change.recv().await; v6_may_change.recv().await;
loop { loop {
tokio::time::sleep(Duration::from_secs(1)).await; tokio::time::sleep(Duration::from_secs(1)).await;
let ipv6 = get_current_ipv6(); let mut ipv6 = get_current_ipv6();
if ipv6.is_none() {
tokio::time::sleep(Duration::from_secs(5)).await;
ipv6 = get_current_ipv6();
if ipv6.is_none() { if ipv6.is_none() {
v6_may_change.recv().await; v6_may_change.recv().await;
continue; continue;
} }
}
// ipv6 is not none
let ipv6 = ipv6.unwrap(); let ipv6 = ipv6.unwrap();
/* /*
@ -37,7 +45,6 @@ pub async fn run_ipv6(edge: &'static Node, mut v6_may_change: Receiver<bool>) {
let socket_clone = socket.clone(); let socket_clone = socket.clone();
let cancel = CancellationToken::new(); let cancel = CancellationToken::new();
*edge.ipv6.write().unwrap() = Some(SdlanSock { *edge.ipv6.write().unwrap() = Some(SdlanSock {
family: AF_INET6, family: AF_INET6,
port, port,
@ -68,9 +75,9 @@ pub fn get_current_ipv6() -> Option<Ipv6Addr> {
continue; continue;
} }
IpAddr::V6(ipv6) => { IpAddr::V6(ipv6) => {
if (ipv6.octets()[0] & 0x70 == 0x20) { if ipv6.octets()[0] & 0x70 == 0x20 {
println!("got global ip: {}", ipv6); // println!("got global ip: {}", ipv6);
return Some(ipv6) return Some(ipv6);
} }
} }
} }

10
src/network/mod.rs Normal file → Executable file
View File

@ -9,10 +9,18 @@ mod ipv6;
mod packet; mod packet;
pub use packet::*; pub use packet::*;
mod arp;
pub use arp::*;
mod route;
pub use route::*;
mod tuntap;
pub use tuntap::*;
#[cfg_attr(target_os = "linux", path = "tun_linux.rs")] #[cfg_attr(target_os = "linux", path = "tun_linux.rs")]
#[cfg_attr(target_os = "windows", path = "tun_win.rs")] #[cfg_attr(target_os = "windows", path = "tun_win.rs")]
mod tun; mod tun;
pub use tun::get_install_channel; pub use tun::get_install_channel;
mod device; mod device;

123
src/network/node.rs Normal file → Executable file
View File

@ -1,7 +1,6 @@
use dashmap::DashMap; use dashmap::DashMap;
use rsa::RsaPrivateKey; use rsa::RsaPrivateKey;
use sdlan_sn_rs::config::{AF_INET, AF_INET6}; use sdlan_sn_rs::config::{AF_INET, AF_INET6};
use std::collections::HashMap;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, AtomicU8, Ordering}; use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, AtomicU8, Ordering};
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock};
@ -9,7 +8,7 @@ use std::time::Duration;
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
use tokio::sync::mpsc::Sender; use tokio::sync::mpsc::Sender;
use tokio::sync::oneshot; use tokio::sync::oneshot;
use tracing::error; use tracing::{debug, error};
use crate::pb::{ use crate::pb::{
encode_to_tcp_message, encode_to_udp_message, SdlEmpty, SdlStunProbe, SdlStunProbeReply, encode_to_tcp_message, encode_to_udp_message, SdlEmpty, SdlStunProbe, SdlStunProbeReply,
@ -17,7 +16,7 @@ use crate::pb::{
use crate::tcp::{get_tcp_conn, NatType, PacketType, StunProbeAttr}; use crate::tcp::{get_tcp_conn, NatType, PacketType, StunProbeAttr};
use crate::utils::{PidRecorder, Socket}; use crate::utils::{PidRecorder, Socket};
use sdlan_sn_rs::peer::{is_sdlan_sock_equal, IpSubnet, V6Info}; use sdlan_sn_rs::peer::{IpSubnet, V6Info};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
@ -25,16 +24,18 @@ use super::device::{DeviceConfig, Mode};
use super::tun::{new_iface, Iface}; use super::tun::{new_iface, Iface};
use tokio::fs::File; use tokio::fs::File;
use sdlan_sn_rs::utils::{gen_rsa_keys, load_private_key_file}; use sdlan_sn_rs::utils::{gen_rsa_keys, load_private_key_file, Mac};
use sdlan_sn_rs::utils::{Result, SDLanError}; use sdlan_sn_rs::utils::{Result, SDLanError};
static EDGE: OnceCell<Node> = OnceCell::new(); static EDGE: OnceCell<Node> = OnceCell::new();
pub async fn init_edge( pub async fn init_edge(
token: &str, token: &str,
network_code: &str,
node_conf: NodeConfig, node_conf: NodeConfig,
tos: u32, tos: u32,
start_stop: Sender<StartStopInfo>, start_stop: Sender<StartStopInfo>,
mtu: u32,
) -> Result<()> { ) -> Result<()> {
let _ = PidRecorder::new(".pid"); let _ = PidRecorder::new(".pid");
@ -52,9 +53,15 @@ pub async fn init_edge(
// let edge_uuid = create_or_load_uuid("")?; // let edge_uuid = create_or_load_uuid("")?;
//let node_conf = parse_config(edge_uuid, &args).await?; //let node_conf = parse_config(edge_uuid, &args).await?;
let sock_v4 = Socket::build(0, true, false, tos).await?; let Ok(sock_v4) = Socket::build(node_conf._local_port, true, false, tos).await else {
panic!("failed to build sock for sock v4");
};
let sock_multicast = Socket::build(MULTICAST_PORT, true, true, 0).await?; let mut sock_multicast = None;
if !node_conf._drop_multicast {
sock_multicast = Some(Socket::build(MULTICAST_PORT, true, true, 0).await?);
}
// let sock_multicast = Socket::build(MULTICAST_PORT, true, true, 0).await?;
// allow multicast // allow multicast
// TODO: set the sn's tcp socket // TODO: set the sn's tcp socket
@ -66,9 +73,11 @@ pub async fn init_edge(
sock_v4, sock_v4,
sock_multicast, sock_multicast,
token, token,
network_code,
privatekey, privatekey,
tcp_pong.clone(), tcp_pong.clone(),
start_stop, start_stop,
mtu,
); );
do_init_edge(edge)?; do_init_edge(edge)?;
@ -113,6 +122,7 @@ pub struct Node {
// user token info // user token info
pub _token: Mutex<String>, pub _token: Mutex<String>,
pub network_code: Mutex<String>,
pub device_config: DeviceConfig, pub device_config: DeviceConfig,
pub device: Iface, pub device: Iface,
@ -134,7 +144,7 @@ pub struct Node {
pub known_peers: PeerMap, pub known_peers: PeerMap,
// pub tcp_sock_v4: TCPSocket, // pub tcp_sock_v4: TCPSocket,
pub udp_sock_multicast: Socket, pub udp_sock_multicast: Option<Socket>,
pub udp_sock_v4: Socket, pub udp_sock_v4: Socket,
pub outer_ip_v4: AtomicU32, pub outer_ip_v4: AtomicU32,
pub udp_sock_v6: RwLock<Option<Arc<Socket>>>, pub udp_sock_v6: RwLock<Option<Arc<Socket>>>,
@ -203,6 +213,7 @@ impl Node {
pkt_id: Some(id), pkt_id: Some(id),
}) })
.await; .await;
debug!("start with feedback");
tokio::select! { tokio::select! {
rx_info = rx => { rx_info = rx => {
@ -234,17 +245,26 @@ impl Node {
pubkey: String, pubkey: String,
config: NodeConfig, config: NodeConfig,
sock: Socket, sock: Socket,
multicast_sock: Socket, multicast_sock: Option<Socket>,
// tcpsock: TCPSocket, // tcpsock: TCPSocket,
token: &str, token: &str,
network_code: &str,
private: RsaPrivateKey, private: RsaPrivateKey,
tcp_pong: Arc<AtomicU64>, tcp_pong: Arc<AtomicU64>,
start_stop: Sender<StartStopInfo>, start_stop: Sender<StartStopInfo>,
mtu: u32,
) -> Self { ) -> Self {
let mode = if cfg!(not(feature = "tun")) {
Mode::Tap
} else {
Mode::Tun
};
Self { Self {
packet_id: AtomicU32::new(1), packet_id: AtomicU32::new(1),
network_id: AtomicU32::new(0), network_id: AtomicU32::new(0),
_token: Mutex::new(token.to_owned()), _token: Mutex::new(token.to_owned()),
network_code: Mutex::new(network_code.to_owned()),
start_stop_sender: start_stop, start_stop_sender: start_stop,
@ -252,8 +272,8 @@ impl Node {
nat_type: Mutex::new(NatType::Blocked), nat_type: Mutex::new(NatType::Blocked),
device_config: DeviceConfig::new(), device_config: DeviceConfig::new(mtu),
device: new_iface("dev", Mode::Tun), device: new_iface("dev", mode),
authorized: AtomicBool::new(false), authorized: AtomicBool::new(false),
encrypt_key: RwLock::new(Arc::new(Vec::new())), encrypt_key: RwLock::new(Arc::new(Vec::new())),
@ -366,6 +386,7 @@ impl Node {
pub async fn send_nat_probe_reply(&self, cookie: u32, buf: SdlStunProbeReply) { pub async fn send_nat_probe_reply(&self, cookie: u32, buf: SdlStunProbeReply) {
if let Some((_key, chan)) = self.cookie_match.remove(&cookie) { if let Some((_key, chan)) = self.cookie_match.remove(&cookie) {
let _ = chan.send(buf); let _ = chan.send(buf);
return;
} }
error!("failed to get such cookie stun probe"); error!("failed to get such cookie stun probe");
} }
@ -385,32 +406,38 @@ impl Node {
return NatType::Blocked; return NatType::Blocked;
}; };
let Ok(reply2) = self if reply1.ip == self.outer_ip_v4.load(Ordering::Relaxed) {
let Ok(_reply2) = self
.send_and_wait_for_probe_reply(StunProbeAttr::Peer, &self.config.nat_server1)
.await
else {
*self.nat_type.lock().unwrap() = NatType::Symmetric;
return NatType::Symmetric;
};
*self.nat_type.lock().unwrap() = NatType::NoNat;
return NatType::NoNat;
}
if let Ok(_reply2_2) = self
.send_and_wait_for_probe_reply(StunProbeAttr::Peer, &self.config.nat_server1)
.await
{
*self.nat_type.lock().unwrap() = NatType::FullCone;
return NatType::FullCone;
}
let Ok(reply3) = self
.send_and_wait_for_probe_reply(StunProbeAttr::None, &self.config.nat_server2) .send_and_wait_for_probe_reply(StunProbeAttr::None, &self.config.nat_server2)
.await .await
else { else {
*self.nat_type.lock().unwrap() = NatType::Blocked; *self.nat_type.lock().unwrap() = NatType::Blocked;
return NatType::Blocked; return NatType::Blocked;
}; };
if reply3.ip != reply1.ip || reply3.port != reply1.port {
if reply1.ip == self.outer_ip_v4.load(Ordering::Relaxed) {
*self.nat_type.lock().unwrap() = NatType::NoNat;
return NatType::NoNat;
}
if reply1.ip != reply2.ip || reply1.port != reply2.port {
*self.nat_type.lock().unwrap() = NatType::Symmetric; *self.nat_type.lock().unwrap() = NatType::Symmetric;
return NatType::Symmetric; return NatType::Symmetric;
} }
if let Ok(_reply3) = self
.send_and_wait_for_probe_reply(StunProbeAttr::Peer, &self.config.nat_server1)
.await
{
*self.nat_type.lock().unwrap() = NatType::FullCone;
return NatType::FullCone;
}
if let Ok(_reply4) = self if let Ok(_reply4) = self
.send_and_wait_for_probe_reply(StunProbeAttr::Port, &self.config.nat_server1) .send_and_wait_for_probe_reply(StunProbeAttr::Port, &self.config.nat_server1)
.await .await
@ -443,6 +470,7 @@ impl Node {
attr: msgattr as u32, attr: msgattr as u32,
cookie, cookie,
}; };
// println!("==> sending probe request: {:?}", probe);
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
self.cookie_match.insert(cookie, tx); self.cookie_match.insert(cookie, tx);
@ -473,7 +501,7 @@ impl Node {
} }
pub struct PeerMap { pub struct PeerMap {
pub peers: DashMap<u32, Arc<EdgePeer>>, pub peers: DashMap<Mac, EdgePeer>,
} }
#[allow(unused)] #[allow(unused)]
@ -484,37 +512,38 @@ impl PeerMap {
} }
} }
pub fn get_peer(&self, ip: &u32) -> Option<Arc<EdgePeer>> { /*
if let Some(v) = self.peers.get(ip) { pub fn get_peer(&self, mac: &Mac) -> Option<Arc<EdgePeer>> {
if let Some(v) = self.peers.get(mac) {
Some(v.clone()) Some(v.clone())
} else { } else {
None None
} }
} }
*/
pub fn clear(&self) { pub fn clear(&self) {
self.peers.clear(); self.peers.clear();
} }
pub fn get_peer_by_sock(&self, sock: &SdlanSock) -> Option<Arc<EdgePeer>> { pub fn get_peer_by_sock(&self, sock: &SdlanSock) -> Option<Arc<EdgePeer>> {
/*
for s in self.peers.iter() { for s in self.peers.iter() {
let m = s.sock.read().unwrap(); let m = s.sock.read().unwrap();
if is_sdlan_sock_equal(&m, sock) { if is_sdlan_sock_equal(&m, sock) {
return Some(s.value().clone()); return Some(s.value().clone());
} }
} }
*/
None None
} }
pub fn delete_peer_with_ip(&self, ip: &u32) { pub fn delete_peer_with_mac(&self, mac: &Mac) -> Option<(Mac, EdgePeer)> {
self.peers.remove(ip); self.peers.remove(mac)
} }
pub fn insert_peer(&self, p: Arc<EdgePeer>) { pub fn insert_peer(&self, mac: Mac, p: EdgePeer) {
let net_addr = p.dev_addr.net_addr(); self.peers.insert(mac, p);
if net_addr != 0 {
self.peers.insert(net_addr, p);
}
} }
} }
@ -548,7 +577,7 @@ impl NodeStats {
use sdlan_sn_rs::peer::SdlanSock; use sdlan_sn_rs::peer::SdlanSock;
use crate::config::{self, MULTICAST_PORT, REGISTER_INTERVAL}; use crate::config::{self, MULTICAST_PORT, REGISTER_SUPER_INTERVAL};
pub struct NodeConfig { pub struct NodeConfig {
// node name // node name
pub name: String, pub name: String,
@ -588,12 +617,15 @@ pub struct NodeConfig {
#[derive(Debug)] #[derive(Debug)]
pub struct EdgePeer { pub struct EdgePeer {
// pub mac: Mac,
pub dev_addr: IpSubnet, pub dev_addr: IpSubnet,
pub nat_type: NatType,
// 对端对外开放的ip和端口信息 // 对端对外开放的ip和端口信息
pub sock: RwLock<SdlanSock>, pub sock: SdlanSock,
// peer's ipv6 info // peer's ipv6 info
pub _v6_info: RwLock<Option<SdlanSock>>, pub _v6_info: Option<SdlanSock>,
pub timeout: u8, pub timeout: u8,
@ -613,6 +645,7 @@ pub struct EdgePeer {
impl EdgePeer { impl EdgePeer {
pub fn new( pub fn new(
// mac: Mac,
net_addr: u32, net_addr: u32,
net_bit_len: u8, net_bit_len: u8,
sock: &SdlanSock, sock: &SdlanSock,
@ -629,14 +662,20 @@ impl EdgePeer {
}) })
} }
Self { Self {
// mac,
dev_addr: IpSubnet::new(net_addr, net_bit_len), dev_addr: IpSubnet::new(net_addr, net_bit_len),
sock: RwLock::new(sock.deepcopy()), sock: sock.deepcopy(),
_v6_info: RwLock::new(v6_info), _v6_info: v6_info,
timeout: REGISTER_INTERVAL, timeout: REGISTER_SUPER_INTERVAL as u8,
last_p2p: AtomicU64::new(0), last_p2p: AtomicU64::new(0),
last_seen: AtomicU64::new(0), last_seen: AtomicU64::new(0),
_last_valid_timestamp: AtomicU64::new(now), _last_valid_timestamp: AtomicU64::new(now),
last_sent_query: AtomicU64::new(0), last_sent_query: AtomicU64::new(0),
nat_type: NatType::Invalid,
} }
} }
pub fn get_nat_type(&self) -> NatType {
self.nat_type
}
} }

615
src/network/packet.rs Normal file → Executable file
View File

@ -1,11 +1,10 @@
use std::{ use std::{net::SocketAddr, sync::atomic::Ordering, time::Duration};
net::SocketAddr,
sync::{atomic::Ordering, RwLock}, use crate::tcp::NatType;
time::Duration, use crate::{network::TunTapPacketHandler, utils::mac_to_string};
};
use crate::{ use crate::{
config::REGISTER_INTERVAL, config::{NULL_MAC, REGISTER_INTERVAL},
pb::{ pb::{
encode_to_tcp_message, encode_to_udp_message, SdlData, SdlEmpty, SdlPeerInfo, SdlQueryInfo, encode_to_tcp_message, encode_to_udp_message, SdlData, SdlEmpty, SdlPeerInfo, SdlQueryInfo,
SdlRegister, SdlRegisterAck, SdlStunProbeReply, SdlRegister, SdlRegisterAck, SdlStunProbeReply,
@ -13,24 +12,24 @@ use crate::{
tcp::{get_tcp_conn, PacketType}, tcp::{get_tcp_conn, PacketType},
utils::{send_to_sock, Socket}, utils::{send_to_sock, Socket},
}; };
use etherparse::IpHeaders; use etherparse::Ethernet2Header;
use prost::Message; use prost::Message;
use sdlan_sn_rs::utils::{aes_encrypt, BROADCAST_MAC};
use sdlan_sn_rs::{ use sdlan_sn_rs::{
config::{AF_INET, AF_INET6}, config::{AF_INET, AF_INET6},
peer::{is_sdlan_sock_equal, SdlanSock, V6Info}, peer::{is_sdlan_sock_equal, SdlanSock, V6Info},
utils::{ utils::{
aes_decrypt, get_current_timestamp, get_sdlan_sock_from_socketaddr, ip_to_string, aes_decrypt, get_current_timestamp, get_sdlan_sock_from_socketaddr, is_multi_broadcast,
is_multi_broadcast, Result, SDLanError, Mac, Result, SDLanError,
}, },
}; };
use std::sync::Arc;
use tracing::{debug, error, info}; use tracing::{debug, error, info};
use super::{EdgePeer, Node}; use super::{EdgePeer, Node};
pub async fn read_and_parse_packet( pub async fn read_and_parse_packet(
eee: &Node, eee: &'static Node,
sock: &Socket, sock: &Socket,
timeout: Option<Duration>, timeout: Option<Duration>,
_is_multicast_sock: bool, _is_multicast_sock: bool,
@ -87,7 +86,7 @@ pub async fn read_and_parse_packet(
Ok(()) Ok(())
} }
pub async fn handle_packet(eee: &Node, addr: SocketAddr, buf: &[u8]) -> Result<()> { pub async fn handle_packet(eee: &'static Node, addr: SocketAddr, buf: &[u8]) -> Result<()> {
if buf.len() < 1 { if buf.len() < 1 {
return Err(SDLanError::NormalError("buf length error")); return Err(SDLanError::NormalError("buf length error"));
} }
@ -96,6 +95,7 @@ pub async fn handle_packet(eee: &Node, addr: SocketAddr, buf: &[u8]) -> Result<(
}; };
match pkt_type { match pkt_type {
PacketType::Data => { PacketType::Data => {
debug!("got data");
let from_sock = get_sdlan_sock_from_socketaddr(addr).unwrap(); let from_sock = get_sdlan_sock_from_socketaddr(addr).unwrap();
debug!("[PPP]Rx data from {}", from_sock.to_string()); debug!("[PPP]Rx data from {}", from_sock.to_string());
if !eee.is_authorized() { if !eee.is_authorized() {
@ -107,33 +107,51 @@ pub async fn handle_packet(eee: &Node, addr: SocketAddr, buf: &[u8]) -> Result<(
error!("failed to decode to SDLData"); error!("failed to decode to SDLData");
return Err(SDLanError::NormalError("failed to decode to SDLData")); return Err(SDLanError::NormalError("failed to decode to SDLData"));
}; };
let Ok(src_mac) = data.src_mac.clone().try_into() else {
error!("failed to convert src mac");
return Err(SDLanError::NormalError("failed to convert vec to Mac"));
};
// let from_sock = get_sdlan_sock_from_socketaddr(addr).unwrap(); // let from_sock = get_sdlan_sock_from_socketaddr(addr).unwrap();
if data.is_p2p { if data.is_p2p {
debug!("[P2P] Rx data from {}", from_sock.to_string()); debug!("[P2P] Rx data from {}", from_sock.to_string());
} else { } else {
debug!( debug!(
"[PsP] Rx data from {} via {}", "[PsP] Rx data from {} via {}",
ip_to_string(&data.src_ip), mac_to_string(&src_mac),
from_sock.to_string() from_sock.to_string()
); );
} }
if data.is_p2p { if data.is_p2p {
check_peer_registration_needed(eee, !data.is_p2p, data.src_ip, &None, &from_sock) let from_sock = from_sock.deepcopy();
tokio::spawn(async move {
check_peer_registration_needed(
eee,
!data.is_p2p,
src_mac,
NatType::NoNat,
&None,
&from_sock,
)
.await; .await;
});
} }
handle_tun_packet(eee, !data.is_p2p, data).await; handle_tun_packet(eee, &from_sock, !data.is_p2p, data).await;
} }
PacketType::StunProbeReply => { PacketType::StunProbeReply => {
debug!("got StunProbeReply");
let Ok(reply) = SdlStunProbeReply::decode(&buf[1..]) else { let Ok(reply) = SdlStunProbeReply::decode(&buf[1..]) else {
error!("failed to decode SdlStunReply"); error!("failed to decode SdlStunReply");
return Ok(()); return Ok(());
}; };
// println!("got stun probe reply: {:?}", reply);
eee.send_nat_probe_reply(reply.cookie, reply).await; eee.send_nat_probe_reply(reply.cookie, reply).await;
} }
PacketType::StunReply => { PacketType::StunReply => {
debug!("got stun reply");
// stun reply, like pong // stun reply, like pong
} }
PacketType::Register => { PacketType::Register => {
debug!("got Register");
if !eee.is_authorized() { if !eee.is_authorized() {
error!("dropping REGISTER received before authorized"); error!("dropping REGISTER received before authorized");
return Ok(()); return Ok(());
@ -142,6 +160,7 @@ pub async fn handle_packet(eee: &Node, addr: SocketAddr, buf: &[u8]) -> Result<(
let _ = handle_packet_register(eee, &buf[1..], false, &from_sock).await; let _ = handle_packet_register(eee, &buf[1..], false, &from_sock).await;
} }
PacketType::RegisterACK => { PacketType::RegisterACK => {
debug!("got RegisterACK");
if !eee.is_authorized() { if !eee.is_authorized() {
error!("dropping REGISTER received before authorized"); error!("dropping REGISTER received before authorized");
return Ok(()); return Ok(());
@ -221,7 +240,7 @@ pub async fn handle_packet(eee: &Node, addr: SocketAddr, buf: &[u8]) -> Result<(
} }
pub async fn handle_packet_peer_info( pub async fn handle_packet_peer_info(
eee: &Node, eee: &'static Node,
// cmn: Common<'_>, // cmn: Common<'_>,
body: &[u8], body: &[u8],
//sender_sock: &SdlanSock, //sender_sock: &SdlanSock,
@ -232,6 +251,10 @@ pub async fn handle_packet_peer_info(
}; };
debug!("got peer info: {:?}", pi); debug!("got peer info: {:?}", pi);
let Ok(dst_mac) = pi.dst_mac.try_into() else {
error!("mac is null");
return Ok(());
};
if pi.v4_info.is_none() { if pi.v4_info.is_none() {
error!("PEER's v4_info is none"); error!("PEER's v4_info is none");
@ -243,6 +266,11 @@ pub async fn handle_packet_peer_info(
error!("failed to convert v4"); error!("failed to convert v4");
return Ok(()); return Ok(());
}; };
let remote_nat_byte = v4.nat_type as u8;
let remote_nat = match NatType::try_from(remote_nat_byte) {
Ok(nat) => nat,
Err(_) => NatType::Invalid,
};
let mut v6: [u8; 16] = [0; 16]; let mut v6: [u8; 16] = [0; 16];
let mut v6_port = 0; let mut v6_port = 0;
@ -254,33 +282,35 @@ pub async fn handle_packet_peer_info(
} }
// let src_ip = u32::from_be_bytes(v4_u32); // let src_ip = u32::from_be_bytes(v4_u32);
if pi.dst_ip == 0 { if dst_mac == NULL_MAC {
// pong from sn // pong from sn
} else { } else {
match eee.pending_peers.get_peer(&pi.dst_ip) { let pending = eee.pending_peers.peers.get_mut(&dst_mac);
Some(edgeinfo) => { match pending {
let mut sock = SdlanSock { Some(mut v) => {
let sock = SdlanSock {
family: AF_INET, family: AF_INET,
port: v4.port as u16, port: v4.port as u16,
v4: v4_u32, v4: v4_u32,
v6: [0; 16], v6: [0; 16],
}; };
*(edgeinfo.sock.write().unwrap()) = sock.deepcopy(); v.nat_type = remote_nat;
v.sock = sock.deepcopy();
// v.sock = sock.deepcopy();
info!( info!(
"Rx PEERINFO for {}: is at {}", "Rx PEERINFO for {}: is at {}",
ip_to_string(&pi.dst_ip), mac_to_string(&dst_mac),
sock.to_string() sock.to_string()
); );
let mut v6_info = None; let mut v6_info = None;
if v6_port != 0 { if v6_port != 0 {
v6_info = Some(V6Info { port: v6_port, v6 }) v6_info = Some(V6Info { port: v6_port, v6 })
} }
send_register(eee, &sock, &v6_info).await; send_register(eee, remote_nat, &sock, dst_mac, &v6_info).await;
// register_with_local_peers(eee).await;
} }
None => { None => {
debug!("Rx PEERINFO unknown peer: {}", ip_to_string(&pi.dst_ip)); debug!("Rx PEERINFO unknown peer: {}", mac_to_string(&dst_mac));
} }
} }
} }
@ -372,21 +402,35 @@ async fn handle_packet_register_ack(
}; };
let origin_sender = sender_sock; let origin_sender = sender_sock;
let Ok(src_mac) = ack.src_mac.try_into() else {
error!("failed to get src_mac");
return Ok(());
};
let Ok(dst_mac) = ack.dst_mac.try_into() else {
error!("failed to get dst_mac");
return Ok(());
};
let via_multicast = is_multi_broadcast(&dst_mac);
if via_multicast && src_mac == eee.device_config.get_mac() {
debug!("skipping register ack from self");
return Ok(());
}
debug!( debug!(
"Rx REGISTER ACK from {} [{}] to {} via {}", "Rx REGISTER ACK from {} [{}] to {} via {}",
ip_to_string(&ack.src_ip), mac_to_string(&src_mac),
origin_sender.to_string(), origin_sender.to_string(),
ip_to_string(&ack.dst_ip), mac_to_string(&dst_mac),
sender_sock.to_string(), sender_sock.to_string(),
); );
peer_set_p2p_confirmed(eee, ack.src_ip, sender_sock); peer_set_p2p_confirmed(eee, src_mac, sender_sock);
Ok(()) Ok(())
} }
async fn handle_packet_register( async fn handle_packet_register(
eee: &Node, eee: &'static Node,
// cmn: Common<'_>, // cmn: Common<'_>,
body: &[u8], body: &[u8],
from_sn: bool, from_sn: bool,
@ -404,27 +448,43 @@ async fn handle_packet_register(
let origin_sender = sender_sock; let origin_sender = sender_sock;
let via_multicast = is_multi_broadcast(reg.dst_ip); let Ok(src_mac) = reg.src_mac.clone().try_into() else {
if via_multicast && reg.src_ip == eee.device_config.get_ip() { error!("[REGISTER] failed to get src_mac");
return Ok(());
};
let Ok(dst_mac) = reg.dst_mac.clone().try_into() else {
error!("[REGISTER] failed to get dst_mac");
return Ok(());
};
let via_multicast = is_multi_broadcast(&dst_mac);
if via_multicast && src_mac == eee.device_config.get_mac() {
debug!("skipping register from self"); debug!("skipping register from self");
return Ok(()); return Ok(());
} }
let mut remote_nat = NatType::NoNat;
if !from_sn { if !from_sn {
info!("[P2P] Rx REGISTER from {}", sender_sock.to_string()); info!(
eee.pending_peers.delete_peer_with_ip(&reg.src_ip); "[P2P] Rx REGISTER from {}, deleting from pending",
sender_sock.to_string()
);
if let Some((_, v)) = eee.pending_peers.delete_peer_with_mac(&src_mac) {
remote_nat = v.get_nat_type();
}
send_register_ack(eee, origin_sender, &reg).await; send_register_ack(eee, origin_sender, &reg).await;
info!("sent back REGISTERACK");
} else { } else {
info!( info!(
"[PsP] Rx REGISTER from {} [{}] to {} via {}", "[PsP] Rx REGISTER from {} [{}] to {} via {}",
ip_to_string(&reg.src_ip), mac_to_string(&src_mac),
ip_to_string(&reg.dst_ip), mac_to_string(&dst_mac),
sender_sock.to_string(), sender_sock.to_string(),
origin_sender.to_string(), origin_sender.to_string(),
); );
} }
// check_peer_registration_needed(eee, from_sn, reg.src_ip, &None, origin_sender).await; // check_peer_registration_needed(eee, from_sn, reg.src_ip, &None, origin_sender).await;
check_peer_registration_needed(eee, from_sn, reg.src_ip, &None, origin_sender).await; check_peer_registration_needed(eee, from_sn, src_mac, remote_nat, &None, origin_sender).await;
Ok(()) Ok(())
} }
@ -479,30 +539,35 @@ async fn handle_packet_packet(
*/ */
pub async fn check_peer_registration_needed( pub async fn check_peer_registration_needed(
eee: &Node, eee: &'static Node,
from_sn: bool, from_sn: bool,
src_ip: u32, src_mac: Mac,
remote_nat: NatType,
_v6_info: &Option<V6Info>, _v6_info: &Option<V6Info>,
peer_sock: &SdlanSock, peer_sock: &SdlanSock,
) { ) {
let mut p = eee.known_peers.get_peer(&src_ip); let p = eee.known_peers.peers.get(&src_mac);
if let None = p { let last_seen;
p = eee.known_peers.get_peer_by_sock(peer_sock); let now;
if let Some(ref k) = p {
eee.known_peers.insert_peer(k.clone());
}
}
match p { match p {
None => { None => {
let _ = register_with_new_peer(eee, from_sn, src_ip, _v6_info, peer_sock).await; debug!("check peer registration needed, not found in known peers");
let _ = register_with_new_peer(eee, from_sn, src_mac, _v6_info, remote_nat, peer_sock)
.await;
return;
// unimplemented!(); // unimplemented!();
} }
Some(k) => { Some(k) => {
let mut ipv4_to_ipv6 = false; // let mut ipv4_to_ipv6 = false;
let now = get_current_timestamp(); now = get_current_timestamp();
if !from_sn { if !from_sn {
k.last_p2p.store(now, Ordering::Relaxed); k.last_p2p.store(now, Ordering::Relaxed);
} }
let origin_family = k.sock.family;
if origin_family != peer_sock.family {
return;
}
/*
if peer_sock.family == AF_INET6 && k.sock.read().unwrap().family == AF_INET { if peer_sock.family == AF_INET6 && k.sock.read().unwrap().family == AF_INET {
println!("changing to ipv6"); println!("changing to ipv6");
*k.sock.write().unwrap() = peer_sock.deepcopy(); *k.sock.write().unwrap() = peer_sock.deepcopy();
@ -510,135 +575,157 @@ pub async fn check_peer_registration_needed(
} else { } else {
println!("already is ipv6"); println!("already is ipv6");
} }
let last_seen = k.last_seen.load(Ordering::Relaxed); */
last_seen = k.last_seen.load(Ordering::Relaxed);
// more than 3 seconds // more than 3 seconds
if now - last_seen > 1 {
check_known_peer_sock_change(eee, from_sn, src_ip, peer_sock, now, ipv4_to_ipv6)
.await;
} }
} }
if now - last_seen > 3 {
check_known_peer_sock_change(eee, from_sn, src_mac, peer_sock, now, false).await;
} }
} }
async fn check_known_peer_sock_change( async fn check_known_peer_sock_change(
eee: &Node, eee: &'static Node,
from_sn: bool, from_sn: bool,
ip: u32, mac: Mac,
// v6_info: &Option<V6Info>, // v6_info: &Option<V6Info>,
// dev_addr: &IpSubnet, // dev_addr: &IpSubnet,
peersock: &SdlanSock, peersock: &SdlanSock,
when: u64, when: u64,
ipv4_to_ipv6: bool, ipv4_to_ipv6: bool,
) { ) {
if is_multi_broadcast(ip) { if is_multi_broadcast(&mac) {
return; return;
} }
match eee.known_peers.get_peer(&ip) { let delete_from_known_peers;
let remote_nat;
match eee.known_peers.peers.get_mut(&mac) {
Some(p) => { Some(p) => {
if !ipv4_to_ipv6 && !is_sdlan_sock_equal(&p.sock.read().unwrap(), peersock) { if !ipv4_to_ipv6 && !is_sdlan_sock_equal(&p.sock, peersock) {
if !from_sn { if !from_sn {
info!( info!(
"peer changed: {}: {} -> {}", "peer changed: {}: {} -> {}",
ip_to_string(&ip), mac_to_string(&mac),
&p.sock.read().unwrap().to_string(), &p.sock.to_string(),
peersock.to_string() peersock.to_string()
); );
eee.known_peers.delete_peer_with_ip(&ip); delete_from_known_peers = true;
register_with_new_peer(eee, from_sn, ip, &None, peersock).await; remote_nat = p.get_nat_type();
} else { } else {
// from sn, sn could see a different sock with us, just ignore it // from sn, sn could see a different sock with us, just ignore it
return;
} }
} else { } else {
p.last_seen.store(when, Ordering::Relaxed); p.last_seen.store(when, Ordering::Relaxed);
return;
// from sn, sn could see a different sock with us, just ignore it // from sn, sn could see a different sock with us, just ignore it
} }
} }
None => return, None => return,
} }
if delete_from_known_peers {
eee.known_peers.delete_peer_with_mac(&mac);
error!("known peers is deleted");
register_with_new_peer(eee, from_sn, mac, &None, remote_nat, peersock).await;
}
} }
async fn register_with_new_peer( async fn register_with_new_peer(
eee: &Node, eee: &'static Node,
from_sn: bool, from_sn: bool,
ip: u32, mac: Mac,
v6_info: &Option<V6Info>, v6_info: &Option<V6Info>,
// dev_addr: &IpSubnet, // dev_addr: &IpSubnet,
remote_nat: NatType,
peersock: &SdlanSock, peersock: &SdlanSock,
) { ) {
let now = get_current_timestamp(); let now = get_current_timestamp();
let mut scan = eee.pending_peers.get_peer(&ip); let entry = eee.pending_peers.peers.entry(mac);
if let None = scan { let mut new_created = false;
// such ip not found in pending
let temp = Arc::new(EdgePeer::new( let mut scan = entry.or_insert_with(|| {
ip, new_created = true;
eee.device_config.get_net_bit(), let temp = EdgePeer::new(0, eee.device_config.get_net_bit(), peersock, &None, now);
peersock, temp
&None, });
now,
)); if new_created {
debug!( debug!(
"===> new pending {} => {}", "===> new pending {} => {}",
ip_to_string(&ip), mac_to_string(&mac),
peersock.to_string(), peersock.to_string(),
); );
eee.pending_peers.insert_peer(temp.clone());
scan = Some(temp);
debug!("Pending size: {}", eee.pending_peers.peers.len());
if from_sn { if from_sn {
// should send register to peer // should send register to peer
if eee.config.register_ttl == 1 { if eee.config.register_ttl == 1 {
/* We are DMZ host or port is directly accessible. Just let peer to send back the ack */ /* We are DMZ host or port is directly accessible. Just let peer to send back the ack */
} else if eee.config.register_ttl > 1 { } else if eee.config.register_ttl > 1 {
/*
let mut alter = 16; let mut alter = 16;
if let Ok(ttl) = eee.udp_sock_v4.ttl() { if let Ok(ttl) = eee.udp_sock_v4.ttl() {
let mut temp = peersock.deepcopy(); let mut temp = peersock.deepcopy();
send_register(eee, &temp, v6_info).await; send_register(eee, remote_nat, &temp, mac, v6_info).await;
let _ = eee.udp_sock_v4.set_ttl(eee.config.register_ttl as u32); let _ = eee.udp_sock_v4.set_ttl(eee.config.register_ttl as u32);
while alter > 0 { while alter > 0 {
temp.port += 1; temp.port += 1;
send_register(eee, &temp, v6_info).await; send_register(eee, &temp, mac, v6_info).await;
alter -= 1; alter -= 1;
} }
let _ = eee.udp_sock_v4.set_ttl(ttl); let _ = eee.udp_sock_v4.set_ttl(ttl);
} }
*/
} else { } else {
// Normal STUN // Normal STUN
send_register(eee, peersock, v6_info).await; send_register(eee, remote_nat, peersock, mac, v6_info).await;
} }
// 发送给sn // 发送给sn
send_register( send_register(
eee, eee,
remote_nat,
&eee.config.super_nodes &eee.config.super_nodes
[eee.config.super_node_index.load(Ordering::Relaxed) as usize], [eee.config.super_node_index.load(Ordering::Relaxed) as usize],
mac,
v6_info, v6_info,
) )
.await; .await;
} else { } else {
// P2P register, send directly // P2P register, send directly
send_register(eee, peersock, v6_info).await; send_register(eee, remote_nat, peersock, mac, v6_info).await;
} }
register_with_local_peers(eee).await; register_with_local_peers(eee).await;
} else { } else {
if let Some(ref s) = scan { scan.sock = peersock.deepcopy();
*(s.sock.write().unwrap()) = peersock.deepcopy();
} }
}
if let Some(s) = scan { scan.last_seen
s.last_seen
.store(get_current_timestamp(), Ordering::Relaxed); .store(get_current_timestamp(), Ordering::Relaxed);
} }
}
async fn register_with_local_peers(eee: &Node) { async fn register_with_local_peers(eee: &'static Node) {
if eee.config.allow_p2p { if !eee.config._drop_multicast {
debug!("send register to multicast sock"); send_register(
send_register(eee, &eee.multicast_sock, &None).await; eee,
NatType::NoNat,
&eee.multicast_sock,
BROADCAST_MAC,
&None,
)
.await;
} }
} }
async fn send_register(eee: &Node, sock: &SdlanSock, _v6_info: &Option<V6Info>) { async fn send_register(
eee: &'static Node,
remote_nat: NatType,
sock: &SdlanSock,
mac: Mac,
_v6_info: &Option<V6Info>,
) {
if !eee.config.allow_p2p { if !eee.config.allow_p2p {
debug!("skipping register as p2p is disabled"); debug!("skipping register as p2p is disabled");
return; return;
@ -649,10 +736,14 @@ async fn send_register(eee: &Node, sock: &SdlanSock, _v6_info: &Option<V6Info>)
return; return;
} }
let self_nat = eee.get_nat_type();
let register = SdlRegister { let register = SdlRegister {
network_id: network_id, network_id: network_id,
src_ip: eee.device_config.get_ip(), src_mac: Vec::from(eee.device_config.get_mac()),
dst_ip: u32::from_be_bytes(sock.v4), // src_ip: eee.device_config.get_ip(),
dst_mac: Vec::from(mac),
// dst_ip: u32::from_be_bytes(sock.v4),
}; };
let msg = encode_to_udp_message(Some(register), PacketType::Register as u8).unwrap(); let msg = encode_to_udp_message(Some(register), PacketType::Register as u8).unwrap();
@ -671,6 +762,41 @@ async fn send_register(eee: &Node, sock: &SdlanSock, _v6_info: &Option<V6Info>)
) )
.await; .await;
} }
let mut need_guess_port = false;
match self_nat {
NatType::PortRestricted => {
if let NatType::Symmetric = remote_nat {
need_guess_port = true;
}
}
NatType::Symmetric => {
if let NatType::PortRestricted = remote_nat {
need_guess_port = true;
}
}
_other => {}
}
if need_guess_port {
// println!("need guess port");
}
/*
let mut target_sock_v4 = sock.deepcopy();
tokio::spawn(async move {
for i in 1..=10 {
target_sock_v4.port += i;
let _ = send_to_sock(eee, &msg, &target_sock_v4).await;
tokio::time::sleep(Duration::from_millis(500)).await;
}
for i in 1..=10 {
target_sock_v4.port -= i;
let _ = send_to_sock(eee, &msg, &target_sock_v4).await;
tokio::time::sleep(Duration::from_millis(500)).await;
}
});
*/
/* /*
let key = eee.get_header_key(); let key = eee.get_header_key();
if key.len() > 0 { if key.len() > 0 {
@ -683,13 +809,20 @@ async fn send_register(eee: &Node, sock: &SdlanSock, _v6_info: &Option<V6Info>)
*/ */
} }
pub fn printHex(key: &[u8]) {
let mut value = vec![];
for item in key {
value.push(format!("0x{:02x}", item))
}
println!("[{}]", value.join(" "))
}
async fn handle_tun_packet( async fn handle_tun_packet(
eee: &Node, eee: &Node,
from_sn: bool, _from_sock: &SdlanSock,
_from_sn: bool,
pkt: SdlData, //orig_sender: &SdlanSock pkt: SdlData, //orig_sender: &SdlanSock
) { ) {
let now = get_current_timestamp();
let payload = pkt.data; let payload = pkt.data;
let key = eee.get_encrypt_key(); let key = eee.get_encrypt_key();
if key.len() == 0 { if key.len() == 0 {
@ -698,16 +831,30 @@ async fn handle_tun_packet(
return; return;
} }
// test_aes(key.as_slice());
let origin = aes_decrypt(key.as_slice(), &payload); let origin = aes_decrypt(key.as_slice(), &payload);
if let Err(_e) = origin { if let Err(_e) = origin {
error!("failed to decrypt original data"); error!("failed to decrypt original data");
return; return;
} }
let data = origin.unwrap(); let data = origin.unwrap();
if let Err(e) = eee
.device
.handle_packet_from_net(&data, key.as_slice())
.await
{
error!("failed to handle packet from net: {}", e.to_string());
}
/*
let msg_size = data.len() as u64; let msg_size = data.len() as u64;
let Ok(dst_mac) = pkt.dst_mac.try_into() else {
error!("[PACKET] failed to decode dst_mac");
return;
};
if from_sn { if from_sn {
if is_multi_broadcast(pkt.dst_ip) { if is_multi_broadcast(&dst_mac) {
eee.stats eee.stats
.rx_broadcast .rx_broadcast
.fetch_add(msg_size, Ordering::Relaxed); .fetch_add(msg_size, Ordering::Relaxed);
@ -719,27 +866,153 @@ async fn handle_tun_packet(
eee.stats.last_p2p.store(now, Ordering::Relaxed); eee.stats.last_p2p.store(now, Ordering::Relaxed);
} }
// TODO: parse the mac
debug!("got packet from sock, will send to tun"); debug!("got packet from sock, will send to tun");
match IpHeaders::from_slice(&data) { match Ethernet2Header::from_slice(&data) {
Ok((iphdr, _)) => { Ok((hdr, rest)) => {
if let Some(ipv4hdr) = iphdr.ipv4() { if rest.len() < 4 {
let dstip = u32::from_be_bytes(ipv4hdr.0.destination); error!("payload length error");
if !is_multi_broadcast(dstip) && dstip != eee.device_config.get_ip() {
// should not routed to me
error!("should not routed to me");
return; return;
} }
// packet should be sent to dev let crc_code = &rest[(rest.len() - 4)..rest.len()];
debug!("writing {} bytes to tun: {:?}", data.len(), data); let rest = &rest[..(rest.len() - 4)];
if let Err(e) = eee.device.send(&data) {
error!("failed to write to tun: {}", e.to_string()); let crc_hash: crc::Crc<u32> = crc::Crc::<u32>::new(&crc::CRC_32_CKSUM);
let ck = CRC_HASH.checksum(&data[..(data.len()) - 4]);
let sent_ck = u32::from_be_bytes(crc_code.try_into().unwrap());
debug!("ck = {}, sent_ck = {}", ck, sent_ck);
debug!("ip size is {}", rest.len());
let edge = get_edge();
let self_mac = edge.device_config.get_mac();
/*
if hdr.destination != self_mac && hdr.destination != BROADCAST_MAC {
error!(
"packet to [{:?}] not direct to us",
mac_to_string(&hdr.destination)
);
return;
} }
*/
if hdr.ether_type == ARP {
let mut arp = ArpHdr::from_slice(&data);
let self_ip = edge.device_config.get_ip();
println!("self_ip: {:?}", self_ip.to_be_bytes());
let from_ip = ((arp.sipaddr[0] as u32) << 16) + arp.sipaddr[1] as u32;
println!("from_ip: {:?}", from_ip.to_be_bytes());
let dest_ip = ((arp.dipaddr[0] as u32) << 16) + arp.dipaddr[1] as u32;
println!("dest_ip: {:?}", dest_ip.to_be_bytes());
match arp.opcode {
ARP_REQUEST => {
// handle ARP REQUEST
debug!("got ARP REQUEST");
if arp.ethhdr.dest != [0xff; 6] {
println!("ARP REQUEST not broadcast");
return;
}
if dest_ip == self_ip {
send_arp_request(ArpRequestInfo::Set {
ip: from_ip,
mac: arp.shwaddr,
})
.await;
// target to us
arp.opcode = ARP_REPLY;
arp.dhwaddr = arp.shwaddr;
arp.shwaddr = self_mac;
arp.ethhdr.src = self_mac;
arp.ethhdr.dest = arp.dhwaddr;
arp.dipaddr = arp.sipaddr;
arp.sipaddr =
[((self_ip >> 16) & 0xffff) as u16, (self_ip & 0xffff) as u16];
let data = arp.marshal_to_bytes();
let Ok(encrypted) = aes_encrypt(key.as_slice(), &data) else {
error!("failed to encrypt arp reply");
return;
};
let data = SdlData {
is_p2p: true,
ttl: 2,
network_id: edge.network_id.load(Ordering::Relaxed),
src_mac: Vec::from(self_mac),
dst_mac: Vec::from(arp.dhwaddr),
data: encrypted,
};
let v =
encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap();
println!(
"xxxx send arp reply to [{}], selfmac=[{}]",
mac_to_string(&arp.dhwaddr),
mac_to_string(&self_mac)
);
send_packet_to_net(edge, arp.dhwaddr, &v, 0).await;
// send_to_sock(edge, &v, from_sock);
// edge.sock.send(v).await;
}
}
ARP_REPLY => {
println!("got arp reply",);
println!("mac {:?} is at {:?}", arp.shwaddr, from_ip.to_be_bytes());
if dest_ip == self_ip {
send_arp_request(ArpRequestInfo::Set {
ip: from_ip,
mac: arp.shwaddr,
})
.await;
}
}
other => {
println!("unknown arp type info");
}
}
} else {
match IpHeaders::from_slice(rest) {
Ok((iphdr, _)) => {
let Some(ipv4) = iphdr.ipv4() else {
error!("not ipv4, dropping");
return;
};
let ip = u32::from_be_bytes(ipv4.0.source);
let mac = hdr.source;
if !is_multi_broadcast(&mac) {
send_arp_request(ArpRequestInfo::Set { ip, mac }).await;
} }
} }
Err(e) => { Err(e) => {
error!("failed to parse ip packet: {}", e.to_string()); error!("failed to parse ip header, dropping");
return;
} }
} }
println!("got ip packet");
println!("got data: {:?}", rest);
match edge.device.send(rest) {
Ok(size) => {
debug!("send to tun {} bytes", size);
}
Err(e) => {
error!("failed to send to device: {}", e.to_string());
}
}
// edge.tun.send_data_to_tun(Vec::from(hdr.1)).await;
}
}
Err(e) => {
error!("failed to parse tap packet: {}", e);
return;
}
}
*/
} }
async fn send_register_ack(eee: &Node, orig_sender: &SdlanSock, reg: &SdlRegister) { async fn send_register_ack(eee: &Node, orig_sender: &SdlanSock, reg: &SdlRegister) {
@ -752,10 +1025,11 @@ async fn send_register_ack(eee: &Node, orig_sender: &SdlanSock, reg: &SdlRegiste
error!("not authed"); error!("not authed");
return; return;
} }
let src_mac = reg.src_mac.clone();
let ack = SdlRegisterAck { let ack = SdlRegisterAck {
network_id, network_id,
src_ip: eee.device_config.get_ip(), src_mac: Vec::from(eee.device_config.get_mac()),
dst_ip: reg.src_ip, dst_mac: src_mac,
}; };
let Ok(ack) = encode_to_udp_message(Some(ack), PacketType::RegisterACK as u8) else { let Ok(ack) = encode_to_udp_message(Some(ack), PacketType::RegisterACK as u8) else {
error!("failed to encode to udp message"); error!("failed to encode to udp message");
@ -764,11 +1038,10 @@ async fn send_register_ack(eee: &Node, orig_sender: &SdlanSock, reg: &SdlRegiste
let _ = send_to_sock(eee, &ack, orig_sender).await; let _ = send_to_sock(eee, &ack, orig_sender).await;
} }
fn peer_set_p2p_confirmed(eee: &Node, src_ip: u32, sender_sock: &SdlanSock) { fn peer_set_p2p_confirmed(eee: &Node, src_mac: Mac, sender_sock: &SdlanSock) {
let mut scan = eee.pending_peers.get_peer(&src_ip); // let mut scan = eee.pending_peers.get_peer(&src_mac);
if let None = scan { let scan = eee.pending_peers.peers.remove(&src_mac);
scan = eee.pending_peers.get_peer_by_sock(sender_sock);
}
if let None = scan { if let None = scan {
error!( error!(
"failed to find sender in pending peer: {}", "failed to find sender in pending peer: {}",
@ -776,72 +1049,65 @@ fn peer_set_p2p_confirmed(eee: &Node, src_ip: u32, sender_sock: &SdlanSock) {
); );
return; return;
} }
let (_, scan) = scan.unwrap();
{
let entry = eee.known_peers.peers.entry(src_mac);
let mut scan2 = entry.or_insert(scan);
scan2.sock = sender_sock.deepcopy();
let mut scan = scan.unwrap();
eee.pending_peers.delete_peer_with_ip(&src_ip);
match eee.known_peers.get_peer(&src_ip) {
Some(scantmp) => {
eee.known_peers.delete_peer_with_ip(&src_ip);
scan = scantmp;
// set the remote peer sock
*scan.sock.write().unwrap() = sender_sock.deepcopy();
scan.dev_addr.net_addr.store(src_ip, Ordering::Relaxed);
scan.dev_addr
.net_bit_len
.store(eee.device_config.get_net_bit(), Ordering::Relaxed);
}
None => {
*(scan.sock.write().unwrap()) = sender_sock.deepcopy();
}
}
let now = get_current_timestamp(); let now = get_current_timestamp();
scan.last_p2p.store(now, Ordering::Relaxed); scan2.last_p2p.store(now, Ordering::Relaxed);
scan.last_seen.store(now, Ordering::Relaxed); scan2.last_seen.store(now, Ordering::Relaxed);
}
let ip_string = ip_to_string(&src_ip); let mac_string = mac_to_string(&src_mac);
let sock_string = sender_sock.to_string(); let sock_string = sender_sock.to_string();
info!( info!(
"P2P connection established: {} [{}]", "P2P connection established: {} [{}]",
&ip_string, &sock_string, &mac_string, &sock_string,
); );
debug!("==> new peer: {} -> {}", &ip_string, &sock_string,); // eee.known_peers.insert_peer(src_mac, scan);
eee.known_peers.insert_peer(scan); debug!("==> new peer: {} -> {}", &mac_string, &sock_string,);
} }
pub async fn check_query_peer_info(eee: &Node, dst_ip: u32) { pub async fn check_query_peer_info(eee: &'static Node, mac: Mac) {
let scan: Arc<EdgePeer>; // let scan: Arc<EdgePeer>;
let now = get_current_timestamp(); let now = get_current_timestamp();
match eee.pending_peers.get_peer(&dst_ip) {
None => { let last_sent_query;
let mut need_send_query = false;
{
let entry = eee.pending_peers.peers.entry(mac);
let sock = SdlanSock { let sock = SdlanSock {
family: AF_INET, family: AF_INET,
port: 0, port: 0,
v4: [0; 4], v4: [0; 4],
v6: [0; 16], v6: [0; 16],
}; };
let peer = Arc::new(EdgePeer::new( let peer = EdgePeer::new(
dst_ip, // mac,
0,
eee.device_config.get_net_bit(), eee.device_config.get_net_bit(),
&sock, &sock,
&None, &None,
now, now,
));
debug!("insert peer {} to pending", ip_to_string(&dst_ip));
eee.pending_peers.insert_peer(peer.clone());
scan = peer;
}
Some(s) => {
scan = s;
}
}
debug!(
"now={}, last_sent_query={}, REGISTER_INTERVAL={}, scan={:?}",
now,
scan.last_sent_query.load(Ordering::Relaxed),
REGISTER_INTERVAL,
scan,
); );
if now - scan.last_sent_query.load(Ordering::Relaxed) > (REGISTER_INTERVAL as u64) { debug!("insert peer {} to pending", mac_to_string(&mac));
let val = entry.or_insert(peer);
last_sent_query = val.last_sent_query.load(Ordering::Relaxed);
if now - last_sent_query > (REGISTER_INTERVAL as u64) {
need_send_query = true;
val.last_sent_query.store(now, Ordering::Relaxed);
}
}
debug!(
"now={}, last_sent_query={}, REGISTER_INTERVAL={}",
now, last_sent_query, REGISTER_INTERVAL,
);
if need_send_query {
/* /*
send_register( send_register(
eee, eee,
@ -850,22 +1116,22 @@ pub async fn check_query_peer_info(eee: &Node, dst_ip: u32) {
) )
.await; .await;
*/ */
debug!("sending query for {}", ip_to_string(&dst_ip)); debug!("sending query for {}", mac_to_string(&mac));
register_with_local_peers(eee).await; register_with_local_peers(eee).await;
if let Ok(()) = send_query_peer(eee, dst_ip).await { let _ = send_query_peer(eee, mac).await;
scan.last_sent_query.store(now, Ordering::Relaxed);
}
} }
} }
async fn send_query_peer(eee: &Node, dst_ip: u32) -> Result<()> { async fn send_query_peer(eee: &Node, dst_mac: Mac) -> Result<()> {
let network_id = eee.network_id.load(Ordering::Relaxed); let network_id = eee.network_id.load(Ordering::Relaxed);
if network_id == 0 { if network_id == 0 {
error!("not authed"); error!("not authed");
return Err(SDLanError::NormalError("not connected")); return Err(SDLanError::NormalError("not connected"));
} }
let query = SdlQueryInfo { dst_ip }; let query = SdlQueryInfo {
dst_mac: Vec::from(dst_mac),
};
let Ok(content) = encode_to_tcp_message( let Ok(content) = encode_to_tcp_message(
Some(query), Some(query),
@ -926,3 +1192,14 @@ pub async fn update_supernode_reg(eee: &Node) {
register_with_local_peers(eee).await; register_with_local_peers(eee).await;
} }
*/ */
pub fn form_ethernet_packet(src_mac: Mac, dst_mac: Mac, data: &[u8]) -> Vec<u8> {
let mut etherheader = Ethernet2Header::default();
etherheader.destination = dst_mac;
etherheader.ether_type = etherparse::EtherType::IPV4;
etherheader.source = src_mac;
let mut packet = Vec::with_capacity(14 + data.len() + 4);
packet.extend_from_slice(&etherheader.to_bytes()[..]);
packet.extend_from_slice(&data);
packet
}

127
src/network/route.rs Executable file
View File

@ -0,0 +1,127 @@
use std::{net::Ipv4Addr, sync::RwLock};
use once_cell::sync::OnceCell;
use sdlan_sn_rs::utils::net_bit_len_to_mask;
use tracing::{debug, error};
#[derive(Debug)]
pub struct RouteTable {
content: RwLock<Vec<RouteInfo>>,
}
static ROUTETABLE: OnceCell<RouteTable> = OnceCell::new();
pub fn init_route() {
let rt = RouteTable::new();
ROUTETABLE.set(rt).unwrap();
}
pub fn get_route_table() -> &'static RouteTable {
ROUTETABLE.get().unwrap()
}
impl RouteTable {
pub fn new() -> Self {
Self {
content: RwLock::new(Vec::new()),
}
}
pub fn get_gateway_ip(&self, net_ip: u32) -> Option<u32> {
let routes = self.content.read().unwrap();
for route in &*routes {
debug!("route: {:?}", route.to_string());
if (route.net_ip & route.net_mask) == (net_ip & route.net_mask) {
// found
return Some(route.gateway_ip);
}
}
None
}
pub fn del_route(&self, net_ip: u32, net_mask: u32) {
let mut routes = self.content.write().unwrap();
let mut remove_idx = routes.len();
for i in 0..routes.len() {
let route = &routes[i];
if route.net_ip == net_ip && route.net_mask == net_mask {
remove_idx = i;
break;
}
}
if remove_idx < routes.len() {
routes.remove(remove_idx);
}
}
pub fn add_route(&self, net_ip: u32, net_mask: u32, gateway_ip: u32) -> Result<(), String> {
{
let cnt = self.content.read().unwrap();
let net = net_ip & net_mask;
for route in &*cnt {
if (route.net_ip & route.net_mask) == net {
return Err("route exists".to_owned());
}
}
}
{
let mut routes = self.content.write().unwrap();
routes.push(RouteInfo {
net_ip,
net_mask,
gateway_ip,
})
}
Ok(())
}
}
#[derive(Debug)]
pub struct RouteInfo {
pub net_ip: u32,
pub net_mask: u32,
pub gateway_ip: u32,
}
impl RouteInfo {
pub fn to_string(&self) -> String {
format!(
"{:?} mask={:?}, gateway={:?}",
self.net_ip.to_be_bytes(),
self.net_mask.to_be_bytes(),
self.gateway_ip.to_be_bytes()
)
}
}
// ip, mask, gateway, cidr;gateway,cidr2;gateway2
pub fn parse_route(route: String) -> Vec<(u32, u32, u32)> {
let mut result = Vec::new();
let routes: Vec<_> = route.split(",").collect();
for route in routes {
let route_info: Vec<_> = route.split(";").collect();
debug!("got route info: {:?}", route_info);
if route_info.len() != 2 {
error!("route info format error");
continue;
}
let cidr = route_info[0];
let gateway = route_info[1].parse::<Ipv4Addr>().unwrap();
let ip_and_mask: Vec<_> = cidr.split("/").collect();
if ip_and_mask.len() != 2 {
error!("route info ip/bit error");
continue;
}
let ip = ip_and_mask[0].parse::<Ipv4Addr>().unwrap();
let maskbit = ip_and_mask[1].parse::<u8>().unwrap();
result.push((
u32::from_be_bytes(ip.octets()),
net_bit_len_to_mask(maskbit),
u32::from_be_bytes(gateway.octets()),
));
}
result
}

368
src/network/tun_linux.rs Normal file → Executable file
View File

@ -1,18 +1,36 @@
use sdlan_sn_rs::utils::{ip_to_string, net_bit_len_to_mask, SDLanError}; use etherparse::ether_type::ARP;
use etherparse::{Ethernet2Header, IpHeaders};
use sdlan_sn_rs::config::SDLAN_DEFAULT_TTL;
use sdlan_sn_rs::utils::{
aes_encrypt, ip_to_string, is_ipv6_multicast, is_multi_broadcast, net_bit_len_to_mask,
SDLanError, BROADCAST_MAC,
};
use std::ffi::CStr; use std::ffi::CStr;
use std::ffi::{c_char, c_int}; use std::ffi::{c_char, c_int};
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::ptr::null_mut; use std::ptr::null_mut;
use std::sync::atomic::Ordering;
use sdlan_sn_rs::utils::Result; use sdlan_sn_rs::utils::Result;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::os::fd::AsRawFd; use std::os::fd::AsRawFd;
use std::process::Command; use std::process::Command;
use tracing::{debug, error}; use tracing::{debug, error, info};
use crate::get_edge;
use crate::network::{
add_to_arp_wait_list, arp_arrived, generate_arp_request, send_arp_request, send_packet_to_net,
ArpHdr, ArpRequestInfo, ArpResponse, ARP_REPLY, ARP_REQUEST,
};
use crate::pb::{encode_to_udp_message, SdlData};
use crate::tcp::PacketType;
use crate::utils::{caculate_crc, mac_to_string};
use super::device::{DeviceConfig, Mode}; use super::device::{DeviceConfig, Mode};
use super::TunTapPacketHandler;
// #[link(name = "tuntap", kind="static")]
#[link(name = "tuntap")] #[link(name = "tuntap")]
extern "C" { extern "C" {
fn tuntap_setup(fd: c_int, name: *mut u8, mode: c_int, packet_info: c_int) -> c_int; fn tuntap_setup(fd: c_int, name: *mut u8, mode: c_int, packet_info: c_int) -> c_int;
@ -99,11 +117,22 @@ impl Iface {
let ip = ip_to_string(&ip); let ip = ip_to_string(&ip);
let netbit = ip_to_string(&net_bit_len_to_mask(netbit)); let netbit = ip_to_string(&net_bit_len_to_mask(netbit));
if cfg!(not(feature = "tun")) {
info!("set tap device");
let mac = device_config.get_mac();
let res = Command::new("ifconfig") let res = Command::new("ifconfig")
.arg(&self.name) .arg(&self.name)
.arg(ip) .arg(ip)
.arg("netmask") .arg("netmask")
.arg(&netbit) .arg(&netbit)
.arg("hw")
.arg("ether")
.arg(format!(
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
))
.arg("mtu")
.arg(format!("{}", device_config.mtu))
.arg("up") .arg("up")
.output(); .output();
match res { match res {
@ -114,6 +143,26 @@ impl Iface {
error!("failed to run ifconfig: {}", e.to_string()); error!("failed to run ifconfig: {}", e.to_string());
} }
} }
} else {
info!("set tun device");
let res = Command::new("ifconfig")
.arg(&self.name)
.arg(ip)
.arg("netmask")
.arg(&netbit)
.arg("mtu")
.arg(format!("{}", device_config.mtu))
.arg("up")
.output();
match res {
Ok(_) => {
debug!("ifconfig ok");
}
Err(e) => {
error!("failed to run ifconfig: {}", e.to_string());
}
}
}
} }
pub fn recv(&self, buf: &mut [u8]) -> std::io::Result<usize> { pub fn recv(&self, buf: &mut [u8]) -> std::io::Result<usize> {
@ -125,6 +174,321 @@ impl Iface {
} }
} }
#[cfg(not(feature = "tun"))]
impl TunTapPacketHandler for Iface {
async fn handle_packet_from_net(&self, data: &[u8], _: &[u8]) -> std::io::Result<()> {
// debug!("in tap mode, got data: {:?}", data);
match self.send(data) {
Err(e) => {
error!("failed to write to tap: {}", e.to_string());
return Err(e);
}
Ok(_) => return Ok(()),
}
}
async fn handle_packet_from_device(
&self,
data: Vec<u8>,
encrypt_key: &[u8],
) -> std::io::Result<()> {
debug!("in tap mode2");
let edge = get_edge();
match Ethernet2Header::from_slice(&data) {
Ok((hdr, _)) => {
let target = hdr.destination;
if is_ipv6_multicast(&target) {
return Ok(());
}
let size = data.len();
let Ok(encrypted) = aes_encrypt(encrypt_key, &data) else {
error!("failed to encrypt packet request");
return Ok(());
};
let data = SdlData {
is_p2p: true,
network_id: edge.network_id.load(Ordering::Relaxed),
ttl: SDLAN_DEFAULT_TTL as u32,
src_mac: Vec::from(edge.device_config.get_mac()),
dst_mac: Vec::from(target),
data: Vec::from(encrypted),
};
let msg = encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap();
send_packet_to_net(edge, target, &msg, size as u64).await;
}
Err(e) => {
error!("failed to parse packet from device");
}
};
Ok(())
}
}
#[cfg(feature = "tun")]
impl TunTapPacketHandler for Iface {
async fn handle_packet_from_net(&self, data: &[u8], key: &[u8]) -> std::io::Result<()> {
debug!("in tun mode");
// got layer 2 frame
match Ethernet2Header::from_slice(&data) {
Ok((hdr, rest)) => {
if rest.len() < 4 {
error!("payload length error");
return Ok(());
}
// let crc_code = &rest[(rest.len() - 4)..rest.len()];
// let rest = &rest[..(rest.len() - 4)];
// let crc_hash: crc::Crc<u32> = crc::Crc::<u32>::new(&crc::CRC_32_CKSUM);
// let ck = caculate_crc(&data[..(data.len() - 4)]);
// let sent_ck = u32::from_be_bytes(crc_code.try_into().unwrap());
// debug!("ck = {}, sent_ck = {}", ck, sent_ck);
debug!("ip size is {}", rest.len());
let edge = get_edge();
let self_mac = edge.device_config.get_mac();
if hdr.destination != self_mac && !is_multi_broadcast(&hdr.destination) {
error!(
"packet to [{:?}] not direct to us",
mac_to_string(&hdr.destination)
);
return Ok(());
}
if hdr.ether_type == ARP {
let mut arp = ArpHdr::from_slice(&data);
let self_ip = edge.device_config.get_ip();
// println!("self_ip: {:?}", self_ip.to_be_bytes());
let from_ip = ((arp.sipaddr[0] as u32) << 16) + arp.sipaddr[1] as u32;
// println!("from_ip: {:?}", from_ip.to_be_bytes());
let dest_ip = ((arp.dipaddr[0] as u32) << 16) + arp.dipaddr[1] as u32;
// println!("dest_ip: {:?}", dest_ip.to_be_bytes());
match arp.opcode {
ARP_REQUEST => {
// handle ARP REQUEST
debug!("got ARP REQUEST");
if arp.ethhdr.dest != [0xff; 6] {
debug!("ARP REQUEST not broadcast");
return Ok(());
}
if dest_ip == self_ip {
send_arp_request(ArpRequestInfo::Set {
ip: from_ip,
mac: arp.shwaddr,
})
.await;
// target to us
arp.opcode = ARP_REPLY;
arp.dhwaddr = arp.shwaddr;
arp.shwaddr = self_mac;
arp.ethhdr.src = self_mac;
arp.ethhdr.dest = arp.dhwaddr;
arp.dipaddr = arp.sipaddr;
arp.sipaddr =
[((self_ip >> 16) & 0xffff) as u16, (self_ip & 0xffff) as u16];
let data = arp.marshal_to_bytes();
let Ok(encrypted) = aes_encrypt(key, &data) else {
error!("failed to encrypt arp reply");
return Ok(());
};
let data = SdlData {
is_p2p: true,
ttl: 2,
network_id: edge.network_id.load(Ordering::Relaxed),
src_mac: Vec::from(self_mac),
dst_mac: Vec::from(arp.dhwaddr),
data: encrypted,
};
let v = encode_to_udp_message(Some(data), PacketType::Data as u8)
.unwrap();
debug!(
"xxxx send arp reply to [{}], selfmac=[{}]",
mac_to_string(&arp.dhwaddr),
mac_to_string(&self_mac)
);
send_packet_to_net(edge, arp.dhwaddr, &v, 0).await;
// send_to_sock(edge, &v, from_sock);
// edge.sock.send(v).await;
}
}
ARP_REPLY => {
debug!("mac {:?} is at {:?}", arp.shwaddr, from_ip.to_be_bytes());
if dest_ip == self_ip {
send_arp_request(ArpRequestInfo::Set {
ip: from_ip,
mac: arp.shwaddr,
})
.await;
arp_arrived(from_ip, arp.shwaddr).await;
}
}
_other => {
error!("unknown arp type info");
}
}
} else {
match IpHeaders::from_slice(rest) {
Ok((iphdr, _)) => {
let Some(ipv4) = iphdr.ipv4() else {
error!("not ipv4, dropping");
return Ok(());
};
let ip = u32::from_be_bytes(ipv4.0.source);
let mac = hdr.source;
if !is_multi_broadcast(&mac) {
send_arp_request(ArpRequestInfo::Set { ip, mac }).await;
}
}
Err(_) => {
error!("failed to parse ip header, dropping");
return Ok(());
}
}
// println!("got ip packet");
// println!("got data: {:?}", rest);
match edge.device.send(rest) {
Ok(size) => {
debug!("send to tun {} bytes", size);
}
Err(e) => {
error!("failed to send to device: {}", e.to_string());
}
}
// edge.tun.send_data_to_tun(Vec::from(hdr.1)).await;
}
}
Err(e) => {
error!("failed to parse tap packet: {}", e);
return Ok(());
}
}
Ok(())
}
async fn handle_packet_from_device(
&self,
data: Vec<u8>,
encrypt_key: &[u8],
) -> std::io::Result<()> {
let eee = get_edge();
let src_mac = eee.device_config.get_mac();
match IpHeaders::from_slice(&data) {
Ok((iphdr, _payload)) => {
let Some(ipv4hdr) = iphdr.ipv4() else {
debug!("ipv6 packet ignored");
return Ok(());
};
let dstip = u32::from_be_bytes(ipv4hdr.0.destination);
debug!("packet dst ip: {:?}", ipv4hdr.0.destination);
let src = u32::from_be_bytes(ipv4hdr.0.source);
debug!("packet src ip: {:?}", ipv4hdr.0.source);
// packet should be sent to dev
debug!("got {} bytes from tun", data.len());
if (!eee.config.allow_routing) && (src != eee.device_config.get_ip()) {
info!("dropping routed packet");
return Ok(());
}
if !eee.is_authorized() {
debug!("drop tun packet due to not authed");
return Ok(());
}
match send_arp_request(ArpRequestInfo::Lookup { ip: dstip }).await {
ArpResponse::LookupResp {
mac,
ip,
do_arp_request,
} => {
if do_arp_request {
add_to_arp_wait_list(dstip, data);
debug!(
"find ip: {:?} => {:?}",
src.to_be_bytes(),
dstip.to_be_bytes()
);
let arp_msg =
generate_arp_request(src_mac, ip, eee.device_config.get_ip());
let Ok(encrypted) = aes_encrypt(&encrypt_key, &arp_msg) else {
error!("failed to encrypt arp request");
return Ok(());
};
// println!("arp_msg: {:?}", arp_msg);
let data = SdlData {
network_id: eee.network_id.load(Ordering::Relaxed),
src_mac: Vec::from(src_mac),
dst_mac: Vec::from([0xff; 6]),
is_p2p: true,
ttl: SDLAN_DEFAULT_TTL as u32,
data: encrypted,
};
let data =
encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap();
debug!("sending arp");
// let data = marshal_message(&data);
send_packet_to_net(eee, BROADCAST_MAC, &data, arp_msg.len() as u64)
.await;
// edge.sock.send(data).await;
// println!("should send arp");
return Ok(());
}
// prepend the ether header
let mut etherheader = Ethernet2Header::default();
etherheader.destination = mac;
etherheader.ether_type = etherparse::EtherType::IPV4;
etherheader.source = src_mac;
let mut packet = Vec::with_capacity(14 + data.len() + 4);
packet.extend_from_slice(&etherheader.to_bytes()[..]);
packet.extend_from_slice(&data);
let crc = caculate_crc(&packet);
packet.extend_from_slice(&crc.to_be_bytes());
let pkt_size = packet.len();
// println!("sending data with mac");
let Ok(encrypted) = aes_encrypt(&encrypt_key, &packet) else {
error!("failed to encrypt packet request");
return Ok(());
};
let data = SdlData {
is_p2p: true,
network_id: eee.network_id.load(Ordering::Relaxed),
ttl: SDLAN_DEFAULT_TTL as u32,
src_mac: Vec::from(src_mac),
dst_mac: Vec::from(mac),
data: Vec::from(encrypted),
};
let msg =
encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap();
let size = msg.len();
send_packet_to_net(eee, mac, &msg, pkt_size as u64).await;
// let dstip = u32::from_be_bytes(ipv4hdr.0.destination);
}
_ => {}
}
}
Err(e) => {
error!("failed to parse ip packet: {}", e.to_string());
}
}
Ok(())
}
}
pub fn get_install_channel() -> String { pub fn get_install_channel() -> String {
"linux".to_owned() "linux".to_owned()
} }

316
src/network/tun_win.rs Normal file → Executable file
View File

@ -1,12 +1,29 @@
use sdlan_sn_rs::utils::{ip_to_string, net_bit_len_to_mask}; use etherparse::ether_type::ARP;
use etherparse::{Ethernet2Header, IpHeaders};
use sdlan_sn_rs::config::SDLAN_DEFAULT_TTL;
use sdlan_sn_rs::utils::{
aes_encrypt, ip_to_string, is_multi_broadcast, net_bit_len_to_mask, BROADCAST_MAC,
};
use std::io::{Error, ErrorKind}; use std::io::{Error, ErrorKind};
use std::os::windows::process::CommandExt; use std::os::windows::process::CommandExt;
use std::process::Command; use std::process::Command;
use std::sync::atomic::Ordering;
use std::sync::Arc; use std::sync::Arc;
use tracing::{debug, error, info};
use wintun; use wintun;
use tracing::{error, debug};
use super::device::{Mode, DeviceConfig}; use crate::get_edge;
use crate::network::{
add_to_arp_wait_list, arp_arrived, form_ethernet_packet, generate_arp_request,
send_arp_request, send_packet_to_net, ArpHdr, ArpRequestInfo, ArpResponse, ARP_REPLY,
ARP_REQUEST,
};
use crate::pb::{encode_to_udp_message, SdlData};
use crate::tcp::PacketType;
use crate::utils::mac_to_string;
use super::device::{DeviceConfig, Mode};
use super::TunTapPacketHandler;
pub struct Iface { pub struct Iface {
name: String, name: String,
@ -74,6 +91,293 @@ impl Iface {
error!("failed to run netsh: {}", e.to_string()); error!("failed to run netsh: {}", e.to_string());
} }
} }
let mut cmd = Command::new("netsh");
let command = cmd
.creation_flags(0x08000000)
.arg("interface")
.arg("ipv4")
.arg("set")
.arg("subinterface")
.arg(&format!("\"{}\"", self.name))
.arg(format!("mtu={}", device_config.mtu))
.arg("store=persistent");
let res = command.output();
match res {
Ok(r) => {
debug!("netsh2 ok: [{:?}]", String::from_utf8_lossy(&r.stdout));
}
Err(e) => {
error!("failed to run netsh2: {}", e.to_string());
}
}
}
}
impl TunTapPacketHandler for Iface {
async fn handle_packet_from_net(&self, data: &[u8], key: &[u8]) -> std::io::Result<()> {
// got layer 2 frame
match Ethernet2Header::from_slice(&data) {
Ok((hdr, rest)) => {
if rest.len() < 4 {
error!("payload length error");
return Ok(());
}
// let crc_code = &rest[(rest.len() - 4)..rest.len()];
// let rest = &rest[..(rest.len() - 4)];
// let crc_hash: crc::Crc<u32> = crc::Crc::<u32>::new(&crc::CRC_32_CKSUM);
// let ck = CRC_HASH.checksum(&data[..(data.len()) - 4]);
// let sent_ck = u32::from_be_bytes(crc_code.try_into().unwrap());
// debug!("ck = {}, sent_ck = {}", ck, sent_ck);
debug!("ip size is {}", rest.len());
let edge = get_edge();
let self_mac = edge.device_config.get_mac();
/*
if hdr.destination != self_mac && hdr.destination != BROADCAST_MAC {
error!(
"packet to [{:?}] not direct to us",
mac_to_string(&hdr.destination)
);
return;
}
*/
if hdr.ether_type == ARP {
let mut arp = ArpHdr::from_slice(&data);
let self_ip = edge.device_config.get_ip();
debug!("self_ip: {:?}", self_ip.to_be_bytes());
let from_ip = ((arp.sipaddr[0] as u32) << 16) + arp.sipaddr[1] as u32;
debug!("from_ip: {:?}", from_ip.to_be_bytes());
let dest_ip = ((arp.dipaddr[0] as u32) << 16) + arp.dipaddr[1] as u32;
debug!("dest_ip: {:?}", dest_ip.to_be_bytes());
match arp.opcode {
ARP_REQUEST => {
// handle ARP REQUEST
debug!("got ARP REQUEST");
if arp.ethhdr.dest != [0xff; 6] {
debug!("ARP REQUEST not broadcast");
return Ok(());
}
if dest_ip == self_ip {
send_arp_request(ArpRequestInfo::Set {
ip: from_ip,
mac: arp.shwaddr,
})
.await;
// target to us
arp.opcode = ARP_REPLY;
arp.dhwaddr = arp.shwaddr;
arp.shwaddr = self_mac;
arp.ethhdr.src = self_mac;
arp.ethhdr.dest = arp.dhwaddr;
arp.dipaddr = arp.sipaddr;
arp.sipaddr =
[((self_ip >> 16) & 0xffff) as u16, (self_ip & 0xffff) as u16];
let data = arp.marshal_to_bytes();
let Ok(encrypted) = aes_encrypt(key, &data) else {
error!("failed to encrypt arp reply");
return Ok(());
};
let data = SdlData {
is_p2p: true,
ttl: 2,
network_id: edge.network_id.load(Ordering::Relaxed),
src_mac: Vec::from(self_mac),
dst_mac: Vec::from(arp.dhwaddr),
data: encrypted,
};
let v = encode_to_udp_message(Some(data), PacketType::Data as u8)
.unwrap();
debug!(
"xxxx send arp reply to [{}], selfmac=[{}]",
mac_to_string(&arp.dhwaddr),
mac_to_string(&self_mac)
);
send_packet_to_net(edge, arp.dhwaddr, &v, 0).await;
// send_to_sock(edge, &v, from_sock);
// edge.sock.send(v).await;
}
}
ARP_REPLY => {
debug!("mac {:?} is at {:?}", arp.shwaddr, from_ip.to_be_bytes());
if dest_ip == self_ip {
send_arp_request(ArpRequestInfo::Set {
ip: from_ip,
mac: arp.shwaddr,
})
.await;
arp_arrived(from_ip, arp.shwaddr).await;
}
}
_other => {
error!("unknown arp type info");
}
}
} else {
match IpHeaders::from_slice(rest) {
Ok((iphdr, _)) => {
let Some(ipv4) = iphdr.ipv4() else {
error!("not ipv4, dropping");
return Ok(());
};
let ip = u32::from_be_bytes(ipv4.0.source);
let mac = hdr.source;
if !is_multi_broadcast(&mac) {
send_arp_request(ArpRequestInfo::Set { ip, mac }).await;
}
}
Err(_) => {
error!("failed to parse ip header, dropping");
return Ok(());
}
}
match edge.device.send(rest) {
Ok(size) => {
debug!("send to tun {} bytes", size);
}
Err(e) => {
error!("failed to send to device: {}", e.to_string());
}
}
// edge.tun.send_data_to_tun(Vec::from(hdr.1)).await;
}
}
Err(e) => {
error!("failed to parse tap packet: {}", e);
return Ok(());
}
}
Ok(())
}
async fn handle_packet_from_device(
&self,
data: Vec<u8>,
encrypt_key: &[u8],
) -> std::io::Result<()> {
let eee = get_edge();
let src_mac = eee.device_config.get_mac();
match IpHeaders::from_slice(&data) {
Ok((iphdr, _payload)) => {
let Some(ipv4hdr) = iphdr.ipv4() else {
debug!("ipv6 packet ignored");
return Ok(());
};
let dstip = u32::from_be_bytes(ipv4hdr.0.destination);
debug!("packet dst ip: {:?}", ipv4hdr.0.destination);
let src = u32::from_be_bytes(ipv4hdr.0.source);
debug!("packet src ip: {:?}", ipv4hdr.0.source);
// packet should be sent to dev
debug!("got {} bytes from tun", data.len());
if (!eee.config.allow_routing) && (src != eee.device_config.get_ip()) {
info!("dropping routed packet");
return Ok(());
}
if !eee.is_authorized() {
debug!("drop tun packet due to not authed");
return Ok(());
}
match send_arp_request(ArpRequestInfo::Lookup { ip: dstip }).await {
ArpResponse::LookupResp {
mac,
ip,
do_arp_request,
} => {
if do_arp_request {
add_to_arp_wait_list(dstip, data);
info!(
"find ip: {:?} => {:?}",
src.to_be_bytes(),
dstip.to_be_bytes()
);
let arp_msg =
generate_arp_request(src_mac, ip, eee.device_config.get_ip());
let Ok(encrypted) = aes_encrypt(&encrypt_key, &arp_msg) else {
error!("failed to encrypt arp request");
return Ok(());
};
// println!("arp_msg: {:?}", arp_msg);
let data = SdlData {
network_id: eee.network_id.load(Ordering::Relaxed),
src_mac: Vec::from(src_mac),
dst_mac: Vec::from([0xff; 6]),
is_p2p: true,
ttl: SDLAN_DEFAULT_TTL as u32,
data: encrypted,
};
let data =
encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap();
debug!("sending arp");
// let data = marshal_message(&data);
send_packet_to_net(eee, BROADCAST_MAC, &data, arp_msg.len() as u64)
.await;
// edge.sock.send(data).await;
// println!("should send arp");
return Ok(());
}
let packet = form_ethernet_packet(src_mac, mac, &data);
// prepend the ether header
/*
let mut etherheader = Ethernet2Header::default();
etherheader.destination = mac;
etherheader.ether_type = etherparse::EtherType::IPV4;
etherheader.source = src_mac;
let mut packet = Vec::with_capacity(14 + data.len() + 4);
packet.extend_from_slice(&etherheader.to_bytes()[..]);
packet.extend_from_slice(&data);
*/
// let crc = CRC_HASH.checksum(&packet);
// packet.extend_from_slice(&crc.to_be_bytes());
let pkt_size = packet.len();
// println!("sending data with mac");
let Ok(encrypted) = aes_encrypt(&encrypt_key, &packet) else {
error!("failed to encrypt packet request");
return Ok(());
};
let data = SdlData {
is_p2p: true,
network_id: eee.network_id.load(Ordering::Relaxed),
ttl: SDLAN_DEFAULT_TTL as u32,
src_mac: Vec::from(src_mac),
dst_mac: Vec::from(mac),
data: Vec::from(encrypted),
};
let msg =
encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap();
let size = msg.len();
send_packet_to_net(eee, mac, &msg, pkt_size as u64).await;
// let dstip = u32::from_be_bytes(ipv4hdr.0.destination);
}
_ => {}
}
}
Err(e) => {
error!("failed to parse ip packet: {}", e.to_string());
}
}
Ok(())
} }
} }
@ -86,7 +390,11 @@ fn create_wintun(path: &str,name: &str) -> Iface {
.expect("failed to create wintun adapter"), .expect("failed to create wintun adapter"),
}; };
let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY).unwrap()); let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY).unwrap());
Iface { _adapter: adapter, session, name: name.to_owned()} Iface {
_adapter: adapter,
session,
name: name.to_owned(),
}
} }
pub fn new_iface(name: &str, _mode: Mode) -> Iface { pub fn new_iface(name: &str, _mode: Mode) -> Iface {

0
src/network/tuntap.c Normal file → Executable file
View File

123
src/network/tuntap.rs Executable file
View File

@ -0,0 +1,123 @@
use std::sync::atomic::Ordering;
use dashmap::DashMap;
use etherparse::Ethernet2Header;
use once_cell::sync::OnceCell;
use sdlan_sn_rs::{
config::SDLAN_DEFAULT_TTL,
utils::{aes_encrypt, get_current_timestamp, ip_to_string, Mac},
};
use tracing::debug;
use tracing::error;
use crate::{
network::{form_ethernet_packet, send_packet_to_net},
pb::{encode_to_udp_message, SdlData},
tcp::PacketType,
utils::mac_to_string,
};
use super::get_edge;
pub const MAX_WAIT_PACKETS: usize = 100;
pub trait TunTapPacketHandler {
async fn handle_packet_from_net(&self, data: &[u8], key: &[u8]) -> std::io::Result<()>;
async fn handle_packet_from_device(&self, data: Vec<u8>, key: &[u8]) -> std::io::Result<()>;
}
static ARP_WAIT_LIST: OnceCell<ArpWaitList> = OnceCell::new();
pub fn init_arp_wait_list() {
let waitlist = ArpWaitList {
content: DashMap::new(),
};
ARP_WAIT_LIST.set(waitlist).unwrap();
}
#[derive(Debug)]
pub struct ArpWaitInfo {
timestamp: u64,
// origin data is from the tun or tap device
origin_data: Vec<u8>,
}
#[derive(Debug)]
pub struct ArpWaitList {
content: DashMap<u32, Vec<ArpWaitInfo>>,
}
impl ArpWaitList {
fn add_to_wait_list(&self, ip: u32, origin_data: Vec<u8>) {
let mut entry = self.content.entry(ip).or_insert(vec![]);
if entry.len() < MAX_WAIT_PACKETS {
entry.push(ArpWaitInfo {
timestamp: get_current_timestamp(),
origin_data,
})
}
}
async fn arp_arrived(&self, ip: u32, mac: Mac) {
debug!(
"arp for {} arrived: {}",
ip_to_string(&ip),
mac_to_string(&mac)
);
let Some(items) = self.content.remove(&ip) else {
return;
};
let edge = get_edge();
// just remove the items
if !edge.is_authorized() {
return;
}
let encrypt_key = edge.get_encrypt_key();
let network_id = edge.network_id.load(Ordering::Relaxed);
let src_mac = edge.device_config.get_mac();
let now = get_current_timestamp();
for item in items.1 {
if (now - item.timestamp) > 5 {
continue;
}
let packet = form_ethernet_packet(src_mac, mac, &item.origin_data);
let pkt_size = packet.len();
let Ok(encrypted) = aes_encrypt(&encrypt_key, &packet) else {
error!("failed to encrypt packet request");
return;
};
let data = SdlData {
is_p2p: true,
network_id,
ttl: SDLAN_DEFAULT_TTL as u32,
src_mac: Vec::from(src_mac),
dst_mac: Vec::from(mac),
data: Vec::from(encrypted),
};
let msg = encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap();
send_packet_to_net(edge, mac, &msg, pkt_size as u64).await;
}
}
}
pub fn add_to_arp_wait_list(ip: u32, origin_data: Vec<u8>) {
let waitlist = ARP_WAIT_LIST
.get()
.expect("ARP_WAIT_LIST has not been inited");
waitlist.add_to_wait_list(ip, origin_data);
}
pub async fn arp_arrived(ip: u32, mac: Mac) {
let waitlist = ARP_WAIT_LIST
.get()
.expect("ARP_WAIT_LIST has not been inited");
waitlist.arp_arrived(ip, mac).await;
}

View File

@ -23,9 +23,11 @@ pub struct Sdlv6Info {
pub struct SdlDevAddr { pub struct SdlDevAddr {
#[prost(uint32, tag = "1")] #[prost(uint32, tag = "1")]
pub network_id: u32, pub network_id: u32,
#[prost(uint32, tag = "2")] #[prost(bytes = "vec", tag = "2")]
pub net_addr: u32, pub mac: ::prost::alloc::vec::Vec<u8>,
#[prost(uint32, tag = "3")] #[prost(uint32, tag = "3")]
pub net_addr: u32,
#[prost(uint32, tag = "4")]
pub net_bit_len: u32, pub net_bit_len: u32,
} }
/// tcp通讯消息 /// tcp通讯消息
@ -47,6 +49,8 @@ pub struct SdlRegisterSuper {
pub pub_key: ::prost::alloc::string::String, pub pub_key: ::prost::alloc::string::String,
#[prost(string, tag = "6")] #[prost(string, tag = "6")]
pub token: ::prost::alloc::string::String, pub token: ::prost::alloc::string::String,
#[prost(string, tag = "7")]
pub network_code: ::prost::alloc::string::String,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
@ -55,13 +59,11 @@ pub struct SdlRegisterSuperAck {
pub dev_addr: ::core::option::Option<SdlDevAddr>, pub dev_addr: ::core::option::Option<SdlDevAddr>,
#[prost(bytes = "vec", tag = "2")] #[prost(bytes = "vec", tag = "2")]
pub aes_key: ::prost::alloc::vec::Vec<u8>, pub aes_key: ::prost::alloc::vec::Vec<u8>,
#[prost(bytes = "vec", tag = "3")] #[prost(uint32, tag = "3")]
pub known_ips: ::prost::alloc::vec::Vec<u8>,
#[prost(uint32, tag = "4")]
pub upgrade_type: u32, pub upgrade_type: u32,
#[prost(string, optional, tag = "5")] #[prost(string, optional, tag = "4")]
pub upgrade_prompt: ::core::option::Option<::prost::alloc::string::String>, pub upgrade_prompt: ::core::option::Option<::prost::alloc::string::String>,
#[prost(string, optional, tag = "6")] #[prost(string, optional, tag = "5")]
pub upgrade_address: ::core::option::Option<::prost::alloc::string::String>, pub upgrade_address: ::core::option::Option<::prost::alloc::string::String>,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
@ -75,14 +77,14 @@ pub struct SdlRegisterSuperNak {
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct SdlQueryInfo { pub struct SdlQueryInfo {
#[prost(uint32, tag = "1")] #[prost(bytes = "vec", tag = "1")]
pub dst_ip: u32, pub dst_mac: ::prost::alloc::vec::Vec<u8>,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct SdlPeerInfo { pub struct SdlPeerInfo {
#[prost(uint32, tag = "1")] #[prost(bytes = "vec", tag = "1")]
pub dst_ip: u32, pub dst_mac: ::prost::alloc::vec::Vec<u8>,
#[prost(message, optional, tag = "2")] #[prost(message, optional, tag = "2")]
pub v4_info: ::core::option::Option<Sdlv4Info>, pub v4_info: ::core::option::Option<Sdlv4Info>,
#[prost(message, optional, tag = "3")] #[prost(message, optional, tag = "3")]
@ -90,32 +92,24 @@ pub struct SdlPeerInfo {
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct SdlKnownIpEvent {
#[prost(uint32, tag = "1")]
pub ip: u32,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SdlDropIpEvent {
#[prost(uint32, tag = "1")]
pub ip: u32,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SdlNatChangedEvent { pub struct SdlNatChangedEvent {
#[prost(uint32, tag = "1")] #[prost(bytes = "vec", tag = "1")]
pub mac: ::prost::alloc::vec::Vec<u8>,
#[prost(uint32, tag = "2")]
pub ip: u32, pub ip: u32,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct SdlSendRegisterEvent { pub struct SdlSendRegisterEvent {
#[prost(uint32, tag = "1")] #[prost(bytes = "vec", tag = "1")]
pub dst_ip: u32, pub dst_mac: ::prost::alloc::vec::Vec<u8>,
#[prost(uint32, tag = "2")] #[prost(uint32, tag = "2")]
pub nat_ip: u32, pub nat_ip: u32,
#[prost(uint32, tag = "3")] #[prost(uint32, tag = "3")]
pub nat_port: u32, pub nat_port: u32,
#[prost(message, optional, tag = "4")] #[prost(uint32, tag = "4")]
pub nat_type: u32,
#[prost(message, optional, tag = "5")]
pub v6_info: ::core::option::Option<Sdlv6Info>, pub v6_info: ::core::option::Option<Sdlv6Info>,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
@ -131,8 +125,6 @@ pub struct SdlChangeNetworkCommand {
pub dev_addr: ::core::option::Option<SdlDevAddr>, pub dev_addr: ::core::option::Option<SdlDevAddr>,
#[prost(bytes = "vec", tag = "2")] #[prost(bytes = "vec", tag = "2")]
pub aes_key: ::prost::alloc::vec::Vec<u8>, pub aes_key: ::prost::alloc::vec::Vec<u8>,
#[prost(bytes = "vec", tag = "3")]
pub known_ips: ::prost::alloc::vec::Vec<u8>,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
@ -165,11 +157,13 @@ pub struct SdlStunRequest {
pub client_id: ::prost::alloc::string::String, pub client_id: ::prost::alloc::string::String,
#[prost(uint32, tag = "3")] #[prost(uint32, tag = "3")]
pub network_id: u32, pub network_id: u32,
#[prost(uint32, tag = "4")] #[prost(bytes = "vec", tag = "4")]
pub ip: u32, pub mac: ::prost::alloc::vec::Vec<u8>,
#[prost(uint32, tag = "5")] #[prost(uint32, tag = "5")]
pub ip: u32,
#[prost(uint32, tag = "6")]
pub nat_type: u32, pub nat_type: u32,
#[prost(message, optional, tag = "6")] #[prost(message, optional, tag = "7")]
pub v6_info: ::core::option::Option<Sdlv6Info>, pub v6_info: ::core::option::Option<Sdlv6Info>,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
@ -183,10 +177,10 @@ pub struct SdlStunReply {
pub struct SdlData { pub struct SdlData {
#[prost(uint32, tag = "1")] #[prost(uint32, tag = "1")]
pub network_id: u32, pub network_id: u32,
#[prost(uint32, tag = "2")] #[prost(bytes = "vec", tag = "2")]
pub src_ip: u32, pub src_mac: ::prost::alloc::vec::Vec<u8>,
#[prost(uint32, tag = "3")] #[prost(bytes = "vec", tag = "3")]
pub dst_ip: u32, pub dst_mac: ::prost::alloc::vec::Vec<u8>,
#[prost(bool, tag = "4")] #[prost(bool, tag = "4")]
pub is_p2p: bool, pub is_p2p: bool,
#[prost(uint32, tag = "5")] #[prost(uint32, tag = "5")]
@ -199,20 +193,20 @@ pub struct SdlData {
pub struct SdlRegister { pub struct SdlRegister {
#[prost(uint32, tag = "1")] #[prost(uint32, tag = "1")]
pub network_id: u32, pub network_id: u32,
#[prost(uint32, tag = "2")] #[prost(bytes = "vec", tag = "2")]
pub src_ip: u32, pub src_mac: ::prost::alloc::vec::Vec<u8>,
#[prost(uint32, tag = "3")] #[prost(bytes = "vec", tag = "3")]
pub dst_ip: u32, pub dst_mac: ::prost::alloc::vec::Vec<u8>,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct SdlRegisterAck { pub struct SdlRegisterAck {
#[prost(uint32, tag = "1")] #[prost(uint32, tag = "1")]
pub network_id: u32, pub network_id: u32,
#[prost(uint32, tag = "2")] #[prost(bytes = "vec", tag = "2")]
pub src_ip: u32, pub src_mac: ::prost::alloc::vec::Vec<u8>,
#[prost(uint32, tag = "3")] #[prost(bytes = "vec", tag = "3")]
pub dst_ip: u32, pub dst_mac: ::prost::alloc::vec::Vec<u8>,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]

0
src/pb/mod.rs Normal file → Executable file
View File

0
src/tcp/mod.rs Normal file → Executable file
View File

1
src/tcp/tcp_codec.rs Normal file → Executable file
View File

@ -44,6 +44,7 @@ pub enum NatType {
PortRestricted = 3, PortRestricted = 3,
ConeRestricted = 4, ConeRestricted = 4,
Symmetric = 5, Symmetric = 5,
Invalid = 0xff,
} }
#[derive(Debug, Copy, Clone, TryFromPrimitive)] #[derive(Debug, Copy, Clone, TryFromPrimitive)]

21
src/tcp/tcp_conn.rs Normal file → Executable file
View File

@ -59,7 +59,7 @@ impl ReadWriteActor {
remote: remote.to_owned(), remote: remote.to_owned(),
from_tcp, from_tcp,
connecting_chan, connecting_chan,
ipv6_network_restarter ipv6_network_restarter,
} }
} }
@ -112,7 +112,7 @@ impl ReadWriteActor {
} }
} }
*/ */
debug!("start stop chan recv none"); debug!("start stop chan received: {}", started);
continue; continue;
} }
@ -120,6 +120,7 @@ impl ReadWriteActor {
let _ = connecting_chan.send(ConnectionState::Connecting).await; let _ = connecting_chan.send(ConnectionState::Connecting).await;
} }
debug!("try connecting..."); debug!("try connecting...");
let Ok(mut stream) = TcpStream::connect(&self.remote).await else { let Ok(mut stream) = TcpStream::connect(&self.remote).await else {
self.connected.store(false, Ordering::Relaxed); self.connected.store(false, Ordering::Relaxed);
if keep_reconnect { if keep_reconnect {
@ -136,6 +137,7 @@ impl ReadWriteActor {
return; return;
}; };
self.connected.store(true, Ordering::Relaxed); self.connected.store(true, Ordering::Relaxed);
debug!("connected");
on_connected(&mut stream, start_pkt_id.take()).await; on_connected(&mut stream, start_pkt_id.take()).await;
if let Some(ref connecting_chan) = self.connecting_chan { if let Some(ref connecting_chan) = self.connecting_chan {
@ -204,7 +206,7 @@ impl ReadWriteActor {
return; return;
} }
} }
other => { _other => {
// send chan is closed; // send chan is closed;
started = false; started = false;
return; return;
@ -276,7 +278,15 @@ impl ReadWriterHandle {
let (from_tcp, mut data_from_tcp) = channel(20); let (from_tcp, mut data_from_tcp) = channel(20);
let connected: Arc<AtomicBool> = Arc::new(AtomicBool::new(false)); let connected: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
let actor = ReadWriteActor::new(cancel, addr, from_tcp, connected.clone(), pong_time, connecting_chan, ipv6_network_restarter); let actor = ReadWriteActor::new(
cancel,
addr,
from_tcp,
connected.clone(),
pong_time,
connecting_chan,
ipv6_network_restarter,
);
tokio::spawn(async move { tokio::spawn(async move {
actor actor
.run(true, to_tcp, on_connected, on_disconnected, start_stop_chan) .run(true, to_tcp, on_connected, on_disconnected, start_stop_chan)
@ -287,7 +297,8 @@ impl ReadWriterHandle {
if let Some(msg) = data_from_tcp.recv().await { if let Some(msg) = data_from_tcp.recv().await {
on_message(msg).await; on_message(msg).await;
} else { } else {
eprintln!("data from tcp exited"); error!("data from tcp exited");
// eprintln!("data from tcp exited");
return; return;
} }
} }

22
src/utils/command.rs Normal file → Executable file
View File

@ -2,8 +2,14 @@ use structopt::StructOpt;
#[derive(StructOpt, Debug)] #[derive(StructOpt, Debug)]
pub struct CommandLineInput { pub struct CommandLineInput {
#[structopt(long = "token", default_value = "")] #[structopt(long = "token", default_value = "", help="specify a token")]
pub token: String, pub token: String,
#[structopt(short = "p", long = "port", default_value = "0", help="which port to use")]
pub port: u16,
#[structopt(long = "code", default_value = "", help="specify a network code")]
pub network_code: String,
} }
#[derive(StructOpt, Debug)] #[derive(StructOpt, Debug)]
@ -25,6 +31,9 @@ pub struct CommandLine {
#[structopt(short = "r")] #[structopt(short = "r")]
pub _allow_routing: bool, pub _allow_routing: bool,
#[structopt(short = "dm")]
pub _drop_multicast: bool,
#[structopt( #[structopt(
help = "ttl of the register udp4 packet", help = "ttl of the register udp4 packet",
short = "L", short = "L",
@ -41,11 +50,17 @@ pub struct CommandLine {
#[structopt(long = "tos", default_value = "0")] #[structopt(long = "tos", default_value = "0")]
pub tos: u32, pub tos: u32,
#[structopt(long = "token", default_value = "0")] #[structopt(long = "token", default_value = "")]
pub token: String, pub token: String,
#[structopt(long = "code", default_value = "")]
pub network_code: String,
#[structopt(short = "p")] #[structopt(short = "p")]
pub allow_p2p: bool, pub allow_p2p: bool,
#[structopt(short = "l")]
pub local_port: u16,
} }
impl Clone for CommandLine { impl Clone for CommandLine {
@ -54,11 +69,14 @@ impl Clone for CommandLine {
sn: self.sn.clone(), sn: self.sn.clone(),
tcp: self.tcp.clone(), tcp: self.tcp.clone(),
_allow_routing: self._allow_routing, _allow_routing: self._allow_routing,
_drop_multicast: self._drop_multicast,
register_ttl: self.register_ttl, register_ttl: self.register_ttl,
mtu: self.mtu, mtu: self.mtu,
local_port: self.local_port,
name: self.name.clone(), name: self.name.clone(),
tos: self.tos, tos: self.tos,
token: self.token.clone(), token: self.token.clone(),
network_code: self.network_code.clone(),
allow_p2p: self.allow_p2p, allow_p2p: self.allow_p2p,
nat_server1: self.nat_server1.clone(), nat_server1: self.nat_server1.clone(),
nat_server2: self.nat_server2.clone(), nat_server2: self.nat_server2.clone(),

31
src/utils/mod.rs Normal file → Executable file
View File

@ -1,8 +1,39 @@
mod command; mod command;
pub use command::*; pub use command::*;
mod socks; mod socks;
use rand::Rng;
use sdlan_sn_rs::utils::Mac;
pub use socks::*; pub use socks::*;
mod pid_recorder; mod pid_recorder;
pub use pid_recorder::PidRecorder; pub use pid_recorder::PidRecorder;
// pub const CRC_HASH: crc::Crc<u32> = crc::Crc::<u32>::new(&crc::CRC_32_XFER);
#[allow(unused)]
pub fn caculate_crc(data: &[u8]) -> u32 {
let res = crc32fast::hash(data);
res
}
pub fn mac_to_string(mac: &Mac) -> String {
format!(
"[{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}]",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
)
}
pub fn generate_mac_address() -> Mac {
let mut rng = rand::thread_rng();
let mut mac = [0; 6];
for i in 0..6 {
let number: u8 = rng.gen();
mac[i] = number;
}
mac[0] &= !0x01;
mac[0] |= 0x02;
mac
}

7
src/utils/pid_recorder.rs Normal file → Executable file
View File

@ -2,6 +2,7 @@ use std::{
fs::{self, OpenOptions}, fs::{self, OpenOptions},
io::Write, io::Write,
}; };
use tracing::{debug, error};
pub struct PidRecorder(String); pub struct PidRecorder(String);
@ -19,7 +20,8 @@ impl PidRecorder {
.expect("failed to write"); .expect("failed to write");
} }
Err(e) => { Err(e) => {
eprintln!("failed to open pid file: {}", e); error!("failed to open pid file: {}", e);
// eprintln!("failed to open pid file: {}", e);
} }
} }
@ -30,7 +32,8 @@ impl PidRecorder {
impl Drop for PidRecorder { impl Drop for PidRecorder {
fn drop(&mut self) { fn drop(&mut self) {
if let Err(e) = fs::remove_file(&self.0) { if let Err(e) = fs::remove_file(&self.0) {
eprintln!("failed to remove pid file: {}", e); error!("failed to remove pid file: {}", e);
// eprintln!("failed to remove pid file: {}", e);
} }
} }
} }

6
src/utils/socks.rs Normal file → Executable file
View File

@ -11,11 +11,11 @@ use tokio::net::UdpSocket;
use crate::network::Node; use crate::network::Node;
#[allow(unused)]
pub struct SocketV6 { pub struct SocketV6 {
ipv6: Option<Ipv4Addr>, ipv6: Option<Ipv4Addr>,
port: u16, port: u16,
has_v6: bool, has_v6: bool,
} }
pub struct Socket { pub struct Socket {
@ -58,9 +58,7 @@ impl Socket {
pub async fn build_v6(v6: Ipv6Addr, port: u16) -> Result<Self> { pub async fn build_v6(v6: Ipv6Addr, port: u16) -> Result<Self> {
let udp = UdpSocket::bind(format!("[{}]:{}", v6, port)).await?; let udp = UdpSocket::bind(format!("[{}]:{}", v6, port)).await?;
Ok(Self { Ok(Self { udp })
udp
})
} }
pub async fn build(port: u16, bind_any: bool, join_multicast: bool, tos: u32) -> Result<Self> { pub async fn build(port: u16, bind_any: bool, join_multicast: bool, tos: u32) -> Result<Self> {

2
start_docker.sh Executable file
View File

@ -0,0 +1,2 @@
## pull image: docker pull ubuntu
docker run -v .:/root/punchnet -it --device=/dev/net/tun --cap-add=NET_ADMIN --cap-add=SYS_ADMIN -w /root/punchnet ubuntu

BIN
wintun.dll Executable file

Binary file not shown.