Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c5b04eb843 | |||
| 214e73a0b9 | |||
| 6ef685420c | |||
| f9c33b564f | |||
| d8c908a0b2 | |||
| 2fc246a1fe | |||
| 89f7db657d | |||
| 43c2b01fca | |||
| b36f526cfc | |||
| 2096c3faac | |||
| 0300eb9ade | |||
| 6672e78c42 | |||
| b343124821 | |||
| fad345becb | |||
| 41a21188bf | |||
| 9861c4e850 | |||
| e003584463 | |||
| 6ab4f7042b | |||
| 1e429ad874 | |||
| c2a3048427 | |||
| 8db61a7bbb | |||
| 6f996d020a | |||
| df06803004 | |||
| d9b1329e6a | |||
| ec68a54957 | |||
| 9a72c29870 | |||
| 7fa2ffa04d | |||
| 6e8f4583d6 | |||
| 3f6da7c65e | |||
| 7e5792e190 | |||
| 4aa33a4e26 | |||
| 4fdcfa5bee | |||
| c070d345ad | |||
| 51c323008a | |||
| 63805d9a47 | |||
| 240a3d263e | |||
| c098a3c421 | |||
| b51c78bdfb | |||
| 966f054a63 | |||
| f3cbc1def2 | |||
| 7a75c1d171 | |||
| 93f3dbdcf9 | |||
| c28c9e2911 | |||
| 2b8a536151 | |||
| e32c640466 | |||
| 07c6536d5a | |||
| d1e30370fc | |||
| 69255d7907 | |||
| e7352c7b67 | |||
| c4c1f109b1 | |||
| cb71c53102 | |||
| 06d7819fd1 | |||
| 220cee4a89 | |||
| 9b1710e590 | |||
| 7c4bb64bd4 | |||
| 6dd3d8694c | |||
| 1a5e1d8be3 | |||
| c130dcc83e | |||
| 53b0be35a7 | |||
| 893eef5871 | |||
| 32bbdc4f78 | |||
| af56edd331 | |||
| 3e4fe82a59 | |||
| 302300294a | |||
| 56d6a35fea |
14
.cargo/config.toml
Executable file
14
.cargo/config.toml
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
[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-gcc"
|
||||||
|
strip = { path = "aarch64-linux-gnu-strip" }
|
||||||
|
# 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
8
.gitignore
vendored
Normal file → Executable file
@ -4,3 +4,11 @@
|
|||||||
.client
|
.client
|
||||||
.output
|
.output
|
||||||
sdlan
|
sdlan
|
||||||
|
sdlan.exe
|
||||||
|
*.bak
|
||||||
|
*.a
|
||||||
|
*.o
|
||||||
|
*.tar
|
||||||
|
*.tar.gz
|
||||||
|
*.tgz
|
||||||
|
/punchnet
|
||||||
|
|||||||
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
// "rust-analyzer.cargo.target": "x86_64-pc-windows-gnu"
|
||||||
|
// "rust-analyzer.cargo.features": ["tun"]
|
||||||
|
}
|
||||||
2318
Cargo.lock
generated
2318
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
43
Cargo.toml
Normal file → Executable file
43
Cargo.toml
Normal file → Executable 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,46 @@ 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"
|
||||||
|
reqwest = { version = "0.12.24", default_features = false, features = ["json", "rustls-tls"] }
|
||||||
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"}
|
||||||
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
|
# 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"
|
||||||
|
myactor = { git = "https://gitea.s5s8.com/rust/actor-rs.git" }
|
||||||
|
# rolling-file = { path = "../rolling-file" }
|
||||||
|
|
||||||
|
[target.'cfg(unix)'.dependencies]
|
||||||
|
libc = "0.2.178"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
wintun = "0.4.0"
|
wintun = "0.4.0"
|
||||||
|
winapi = "0.3.9"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
tun = []
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cargo-deb = "3.6.2"
|
||||||
|
|
||||||
|
[package.metadata.deb]
|
||||||
|
maintainer = "alex <asxalex@163.com>"
|
||||||
|
copyright = "2025, alex"
|
||||||
|
# license-file = ["MIT"]
|
||||||
|
depends = "$auto"
|
||||||
|
|
||||||
|
## assets
|
||||||
|
assets = [
|
||||||
|
# executable
|
||||||
|
["target/release/punchnet", "usr/local/punchnet/punchnet", "755"],
|
||||||
|
# lib
|
||||||
|
["libtuntap.so", "usr/lib/", "755"],
|
||||||
|
]
|
||||||
|
|
||||||
|
maintainer-scripts = "debian"
|
||||||
|
|||||||
33
Makefile
Normal file → Executable file
33
Makefile
Normal file → Executable file
@ -1,9 +1,38 @@
|
|||||||
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
|
||||||
|
|
||||||
|
deb: libtun-so
|
||||||
|
RUSTFLAGS="-L ." cargo deb
|
||||||
|
|
||||||
|
deb-aarch64: libtun-so-aarch64
|
||||||
|
RUSTFLAGS="-L ." cargo deb --target aarch64-unknown-linux-gnu
|
||||||
|
|
||||||
|
|||||||
9
debian/postinst
vendored
Normal file
9
debian/postinst
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
#DEBHELPER#
|
||||||
|
|
||||||
|
ln -sf /usr/local/punchnet/punchnet /usr/bin/punchnet
|
||||||
|
|
||||||
|
exit 0;
|
||||||
9
debian/postrm
vendored
Normal file
9
debian/postrm
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
#DEBHELPER#
|
||||||
|
|
||||||
|
rm -rf /usr/lib/libswscale.so.5
|
||||||
|
|
||||||
|
exit 0;
|
||||||
13
install.sh
Normal file
13
install.sh
Normal 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
|
||||||
@ -16,8 +16,10 @@ 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;
|
||||||
|
string network_domain = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// tcp通讯消息
|
// tcp通讯消息
|
||||||
@ -32,15 +34,16 @@ 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;
|
||||||
|
string hostname = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 +54,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 +87,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 +110,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 +122,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 +131,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
216
nat-simulator.sh
Executable 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
12
punchnet.service
Normal 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
4
remote.record
Normal 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)
|
||||||
0
src/bin/build_pb/main.rs
Normal file → Executable file
0
src/bin/build_pb/main.rs
Normal file → Executable file
151
src/bin/punchnet/main.rs
Executable file
151
src/bin/punchnet/main.rs
Executable file
@ -0,0 +1,151 @@
|
|||||||
|
use punchnet::get_base_dir;
|
||||||
|
use punchnet::get_edge;
|
||||||
|
use punchnet::mod_hostname;
|
||||||
|
use punchnet::restore_dns;
|
||||||
|
use punchnet::run_sdlan;
|
||||||
|
use punchnet::set_base_dir;
|
||||||
|
use punchnet::CommandLine;
|
||||||
|
use punchnet::CommandLineInput;
|
||||||
|
use sdlan_sn_rs::log;
|
||||||
|
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
|
use std::net::ToSocketAddrs;
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
set_base_dir("/usr/local/punchnet");
|
||||||
|
let _guard = log::init_log(&format!("{}/.output", get_base_dir()));
|
||||||
|
|
||||||
|
let cmd = CommandLineInput::from_args();
|
||||||
|
|
||||||
|
|
||||||
|
// println!("port is {}", cmd.port);
|
||||||
|
|
||||||
|
let (tx, rx) = std::sync::mpsc::channel();
|
||||||
|
|
||||||
|
let hostname = "punchnet.aioe.tech".to_owned();
|
||||||
|
let host = format!("{}:80", hostname);
|
||||||
|
let mut server = String::new();
|
||||||
|
if let Ok(addrs) = host.to_socket_addrs() {
|
||||||
|
for addr in addrs {
|
||||||
|
let h = addr.to_string().split(":").take(1).collect::<Vec<_>>()[0].to_owned();
|
||||||
|
server = h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if server.is_empty() {
|
||||||
|
println!("failed to resolv host ip");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("server is {}", server);
|
||||||
|
|
||||||
|
mod_hostname::get_hostname();
|
||||||
|
/*
|
||||||
|
let hostname = if cmd.hostname.len() == 0 {
|
||||||
|
mod_hostname::get_hostname()
|
||||||
|
} else {
|
||||||
|
Some(cmd.hostname)
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
let hostname = if cmd.hostname.len() == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(cmd.hostname)
|
||||||
|
};
|
||||||
|
// let hostname = mod_hostname::get_hostname();
|
||||||
|
println!("hostname = {:?}", hostname);
|
||||||
|
|
||||||
|
let _ = run_sdlan(
|
||||||
|
CommandLine {
|
||||||
|
sn: server.clone()+":1265",
|
||||||
|
tcp: server.clone()+":18083",
|
||||||
|
nat_server1: server.clone() +":1265",
|
||||||
|
nat_server2: "47.98.178.3:1265".to_owned(),
|
||||||
|
_allow_routing: true,
|
||||||
|
_drop_multicast: true,
|
||||||
|
register_ttl: 1,
|
||||||
|
mtu: 1400,
|
||||||
|
name: "tau".to_owned(),
|
||||||
|
tos: 0,
|
||||||
|
local_port: cmd.port,
|
||||||
|
token: cmd.token.clone(),
|
||||||
|
network_code: cmd.network_code.clone(),
|
||||||
|
allow_p2p: true,
|
||||||
|
},
|
||||||
|
tx,
|
||||||
|
&punchnet::get_install_channel(),
|
||||||
|
server,
|
||||||
|
hostname,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let _ = rx.recv();
|
||||||
|
|
||||||
|
let edge = get_edge();
|
||||||
|
// let res = edge.start_without_feedback(cmd.token).await;
|
||||||
|
/*
|
||||||
|
let res = match edge
|
||||||
|
.start_with_feedback(cmd.token, Duration::from_secs(3))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(res) => res,
|
||||||
|
Err(e) => {
|
||||||
|
error!("failed to start: {:?}", e);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("here1");
|
||||||
|
|
||||||
|
if res.result != 0 {
|
||||||
|
println!("failed to start: {}", res.message);
|
||||||
|
if res.should_exit {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
// edge.stop().await;
|
||||||
|
// exit(0);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if let Err(e) = edge.start_without_feedback(cmd.token, cmd.network_code, None).await {
|
||||||
|
error!("failed to start: {:?}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
tokio::time::sleep(Duration::from_secs(20)).await;
|
||||||
|
edge.stop().await;
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
let mut stream =
|
||||||
|
tokio::signal::unix::signal(tokio::signal::unix::SignalKind::user_defined1()).unwrap();
|
||||||
|
|
||||||
|
let mut started = true;
|
||||||
|
*/
|
||||||
|
|
||||||
|
match tokio::signal::ctrl_c().await {
|
||||||
|
Ok(()) => {
|
||||||
|
let _ = restore_dns();
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("failed to listen for shutdown signal: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::process::exit(0);
|
||||||
|
|
||||||
|
// loop {
|
||||||
|
// tokio::time::sleep(Duration::from_secs(10)).await;
|
||||||
|
// /*
|
||||||
|
// let sig = stream.recv().await;
|
||||||
|
// if started {
|
||||||
|
// edge.stop().await;
|
||||||
|
// } else {
|
||||||
|
// edge.start("0".to_owned()).await;
|
||||||
|
// }
|
||||||
|
// started = !started;
|
||||||
|
// */
|
||||||
|
// }
|
||||||
|
}
|
||||||
@ -1,82 +0,0 @@
|
|||||||
use sdlan_rs::get_edge;
|
|
||||||
use sdlan_rs::run_sdlan;
|
|
||||||
use sdlan_rs::CommandLine;
|
|
||||||
use sdlan_rs::CommandLineInput;
|
|
||||||
use sdlan_sn_rs::log;
|
|
||||||
|
|
||||||
use std::process::exit;
|
|
||||||
use std::time::Duration;
|
|
||||||
use structopt::StructOpt;
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() {
|
|
||||||
let _guard = log::init_log();
|
|
||||||
|
|
||||||
let cmd = CommandLineInput::from_args();
|
|
||||||
|
|
||||||
let (tx, rx) = std::sync::mpsc::channel();
|
|
||||||
let _ = run_sdlan(
|
|
||||||
CommandLine {
|
|
||||||
sn: "39.98.184.67:1265".to_owned(),
|
|
||||||
tcp: "39.98.184.67:18083".to_owned(),
|
|
||||||
nat_server1: "39.98.184.67:1265".to_owned(),
|
|
||||||
nat_server2: "47.98.178.3:1265".to_owned(),
|
|
||||||
_allow_routing: true,
|
|
||||||
register_ttl: 1,
|
|
||||||
mtu: 1290,
|
|
||||||
name: "tau".to_owned(),
|
|
||||||
tos: 0,
|
|
||||||
token: "".to_owned(),
|
|
||||||
allow_p2p: true,
|
|
||||||
},
|
|
||||||
tx,
|
|
||||||
&sdlan_rs::get_install_channel(),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let _ = rx.recv();
|
|
||||||
|
|
||||||
let edge = get_edge();
|
|
||||||
// let res = edge.start_without_feedback(cmd.token).await;
|
|
||||||
let Ok(res) = edge
|
|
||||||
.start_with_feedback(cmd.token, Duration::from_secs(3))
|
|
||||||
.await
|
|
||||||
else {
|
|
||||||
println!("failed to start1");
|
|
||||||
exit(0);
|
|
||||||
};
|
|
||||||
|
|
||||||
if res.result != 0 {
|
|
||||||
println!("failed to start: {}", res.message);
|
|
||||||
if res.should_exit {
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
// edge.stop().await;
|
|
||||||
// exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
tokio::time::sleep(Duration::from_secs(20)).await;
|
|
||||||
edge.stop().await;
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
let mut stream =
|
|
||||||
tokio::signal::unix::signal(tokio::signal::unix::SignalKind::user_defined1()).unwrap();
|
|
||||||
|
|
||||||
let mut started = true;
|
|
||||||
*/
|
|
||||||
loop {
|
|
||||||
tokio::time::sleep(Duration::from_secs(10)).await;
|
|
||||||
/*
|
|
||||||
let sig = stream.recv().await;
|
|
||||||
if started {
|
|
||||||
edge.stop().await;
|
|
||||||
} else {
|
|
||||||
edge.start("0".to_owned()).await;
|
|
||||||
}
|
|
||||||
started = !started;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
30
src/config/mod.rs
Normal file → Executable file
30
src/config/mod.rs
Normal file → Executable file
@ -1,4 +1,9 @@
|
|||||||
pub const REGISTER_INTERVAL: u8 = 20;
|
use std::fs;
|
||||||
|
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
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 +12,26 @@ 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];
|
||||||
|
|
||||||
|
pub static BASE_DIR: OnceCell<String> = OnceCell::new();
|
||||||
|
|
||||||
|
pub fn get_base_dir() -> &'static str {
|
||||||
|
match BASE_DIR.get() {
|
||||||
|
Some(data) => {
|
||||||
|
data
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
"."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_base_dir(base_dir: &str) {
|
||||||
|
fs::create_dir_all(base_dir).unwrap();
|
||||||
|
let base = base_dir.trim_end_matches("/");
|
||||||
|
if let Err(_) = BASE_DIR.set(base.to_owned()) {
|
||||||
|
println!("failed to set base dir");
|
||||||
|
}
|
||||||
|
}
|
||||||
121
src/lib.rs
Normal file → Executable file
121
src/lib.rs
Normal file → Executable file
@ -4,23 +4,36 @@ mod pb;
|
|||||||
mod tcp;
|
mod tcp;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
use std::{sync::atomic::AtomicU8, time::Duration};
|
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;
|
||||||
|
pub use network::{async_main, init_arp, init_edge, NodeConfig, restore_dns};
|
||||||
|
use sdlan_sn_rs::utils::save_to_file;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tokio::net::UdpSocket;
|
||||||
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, mod_hostname};
|
||||||
pub use network::get_install_channel;
|
|
||||||
|
pub use config::{get_base_dir, set_base_dir};
|
||||||
|
|
||||||
use sdlan_sn_rs::{
|
use sdlan_sn_rs::{
|
||||||
peer::SdlanSock,
|
peer::SdlanSock,
|
||||||
utils::{create_or_load_uuid, get_sdlan_sock_from_socketaddr, Result, SDLanError},
|
utils::{create_or_load_uuid, get_sdlan_sock_from_socketaddr, Result, SDLanError},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum ConnectionInfo {
|
||||||
|
ConnState(ConnectionState),
|
||||||
|
IPInfo(String),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum ConnectionState {
|
pub enum ConnectionState {
|
||||||
@ -34,24 +47,52 @@ 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>>
|
server_ip: String,
|
||||||
// start_stop_sender: Sender<String>,
|
|
||||||
|
hostname: Option<String>,
|
||||||
|
connecting_chan: Option<Sender<ConnectionInfo>>, // 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(&format!("{}/.id", get_base_dir()), None)?;
|
||||||
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 {
|
let hostfile = format!("{}/.host", get_base_dir());
|
||||||
|
let host = create_or_load_uuid(&hostfile, Some(8))?;
|
||||||
|
|
||||||
|
init_arp();
|
||||||
|
|
||||||
|
let hostname = hostname.unwrap_or(host);
|
||||||
|
let _ = save_to_file(&hostfile, &hostname);
|
||||||
|
|
||||||
|
let sock = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
|
||||||
|
|
||||||
|
if let Err(e) = init_edge(
|
||||||
|
&args.token,
|
||||||
|
&args.network_code,
|
||||||
|
node_conf,
|
||||||
|
args.tos,
|
||||||
|
start_stop_sender,
|
||||||
|
args.mtu,
|
||||||
|
connecting_chan.clone(),
|
||||||
|
sock,
|
||||||
|
hostname,
|
||||||
|
server_ip,
|
||||||
|
install_channel.to_owned(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
panic!("failed to init edge: {:?}", e);
|
panic!("failed to init edge: {:?}", e);
|
||||||
}
|
}
|
||||||
let _ = sender.send(true);
|
let _ = sender.send(true);
|
||||||
debug!("edge inited");
|
debug!("edge inited");
|
||||||
|
|
||||||
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(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 +150,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),
|
||||||
@ -160,6 +201,64 @@ fn parse_sns<'a>(sns: &'a Vec<&'a str>) -> (Vec<&'a str>, Vec<SdlanSock>) {
|
|||||||
(correct_sns, result)
|
(correct_sns, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
struct NetworkReq<'a> {
|
||||||
|
client_id: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub struct NetworkRespSingleNetwork {
|
||||||
|
pub name: String,
|
||||||
|
pub code: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub struct NetworkRespNetworks {
|
||||||
|
pub network: Vec<NetworkRespSingleNetwork>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub struct NetworkResp {
|
||||||
|
pub result: NetworkRespNetworks,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_my_networks(url: &str) -> Result<Vec<NetworkRespSingleNetwork>>{
|
||||||
|
let edge_uuid = create_or_load_uuid(&format!("{}/.id", get_base_dir()), None)?;
|
||||||
|
|
||||||
|
let req_data = NetworkReq {
|
||||||
|
client_id: &edge_uuid,
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(client) = reqwest::Client::builder()
|
||||||
|
.timeout(Duration::from_secs(5)).build() else {
|
||||||
|
return Err(SDLanError::NormalError("failed to create client"));
|
||||||
|
};
|
||||||
|
// match client.post("https://punchnet.s5s8.com/api/get_user_network")
|
||||||
|
match client.post(url)
|
||||||
|
.json(&req_data)
|
||||||
|
.send().await {
|
||||||
|
|
||||||
|
Ok(response) => {
|
||||||
|
let Ok(network) = response.json::<NetworkResp>().await else {
|
||||||
|
return Err(SDLanError::NormalError("failed to jsonify get_user_network "));
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(network.result.network)
|
||||||
|
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("failed to send get_user_network: {}", e);
|
||||||
|
return Err(SDLanError::NormalError("failed to get_user_network"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// let Ok(response) = client.post("https://punchnet.aioe.tech/api/get_all_networks")
|
||||||
|
// .json(&req_data)
|
||||||
|
// .send().await else {
|
||||||
|
// return Err(SDLanError::NormalError("failed to send get_all_networks"));
|
||||||
|
// };
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use sdlan_sn_rs::config::AF_INET;
|
use sdlan_sn_rs::config::AF_INET;
|
||||||
|
|||||||
420
src/network/arp.rs
Executable file
420
src/network/arp.rs
Executable file
@ -0,0 +1,420 @@
|
|||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
sync::atomic::{AtomicU8, Ordering},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
use sdlan_sn_rs::utils::{BROADCAST_MAC, MULTICAST_MAC, Mac, ip_to_string, net_bit_len_to_mask};
|
||||||
|
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) -> Option<([u8; 6], u32, bool)> {
|
||||||
|
if ip == BROADCAST_IPADDR {
|
||||||
|
return Some((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 Some((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 Some((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 {
|
||||||
|
error!("target should not route to me: ip = {}", ip_to_string(&ip));
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if let Some(entry) = self.entry.get(&target_ip) {
|
||||||
|
return Some((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 Some((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 Some(mac) = arp.lookup_ip_mac(ip) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
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()
|
||||||
|
}
|
||||||
494
src/network/async_main.rs
Normal file → Executable file
494
src/network/async_main.rs
Normal file → Executable file
@ -1,262 +1,34 @@
|
|||||||
use std::net::IpAddr;
|
|
||||||
use std::sync::atomic::Ordering;
|
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::{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::{
|
||||||
use crate::pb::{
|
get_edge, ping_to_sn, read_and_parse_packet, TunTapPacketHandler,
|
||||||
encode_to_tcp_message, encode_to_udp_message, SdlData, SdlDevAddr, SdlRegisterSuper,
|
|
||||||
SdlRegisterSuperAck, SdlRegisterSuperNak, SdlSendRegisterEvent, SdlStunRequest, Sdlv6Info,
|
|
||||||
};
|
};
|
||||||
use crate::tcp::{init_tcp_conn, EventType, NakMsgCode, PacketType, SdlanTcp};
|
use crate::tcp::{init_tcp_conn, send_stun_request};
|
||||||
use crate::utils::{send_to_sock, CommandLine};
|
use crate::utils::{send_to_sock, CommandLine};
|
||||||
use crate::ConnectionState;
|
use crate::{ConnectionInfo};
|
||||||
use etherparse::IpHeaders;
|
use sdlan_sn_rs::peer::{SdlanSock};
|
||||||
use sdlan_sn_rs::config::{AF_INET, AF_INET6, SDLAN_DEFAULT_TTL};
|
use sdlan_sn_rs::utils::{get_current_timestamp, is_multi_broadcast};
|
||||||
use sdlan_sn_rs::peer::{SdlanSock, V6Info};
|
use sdlan_sn_rs::utils::{Mac, Result};
|
||||||
use sdlan_sn_rs::utils::Result;
|
use tokio::net::{UdpSocket};
|
||||||
use sdlan_sn_rs::utils::{
|
|
||||||
aes_encrypt, get_current_timestamp, ip_to_string, is_multi_broadcast, rsa_decrypt,
|
|
||||||
};
|
|
||||||
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;
|
||||||
|
|
||||||
use super::{check_peer_registration_needed, packet, Node, StartStopInfo};
|
use super::{Node, StartStopInfo};
|
||||||
use crate::utils::Socket;
|
use crate::utils::Socket;
|
||||||
|
|
||||||
use prost::Message;
|
use tracing::{debug, error};
|
||||||
use tracing::{debug, error, info};
|
|
||||||
|
|
||||||
async fn handle_tcp_message(msg: SdlanTcp) {
|
|
||||||
let edge = get_edge();
|
|
||||||
|
|
||||||
// let now = get_current_timestamp();
|
|
||||||
// edge.tcp_pong.store(now, Ordering::Relaxed);
|
|
||||||
|
|
||||||
debug!("got tcp message: {:?}", msg.packet_type);
|
|
||||||
match msg.packet_type {
|
|
||||||
PacketType::RegisterSuperACK => {
|
|
||||||
edge.send_register_super_feedback(
|
|
||||||
msg._packet_id,
|
|
||||||
RegisterSuperFeedback {
|
|
||||||
result: 0,
|
|
||||||
message: "".to_owned(),
|
|
||||||
should_exit: false,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let Ok(ack) = SdlRegisterSuperAck::decode(&msg.current_packet[..]) else {
|
|
||||||
error!("failed to decode REGISTER_SUPER_ACK");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
debug!("got register super ack: {:?}", ack);
|
|
||||||
let Ok(aes) = rsa_decrypt(&edge.rsa_private, &ack.aes_key) else {
|
|
||||||
error!("failed to rsa decrypt aes key");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let Some(dev) = ack.dev_addr else {
|
|
||||||
error!("no dev_addr is specified");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let ip = ip_to_string(&dev.net_addr);
|
|
||||||
debug!("aes key is {:?}, ip is {}/{}", aes, ip, dev.net_bit_len,);
|
|
||||||
edge.device_config
|
|
||||||
.ip
|
|
||||||
.net_addr
|
|
||||||
.store(dev.net_addr, Ordering::Relaxed);
|
|
||||||
edge.device_config
|
|
||||||
.ip
|
|
||||||
.net_bit_len
|
|
||||||
.store(dev.net_bit_len as u8, Ordering::Relaxed);
|
|
||||||
edge.device.reload_config(&edge.device_config);
|
|
||||||
edge.network_id.store(dev.network_id, Ordering::Relaxed);
|
|
||||||
|
|
||||||
edge.set_authorized(true, aes);
|
|
||||||
send_stun_request(edge).await;
|
|
||||||
tokio::spawn(async {
|
|
||||||
let nattype = edge.probe_nat_type().await;
|
|
||||||
println!("nat type is: {:?}", nattype);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
PacketType::RegisterSuperNAK => {
|
|
||||||
let Ok(_nak) = SdlRegisterSuperNak::decode(&msg.current_packet[..]) else {
|
|
||||||
error!("failed to decode REGISTER_SUPER_NAK");
|
|
||||||
edge.send_register_super_feedback(
|
|
||||||
msg._packet_id,
|
|
||||||
RegisterSuperFeedback {
|
|
||||||
result: 1,
|
|
||||||
message: "failed to decode REGISTER SUPER NAK".to_owned(),
|
|
||||||
should_exit: false,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Ok(error_code) = NakMsgCode::try_from(_nak.error_code as u8) else {
|
|
||||||
edge.send_register_super_feedback(
|
|
||||||
msg._packet_id,
|
|
||||||
RegisterSuperFeedback {
|
|
||||||
result: 2,
|
|
||||||
message: "error_code not recognized".to_owned(),
|
|
||||||
should_exit: false,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
match error_code {
|
|
||||||
NakMsgCode::InvalidToken => {
|
|
||||||
edge.send_register_super_feedback(
|
|
||||||
msg._packet_id,
|
|
||||||
RegisterSuperFeedback {
|
|
||||||
result: 3,
|
|
||||||
message: "invalid token".to_owned(),
|
|
||||||
should_exit: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
edge.stop().await;
|
|
||||||
}
|
|
||||||
NakMsgCode::NodeDisabled => {
|
|
||||||
edge.send_register_super_feedback(
|
|
||||||
msg._packet_id,
|
|
||||||
RegisterSuperFeedback {
|
|
||||||
result: 4,
|
|
||||||
message: "Node is disabled".to_owned(),
|
|
||||||
should_exit: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
edge.stop().await;
|
|
||||||
}
|
|
||||||
_other => {
|
|
||||||
edge.send_register_super_feedback(
|
|
||||||
msg._packet_id,
|
|
||||||
RegisterSuperFeedback {
|
|
||||||
result: 0,
|
|
||||||
message: "".to_owned(),
|
|
||||||
should_exit: false,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
edge.send_register_super_feedback(msg._packet_id, RegisterSuperFeedback {
|
|
||||||
result: 1,
|
|
||||||
message: "failed to decode REGISTER SUPER NAK".to_owned(),
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
edge.set_authorized(false, Vec::new());
|
|
||||||
// std::process::exit(0);
|
|
||||||
}
|
|
||||||
PacketType::Command => {
|
|
||||||
if msg.current_packet.len() < 1 {
|
|
||||||
error!("malformed COMMAND received");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
handle_tcp_command(edge, msg.current_packet[0], &msg.current_packet[1..]).await;
|
|
||||||
}
|
|
||||||
PacketType::Event => {
|
|
||||||
if msg.current_packet.len() < 1 {
|
|
||||||
error!("malformed EVENT received");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let Ok(event) = msg.current_packet[0].try_into() else {
|
|
||||||
error!("failed to parse event type");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
handle_tcp_event(edge, event, &msg.current_packet[1..]).await;
|
|
||||||
}
|
|
||||||
PacketType::PeerInfo => {
|
|
||||||
let _ = packet::handle_packet_peer_info(edge, &msg.current_packet[..]).await;
|
|
||||||
}
|
|
||||||
PacketType::Pong => {
|
|
||||||
debug!("tcp pong received");
|
|
||||||
let now = get_current_timestamp();
|
|
||||||
edge.tcp_pong.store(now, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
other => {
|
|
||||||
debug!("tcp not handling {:?}", other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_tcp_command(_edge: &Node, _cmdtype: u8, _cmdprotobuf: &[u8]) {}
|
|
||||||
|
|
||||||
async fn handle_tcp_event(edge: &Node, eventtype: EventType, eventprotobuf: &[u8]) {
|
|
||||||
match eventtype {
|
|
||||||
EventType::SendRegister => {
|
|
||||||
let Ok(reg) = SdlSendRegisterEvent::decode(eventprotobuf) else {
|
|
||||||
error!("failed to decode SendRegister Event");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let v4 = reg.nat_ip.to_be_bytes();
|
|
||||||
let mut v6_sock = None;
|
|
||||||
if let Some(v6_info) = reg.v6_info {
|
|
||||||
if let Ok(v6_bytes) = v6_info.v6.try_into() {
|
|
||||||
v6_sock = Some(V6Info {
|
|
||||||
port: v6_info.port as u16,
|
|
||||||
v6: v6_bytes,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
check_peer_registration_needed(
|
|
||||||
edge,
|
|
||||||
true,
|
|
||||||
reg.dst_ip,
|
|
||||||
// &v6_sock,
|
|
||||||
&v6_sock,
|
|
||||||
&SdlanSock {
|
|
||||||
family: AF_INET,
|
|
||||||
port: reg.nat_port as u16,
|
|
||||||
v4,
|
|
||||||
v6: [0; 16],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
other => {
|
|
||||||
debug!("unhandled event {:?}", other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn async_main(
|
pub async fn async_main(
|
||||||
install_channel: String,
|
|
||||||
args: CommandLine,
|
args: CommandLine,
|
||||||
start_stop_chan: Receiver<StartStopInfo>,
|
start_stop_chan: Receiver<StartStopInfo>,
|
||||||
cancel: CancellationToken,
|
cancel: CancellationToken,
|
||||||
connecting_chan: Option<Sender<ConnectionState>>,
|
connecting_chan: Option<Sender<ConnectionInfo>>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// let _ = PidRecorder::new(".pid");
|
// let _ = PidRecorder::new(".pid");
|
||||||
|
|
||||||
// // gen public key
|
|
||||||
// gen_rsa_keys(".client");
|
|
||||||
// let mut pubkey = String::new();
|
|
||||||
// File::open(".client/id_rsa.pub")?.read_to_string(&mut pubkey)?;
|
|
||||||
// let privatekey = load_private_key_file(".client/id_rsa")?;
|
|
||||||
|
|
||||||
// // init sock
|
|
||||||
// if args.token.len() == 0 {
|
|
||||||
// println!("failed to load token");
|
|
||||||
// return Ok(());
|
|
||||||
// }
|
|
||||||
// let sock_v4 = Socket::build(0, true, true, args.tos).await?;
|
|
||||||
|
|
||||||
// // allow multicast
|
|
||||||
|
|
||||||
// // TODO: set the sn's tcp socket
|
|
||||||
// // let tcpsock = TCPSocket::build("121.4.79.234:1234").await?;
|
|
||||||
// let tcp_pong = Arc::new(AtomicU64::new(0));
|
|
||||||
// let edge = Node::new(
|
|
||||||
// pubkey,
|
|
||||||
// node_conf,
|
|
||||||
// sock_v4,
|
|
||||||
// &args.token,
|
|
||||||
// privatekey,
|
|
||||||
// tcp_pong.clone(),
|
|
||||||
// );
|
|
||||||
|
|
||||||
let edge = get_edge();
|
let edge = get_edge();
|
||||||
|
|
||||||
// let token = args.token.clone();
|
// let token = args.token.clone();
|
||||||
@ -266,56 +38,7 @@ pub async fn async_main(
|
|||||||
init_tcp_conn(
|
init_tcp_conn(
|
||||||
cancel_tcp,
|
cancel_tcp,
|
||||||
&args.tcp,
|
&args.tcp,
|
||||||
move |stream, pkt_id| {
|
// |msg| handle_tcp_message(msg),
|
||||||
let installed_channel = install_channel.to_owned();
|
|
||||||
Box::pin(async move {
|
|
||||||
let token = edge._token.lock().unwrap().clone();
|
|
||||||
// let edge = get_edge();
|
|
||||||
// let edge = get_edge();
|
|
||||||
// let token = args.token.clone();
|
|
||||||
if let Ok(ipaddr) = stream.local_addr() {
|
|
||||||
match ipaddr.ip() {
|
|
||||||
IpAddr::V4(v4) => {
|
|
||||||
let ip = v4.into();
|
|
||||||
// println!("outer ip is {} => {}", v4, ip);
|
|
||||||
edge.outer_ip_v4.store(ip, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
_other => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let register_super = SdlRegisterSuper {
|
|
||||||
version: 1,
|
|
||||||
installed_channel,
|
|
||||||
client_id: edge.config.node_uuid.clone(),
|
|
||||||
dev_addr: Some(SdlDevAddr {
|
|
||||||
net_addr: 0,
|
|
||||||
network_id: 0,
|
|
||||||
net_bit_len: 0,
|
|
||||||
}),
|
|
||||||
pub_key: edge.rsa_pubkey.clone(),
|
|
||||||
token,
|
|
||||||
};
|
|
||||||
// debug!("send register super: {:?}", register_super);
|
|
||||||
let packet_id = match pkt_id {
|
|
||||||
Some(id) => id,
|
|
||||||
None => edge.get_next_packet_id(),
|
|
||||||
};
|
|
||||||
// let packet_id = edge.get_next_packet_id();
|
|
||||||
let data = encode_to_tcp_message(
|
|
||||||
Some(register_super),
|
|
||||||
packet_id,
|
|
||||||
PacketType::RegisterSuper as u8,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
if let Err(e) = stream.write(&data).await {
|
|
||||||
error!("failed to write to tcp: {}", e.to_string());
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|| async {
|
|
||||||
edge.set_authorized(false, vec![]);
|
|
||||||
},
|
|
||||||
|msg| handle_tcp_message(msg),
|
|
||||||
edge.tcp_pong.clone(),
|
edge.tcp_pong.clone(),
|
||||||
// tcp_pong,
|
// tcp_pong,
|
||||||
start_stop_chan,
|
start_stop_chan,
|
||||||
@ -404,9 +127,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;
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -416,36 +139,7 @@ async fn run_edge_loop(eee: &'static Node, cancel: CancellationToken) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_stun_request(eee: &Node) {
|
pub async fn loop_socket_v6(eee: &'static Node, socket: Arc<Socket>, cancel: CancellationToken) {
|
||||||
let sdl_v6_info = match *eee.ipv6.read().unwrap() {
|
|
||||||
Some(ref l) => Some(Sdlv6Info {
|
|
||||||
port: l.port as u32,
|
|
||||||
v6: Vec::from(l.v6),
|
|
||||||
}),
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
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: eee.get_nat_type() as u32,
|
|
||||||
v6_info: sdl_v6_info,
|
|
||||||
};
|
|
||||||
debug!("stun request: {:?}", req);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn loop_socket_v6(eee: &Node, socket: Arc<Socket>, cancel: CancellationToken) {
|
|
||||||
debug!("loop sock v6");
|
debug!("loop sock v6");
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
@ -473,40 +167,52 @@ 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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn receive_dns_reply(sock: &Arc<UdpSocket>) -> Option<Vec<u8>> {
|
||||||
|
let mut reply = vec![0;1024];
|
||||||
|
if let Ok((size, _from)) = sock.recv_from(&mut reply).await {
|
||||||
|
if size == 0 {
|
||||||
|
// closed
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
reply.truncate(size);
|
||||||
|
return Some(reply);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
async fn loop_tap(eee: &'static Node, cancel: CancellationToken) {
|
async fn loop_tap(eee: &'static Node, cancel: CancellationToken) {
|
||||||
debug!("loop tap");
|
debug!("loop tap");
|
||||||
let (tx, mut rx) = channel(10);
|
let (tx, mut rx) = channel(10);
|
||||||
@ -520,6 +226,26 @@ async fn loop_tap(eee: &'static Node, cancel: CancellationToken) {
|
|||||||
drop(rx);
|
drop(rx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
reply = receive_dns_reply(&eee.udp_sock_for_dns) => {
|
||||||
|
if reply.is_none() {
|
||||||
|
drop(rx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let reply = reply.unwrap();
|
||||||
|
let dstmac = eee.device_config.get_mac();
|
||||||
|
let srcmac = eee.device_config.dns_mac;
|
||||||
|
let mut packet = Vec::with_capacity(14+reply.len());
|
||||||
|
packet.extend_from_slice(&dstmac);
|
||||||
|
packet.extend_from_slice(&srcmac);
|
||||||
|
packet.push(0x08);
|
||||||
|
packet.push(0x00);
|
||||||
|
packet.extend_from_slice(&reply);
|
||||||
|
|
||||||
|
/// TODO: check the packet should
|
||||||
|
if let Err(_e) = eee.device.handle_packet_from_net(&packet, &Vec::new()).await {
|
||||||
|
error!("failed to write dns packet to device");
|
||||||
|
}
|
||||||
|
}
|
||||||
buf = rx.recv() => {
|
buf = rx.recv() => {
|
||||||
if buf.is_none() {
|
if buf.is_none() {
|
||||||
break;
|
break;
|
||||||
@ -534,7 +260,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 +295,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 +331,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 +341,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);
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/network/device.rs
Normal file → Executable file
26
src/network/device.rs
Normal file → Executable file
@ -1,13 +1,30 @@
|
|||||||
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,
|
||||||
|
|
||||||
|
pub dns_mac: Mac,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeviceConfig {
|
impl DeviceConfig {
|
||||||
pub fn new() -> Self {
|
pub fn new(mtu: u32) -> Self {
|
||||||
|
let mac = generate_mac_address();
|
||||||
|
let dns_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),
|
||||||
|
dns_mac,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,6 +45,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.
|
||||||
|
|||||||
26
src/network/ipv6.rs
Normal file → Executable file
26
src/network/ipv6.rs
Normal file → Executable file
@ -1,13 +1,15 @@
|
|||||||
use std::{net::{IpAddr, Ipv6Addr}, time::Duration};
|
use std::{
|
||||||
use std::sync::Mutex;
|
net::{IpAddr, Ipv6Addr},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
use sdlan_sn_rs::{config::AF_INET6, peer::SdlanSock};
|
use sdlan_sn_rs::{config::AF_INET6, peer::SdlanSock};
|
||||||
use tokio::{net::UdpSocket, sync::mpsc::Receiver};
|
use std::sync::Arc;
|
||||||
|
use tokio::{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 +17,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 +44,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 +74,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/network/mod.rs
Normal file → Executable file
14
src/network/mod.rs
Normal file → Executable file
@ -9,10 +9,20 @@ 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::*;
|
||||||
|
|
||||||
|
pub const DNS_IP: u32 = (100<<24) + (100<<16) + (100<<8) + 100;
|
||||||
|
|
||||||
#[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, restore_dns};
|
||||||
|
|
||||||
mod device;
|
mod device;
|
||||||
|
|
||||||
|
|||||||
185
src/network/node.rs
Normal file → Executable file
185
src/network/node.rs
Normal file → Executable file
@ -1,7 +1,7 @@
|
|||||||
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 tokio::net::UdpSocket;
|
||||||
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,15 +9,16 @@ 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::{ConnectionInfo, get_base_dir};
|
||||||
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,
|
||||||
};
|
};
|
||||||
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::{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,36 +26,49 @@ 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::{Mac, gen_rsa_keys, load_private_key_file, save_to_file};
|
||||||
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,
|
||||||
|
connecting_chan: Option<Sender<ConnectionInfo>>,
|
||||||
|
udpsock_for_dns: Arc<UdpSocket>,
|
||||||
|
hostname: String,
|
||||||
|
server_ip: String,
|
||||||
|
install_channel: String
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let _ = PidRecorder::new(".pid");
|
|
||||||
|
|
||||||
// gen public key
|
// gen public key
|
||||||
gen_rsa_keys(".client");
|
let rsa_path = format!("{}/.client", get_base_dir());
|
||||||
|
gen_rsa_keys(&rsa_path);
|
||||||
let mut pubkey = String::new();
|
let mut pubkey = String::new();
|
||||||
|
|
||||||
File::open(".client/id_rsa.pub")
|
// File::open(".client/id_rsa.pub")
|
||||||
|
File::open(&format!("{}/id_rsa.pub", rsa_path))
|
||||||
.await?
|
.await?
|
||||||
.read_to_string(&mut pubkey)
|
.read_to_string(&mut pubkey)
|
||||||
.await?;
|
.await?;
|
||||||
let privatekey = load_private_key_file(".client/id_rsa")?;
|
let privatekey = load_private_key_file(&format!("{}/id_rsa", rsa_path))?;
|
||||||
|
|
||||||
// init sock
|
// init sock
|
||||||
// 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 +80,16 @@ 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,
|
||||||
|
connecting_chan,
|
||||||
|
hostname,
|
||||||
|
udpsock_for_dns,
|
||||||
|
server_ip,
|
||||||
|
install_channel,
|
||||||
);
|
);
|
||||||
do_init_edge(edge)?;
|
do_init_edge(edge)?;
|
||||||
|
|
||||||
@ -107,12 +128,19 @@ pub struct Node {
|
|||||||
|
|
||||||
pub network_id: AtomicU32,
|
pub network_id: AtomicU32,
|
||||||
|
|
||||||
|
pub hostname: RwLock<String>,
|
||||||
|
|
||||||
|
pub udp_sock_for_dns: Arc<UdpSocket>,
|
||||||
|
pub server_ip: String,
|
||||||
|
|
||||||
pub tcp_pong: Arc<AtomicU64>,
|
pub tcp_pong: Arc<AtomicU64>,
|
||||||
|
|
||||||
start_stop_sender: Sender<StartStopInfo>,
|
start_stop_sender: Sender<StartStopInfo>,
|
||||||
|
pub connection_chan: Option<Sender<ConnectionInfo>>,
|
||||||
|
|
||||||
// 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 +162,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>>>,
|
||||||
@ -149,6 +177,8 @@ pub struct Node {
|
|||||||
// last register super time, in unix
|
// last register super time, in unix
|
||||||
pub _last_register_req: AtomicU64,
|
pub _last_register_req: AtomicU64,
|
||||||
|
|
||||||
|
pub install_channel: String,
|
||||||
|
|
||||||
nat_type: Mutex<NatType>,
|
nat_type: Mutex<NatType>,
|
||||||
|
|
||||||
nat_cookie: AtomicU32,
|
nat_cookie: AtomicU32,
|
||||||
@ -175,8 +205,14 @@ impl Node {
|
|||||||
self.nat_type.lock().unwrap().clone()
|
self.nat_type.lock().unwrap().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start_without_feedback(&self, token: String) -> Result<()> {
|
pub async fn start_without_feedback(&self, token: String, network_code: String, hostname: Option<String>) -> Result<()> {
|
||||||
|
if let Some(host) = hostname {
|
||||||
|
let idfile = format!("{}/.host", get_base_dir());
|
||||||
|
let _ = save_to_file(&idfile, &host);
|
||||||
|
*self.hostname.write().unwrap() = host;
|
||||||
|
}
|
||||||
*self._token.lock().unwrap() = token;
|
*self._token.lock().unwrap() = token;
|
||||||
|
*self.network_code.lock().unwrap() = network_code;
|
||||||
let _ = self
|
let _ = self
|
||||||
.start_stop_sender
|
.start_stop_sender
|
||||||
.send(StartStopInfo {
|
.send(StartStopInfo {
|
||||||
@ -190,9 +226,17 @@ impl Node {
|
|||||||
pub async fn start_with_feedback(
|
pub async fn start_with_feedback(
|
||||||
&self,
|
&self,
|
||||||
token: String,
|
token: String,
|
||||||
|
network_code: String,
|
||||||
|
hostname: Option<String>,
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
) -> Result<RegisterSuperFeedback> {
|
) -> Result<RegisterSuperFeedback> {
|
||||||
|
if let Some(host) = hostname {
|
||||||
|
let idfile = format!("{}/.host", get_base_dir());
|
||||||
|
let _ = save_to_file(&idfile, &host);
|
||||||
|
*self.hostname.write().unwrap() = host;
|
||||||
|
}
|
||||||
*self._token.lock().unwrap() = token;
|
*self._token.lock().unwrap() = token;
|
||||||
|
*self.network_code.lock().unwrap() = network_code;
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
let id = self.get_next_packet_id();
|
let id = self.get_next_packet_id();
|
||||||
self.packet_id_match.insert(id, tx);
|
self.packet_id_match.insert(id, tx);
|
||||||
@ -203,6 +247,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,26 +279,45 @@ 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,
|
||||||
|
connecting_chan: Option<Sender<ConnectionInfo>>,
|
||||||
|
hostname: String,
|
||||||
|
udpsock_for_dns: Arc<UdpSocket>,
|
||||||
|
server_ip: String,
|
||||||
|
install_channel: String,
|
||||||
) -> 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),
|
||||||
|
hostname: RwLock::new(hostname),
|
||||||
|
|
||||||
|
udp_sock_for_dns: udpsock_for_dns,
|
||||||
|
|
||||||
_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,
|
||||||
|
connection_chan: connecting_chan,
|
||||||
|
|
||||||
tcp_pong,
|
tcp_pong,
|
||||||
|
|
||||||
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())),
|
||||||
@ -287,6 +351,8 @@ impl Node {
|
|||||||
packet_id_match: DashMap::new(),
|
packet_id_match: DashMap::new(),
|
||||||
nat_cookie: AtomicU32::new(1),
|
nat_cookie: AtomicU32::new(1),
|
||||||
cookie_match: DashMap::new(),
|
cookie_match: DashMap::new(),
|
||||||
|
server_ip,
|
||||||
|
install_channel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,6 +432,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 +452,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
|
||||||
@ -428,7 +501,7 @@ impl Node {
|
|||||||
encode_to_tcp_message::<SdlEmpty>(None, 0, PacketType::UnRegisterSuper as u8).unwrap();
|
encode_to_tcp_message::<SdlEmpty>(None, 0, PacketType::UnRegisterSuper as u8).unwrap();
|
||||||
|
|
||||||
let conn = get_tcp_conn();
|
let conn = get_tcp_conn();
|
||||||
let _ = conn.send(&content).await;
|
let _ = conn.send(content).await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -443,6 +516,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 +547,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 +558,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 +623,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 +663,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 +691,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 +708,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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
621
src/network/packet.rs
Normal file → Executable file
621
src/network/packet.rs
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
127
src/network/route.rs
Executable file
127
src/network/route.rs
Executable 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
|
||||||
|
}
|
||||||
679
src/network/tun_linux.rs
Normal file → Executable file
679
src/network/tun_linux.rs
Normal file → Executable file
@ -1,18 +1,37 @@
|
|||||||
use sdlan_sn_rs::utils::{ip_to_string, net_bit_len_to_mask, SDLanError};
|
use etherparse::{Ethernet2Header};
|
||||||
|
use sdlan_sn_rs::config::SDLAN_DEFAULT_TTL;
|
||||||
|
use sdlan_sn_rs::utils::{
|
||||||
|
aes_encrypt, ip_to_string, is_ipv6_multicast, net_bit_len_to_mask,
|
||||||
|
SDLanError,
|
||||||
|
};
|
||||||
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::{self, OpenOptions};
|
||||||
|
use std::os::unix::fs::{MetadataExt, PermissionsExt};
|
||||||
|
use std::path::Path;
|
||||||
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::{BufRead, BufReader, 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::send_packet_to_net;
|
||||||
|
use crate::pb::{encode_to_udp_message, SdlData};
|
||||||
|
use crate::tcp::PacketType;
|
||||||
|
|
||||||
use super::device::{DeviceConfig, Mode};
|
use super::device::{DeviceConfig, Mode};
|
||||||
|
use super::TunTapPacketHandler;
|
||||||
|
|
||||||
|
const RESOLV_FILE: &'static str = "/etc/resolv.conf";
|
||||||
|
const RESOLV_FILE_BACKUP: &'static str = "/etc/resolv.conf.punchnet.bak";
|
||||||
|
use crate::network::DNS_IP;
|
||||||
|
|
||||||
|
// #[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;
|
||||||
@ -23,6 +42,7 @@ pub struct Iface {
|
|||||||
fd: std::fs::File,
|
fd: std::fs::File,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
name: String,
|
name: String,
|
||||||
|
has_resolvectl: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_iface(tunname: &str, mode: Mode) -> Iface {
|
pub fn new_iface(tunname: &str, mode: Mode) -> Iface {
|
||||||
@ -57,7 +77,7 @@ impl Iface {
|
|||||||
let mut success = false;
|
let mut success = false;
|
||||||
let mut _name = Vec::new();
|
let mut _name = Vec::new();
|
||||||
for i in 0..16 {
|
for i in 0..16 {
|
||||||
_name = Vec::new();
|
_name.clear();
|
||||||
_name.extend_from_slice(ifname.as_bytes());
|
_name.extend_from_slice(ifname.as_bytes());
|
||||||
_name.extend_from_slice(i.to_string().as_bytes());
|
_name.extend_from_slice(i.to_string().as_bytes());
|
||||||
_name.extend_from_slice(&[0; 33]);
|
_name.extend_from_slice(&[0; 33]);
|
||||||
@ -83,27 +103,46 @@ impl Iface {
|
|||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.into_owned()
|
.into_owned()
|
||||||
};
|
};
|
||||||
Ok(Iface { fd: fs, mode, name })
|
let has_resolvectl = check_has_resolvectl();
|
||||||
|
|
||||||
|
Ok(Iface { fd: fs, mode, name, has_resolvectl })
|
||||||
} else {
|
} else {
|
||||||
Err(SDLanError::NormalError("failed to setup tun"))
|
Err(SDLanError::NormalError("failed to setup tun"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reload_config(&self, device_config: &DeviceConfig) {
|
pub fn reload_config(&self, device_config: &DeviceConfig, network_domain: &str) {
|
||||||
let netbit = device_config.get_net_bit();
|
let netbit = device_config.get_net_bit();
|
||||||
let ip = device_config.get_ip();
|
let ip = device_config.get_ip();
|
||||||
if netbit == 0 || ip == 0 {
|
if netbit == 0 || ip == 0 {
|
||||||
error!("reload config's ip is 0");
|
error!("reload config's ip is 0");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let mask = net_bit_len_to_mask(netbit);
|
||||||
|
let mut default_gw = (ip & mask) + 1;
|
||||||
|
if default_gw == ip {
|
||||||
|
default_gw += 1;
|
||||||
|
}
|
||||||
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 +153,34 @@ impl Iface {
|
|||||||
error!("failed to run ifconfig: {}", e.to_string());
|
error!("failed to run ifconfig: {}", e.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Err(e) = set_dns(self, &self.name, network_domain, &ip_to_string(&default_gw)) {
|
||||||
|
error!("failed to set dns: {}", e.as_str());
|
||||||
|
}
|
||||||
|
} 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = set_dns(self, &self.name, network_domain, &ip_to_string(&default_gw)) {
|
||||||
|
error!("failed to set dns: {}", e.as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recv(&self, buf: &mut [u8]) -> std::io::Result<usize> {
|
pub fn recv(&self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||||
@ -125,6 +192,604 @@ 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<()> {
|
||||||
|
use etherparse::PacketHeaders;
|
||||||
|
|
||||||
|
debug!("in tap mode2");
|
||||||
|
let edge = get_edge();
|
||||||
|
|
||||||
|
let Ok(headers) = PacketHeaders::from_ethernet_slice(&data) else {
|
||||||
|
error!("failed to parse packet");
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(eth) = headers.link {
|
||||||
|
if let Some(hdr) = eth.ethernet2() {
|
||||||
|
if let Some(ip) = headers.net {
|
||||||
|
match ip {
|
||||||
|
etherparse::NetHeaders::Ipv4(ipv4, _) => {
|
||||||
|
|
||||||
|
if u32::from_be_bytes(ipv4.destination) == DNS_IP {
|
||||||
|
// should send to dns
|
||||||
|
if let Err(e) = edge.udp_sock_for_dns.send_to(&data[14..], format!("{}:15353", edge.server_ip)).await {
|
||||||
|
error!("failed to send request to 15353: {}", e);
|
||||||
|
}
|
||||||
|
// edge.udp_sock_for_dns.send_to()
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_other => {
|
||||||
|
// just ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
} else {
|
||||||
|
println!("erro 2");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("erro 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
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)) => {
|
||||||
|
use etherparse::ether_type::ARP;
|
||||||
|
use sdlan_sn_rs::utils::is_multi_broadcast;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
use sdlan_sn_rs::utils::mac_to_string;
|
||||||
|
|
||||||
|
error!(
|
||||||
|
"packet to [{:?}] not direct to us",
|
||||||
|
mac_to_string(&hdr.destination)
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if hdr.ether_type == ARP {
|
||||||
|
use crate::network::ArpHdr;
|
||||||
|
|
||||||
|
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 {
|
||||||
|
use sdlan_sn_rs::utils::mac_to_string;
|
||||||
|
|
||||||
|
use crate::network::{ARP_REPLY, ArpRequestInfo, send_arp_request};
|
||||||
|
|
||||||
|
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 {
|
||||||
|
use crate::network::{ArpRequestInfo, arp_arrived, send_arp_request};
|
||||||
|
|
||||||
|
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 {
|
||||||
|
use etherparse::IpHeaders;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
use crate::network::{ArpRequestInfo, send_arp_request};
|
||||||
|
|
||||||
|
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 tun packet: {}", e);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_packet_from_device(
|
||||||
|
&self,
|
||||||
|
data: Vec<u8>,
|
||||||
|
encrypt_key: &[u8],
|
||||||
|
) -> std::io::Result<()> {
|
||||||
|
use etherparse::IpHeaders;
|
||||||
|
|
||||||
|
let eee = get_edge();
|
||||||
|
|
||||||
|
let src_mac = eee.device_config.get_mac();
|
||||||
|
|
||||||
|
match IpHeaders::from_slice(&data) {
|
||||||
|
Ok((iphdr, _payload)) => {
|
||||||
|
use crate::network::{ArpRequestInfo, ArpResponse, send_arp_request};
|
||||||
|
|
||||||
|
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(());
|
||||||
|
}
|
||||||
|
if dstip == DNS_IP {
|
||||||
|
// should do the dns request
|
||||||
|
// println!("request for dns");
|
||||||
|
let addr = format!("{}:15353", eee.server_ip);
|
||||||
|
// println!("send dns to {}", addr);
|
||||||
|
if let Err(e) = eee.udp_sock_for_dns.send_to(&data, &addr).await {
|
||||||
|
error!("failed to send request to 15353: {}", e);
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
match send_arp_request(ArpRequestInfo::Lookup { ip: dstip }).await {
|
||||||
|
ArpResponse::LookupResp {
|
||||||
|
mac,
|
||||||
|
ip,
|
||||||
|
do_arp_request,
|
||||||
|
} => {
|
||||||
|
use crate::utils::caculate_crc;
|
||||||
|
|
||||||
|
if do_arp_request {
|
||||||
|
use sdlan_sn_rs::utils::BROADCAST_MAC;
|
||||||
|
|
||||||
|
use crate::network::{add_to_arp_wait_list, generate_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(ðerheader.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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_has_resolvectl() -> bool {
|
||||||
|
let res = Command::new("resolvectl")
|
||||||
|
.arg("status")
|
||||||
|
.output();
|
||||||
|
if let Ok(_) = res {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_dns_route(gw: &str) -> Result<()>{
|
||||||
|
Command::new("route")
|
||||||
|
.arg("add")
|
||||||
|
.arg("-host")
|
||||||
|
.arg("100.100.100.100")
|
||||||
|
.arg("gw")
|
||||||
|
.arg(gw)
|
||||||
|
.output()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_resolvectl(
|
||||||
|
name: &str,
|
||||||
|
network_domain: &str,
|
||||||
|
) -> Result<()>{
|
||||||
|
Command::new("resolvectl")
|
||||||
|
.arg("dns")
|
||||||
|
.arg(name)
|
||||||
|
.arg("100.100.100.100")
|
||||||
|
.output()?;
|
||||||
|
|
||||||
|
Command::new("resolvectl")
|
||||||
|
.arg("domain")
|
||||||
|
.arg(name)
|
||||||
|
.arg(format!("~{}", network_domain))
|
||||||
|
.output()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_dns(
|
||||||
|
iface: &Iface,
|
||||||
|
name: &str,
|
||||||
|
network_domain: &str,
|
||||||
|
gw: &str
|
||||||
|
) -> Result<()> {
|
||||||
|
if iface.has_resolvectl {
|
||||||
|
add_resolvectl(name, network_domain)?;
|
||||||
|
} else {
|
||||||
|
backup_resolv_conf()?;
|
||||||
|
modify_resolv_conf(&vec!["100.100.100.100".to_owned()], network_domain, true)?;
|
||||||
|
}
|
||||||
|
add_dns_route(gw)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn restore_dns() -> Result<()> {
|
||||||
|
let eee = get_edge();
|
||||||
|
if !eee.device.has_resolvectl {
|
||||||
|
// should restore /etc/resolv.conf
|
||||||
|
restore_resolv_conf()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 修改 /etc/resolv.conf 中的 nameserver 条目
|
||||||
|
///
|
||||||
|
/// - `new_nameservers`: 新的 nameserver 列表(IPv4/IPv6 字符串)
|
||||||
|
/// - `keep_other_ns`: 是否保留原有的 nameserver(true = 追加到新列表后,false = 完全替换)
|
||||||
|
pub fn modify_resolv_conf(new_nameservers: &[String], search_domain: &str, keep_other_ns: bool) -> Result<()> {
|
||||||
|
let path = Path::new(RESOLV_FILE);
|
||||||
|
if !path.exists() {
|
||||||
|
return Err(SDLanError::IOError(format!("{} does not exists", RESOLV_FILE)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取原文件权限和元数据
|
||||||
|
let metadata = fs::metadata(path)?;
|
||||||
|
let perms = fs::Permissions::from_mode(metadata.mode());
|
||||||
|
let uid = metadata.uid();
|
||||||
|
let gid = metadata.gid();
|
||||||
|
|
||||||
|
// 读取所有行
|
||||||
|
let file = fs::File::open(path)?;
|
||||||
|
let reader = BufReader::new(file);
|
||||||
|
let mut lines = Vec::new();
|
||||||
|
|
||||||
|
let mut inserted = false;
|
||||||
|
let mut encounted_nameserver = false;
|
||||||
|
let mut search_added = false;
|
||||||
|
|
||||||
|
for line in reader.lines() {
|
||||||
|
let line = line?;
|
||||||
|
let trimmed = line.trim();
|
||||||
|
if trimmed.starts_with("nameserver ") {
|
||||||
|
// 提取 IP
|
||||||
|
encounted_nameserver = true;
|
||||||
|
if keep_other_ns {
|
||||||
|
lines.push(line);
|
||||||
|
}
|
||||||
|
// 如果不保留原有 nameserver,就不加入 lines
|
||||||
|
} else {
|
||||||
|
if encounted_nameserver {
|
||||||
|
if !inserted {
|
||||||
|
inserted = true;
|
||||||
|
for new in new_nameservers {
|
||||||
|
lines.push(format!("nameserver {}", new.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 保留非 nameserver 行(注释、search、options 等)
|
||||||
|
if trimmed.starts_with("search ") {
|
||||||
|
lines.push(format!("{} {}", trimmed, search_domain));
|
||||||
|
search_added = true;
|
||||||
|
} else {
|
||||||
|
lines.push(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !search_added {
|
||||||
|
lines.push(format!("search {}", search_domain));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 原子写入:先写临时文件
|
||||||
|
let tmp_dir = Path::new("/etc");
|
||||||
|
let tmp_path = tmp_dir.join("resolv.conf.tmp");
|
||||||
|
let mut tmp_file = fs::File::create(&tmp_path)?;
|
||||||
|
for l in &lines {
|
||||||
|
writeln!(tmp_file, "{}", l)?;
|
||||||
|
}
|
||||||
|
tmp_file.flush()?;
|
||||||
|
|
||||||
|
// 设置权限
|
||||||
|
fs::set_permissions(&tmp_path, perms)?;
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
use std::os::unix::fs::chown;
|
||||||
|
chown(&tmp_path, Some(uid), Some(gid))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 原子替换
|
||||||
|
fs::rename(&tmp_path, path)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 备份 /etc/resolv.conf 到指定路径
|
||||||
|
fn backup_resolv_conf() -> Result<()> {
|
||||||
|
let src = Path::new(RESOLV_FILE);
|
||||||
|
let dst = Path::new(RESOLV_FILE_BACKUP);
|
||||||
|
|
||||||
|
if !src.exists() {
|
||||||
|
return Err(SDLanError::IOError(format!("{} does not exists", RESOLV_FILE)));
|
||||||
|
// anyhow::bail!("Source /etc/resolv.conf does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果目标已存在,可选择覆盖或跳过(这里覆盖)
|
||||||
|
if dst.exists() {
|
||||||
|
fs::remove_file(dst)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::copy(src, dst)?;
|
||||||
|
|
||||||
|
// 保留原权限
|
||||||
|
let metadata = fs::metadata(src)?;
|
||||||
|
let permissions = fs::Permissions::from_mode(metadata.mode());
|
||||||
|
fs::set_permissions(dst, permissions)?;
|
||||||
|
|
||||||
|
// 保留所有者(需要 root 权限,否则会失败)
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
use std::os::unix::fs::chown;
|
||||||
|
let uid = metadata.uid();
|
||||||
|
let gid = metadata.gid();
|
||||||
|
chown(dst, Some(uid), Some(gid))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 从备份路径恢复 /etc/resolv.conf
|
||||||
|
fn restore_resolv_conf() -> Result<()> {
|
||||||
|
let src = Path::new(RESOLV_FILE_BACKUP);
|
||||||
|
let dst = Path::new(RESOLV_FILE);
|
||||||
|
|
||||||
|
if !src.exists() {
|
||||||
|
return Err(SDLanError::IOError(format!("{} does not exists", RESOLV_FILE_BACKUP)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果目标是符号链接,先删除链接再复制(避免写入到链接指向位置)
|
||||||
|
if dst.is_symlink() {
|
||||||
|
fs::remove_file(dst)?;
|
||||||
|
} else if dst.exists() {
|
||||||
|
fs::remove_file(dst)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::copy(src, dst)?;
|
||||||
|
|
||||||
|
// 保留备份文件的权限
|
||||||
|
let metadata = fs::metadata(src)?;
|
||||||
|
let permissions = fs::Permissions::from_mode(metadata.mode());
|
||||||
|
fs::set_permissions(dst, permissions)?;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
use std::os::unix::fs::chown;
|
||||||
|
let uid = metadata.uid();
|
||||||
|
let gid = metadata.gid();
|
||||||
|
chown(dst, Some(uid), Some(gid))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
381
src/network/tun_win.rs
Normal file → Executable file
381
src/network/tun_win.rs
Normal file → Executable file
@ -1,14 +1,30 @@
|
|||||||
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::{
|
||||||
|
ARP_REPLY, ARP_REQUEST, ArpHdr, ArpRequestInfo, ArpResponse, DNS_IP, add_to_arp_wait_list, arp_arrived, form_ethernet_packet, generate_arp_request, send_arp_request, send_packet_to_net
|
||||||
|
};
|
||||||
|
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 {
|
||||||
|
if_idx: u32,
|
||||||
name: String,
|
name: String,
|
||||||
_adapter: Arc<wintun::Adapter>,
|
_adapter: Arc<wintun::Adapter>,
|
||||||
session: Arc<wintun::Session>,
|
session: Arc<wintun::Session>,
|
||||||
@ -41,14 +57,21 @@ impl Iface {
|
|||||||
Ok(content.len())
|
Ok(content.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reload_config(&self, device_config: &DeviceConfig) {
|
pub fn reload_config(&self, device_config: &DeviceConfig, network_domain: &str) {
|
||||||
let netbit = device_config.get_net_bit();
|
let netbit = device_config.get_net_bit();
|
||||||
let ip = device_config.get_ip();
|
let ip = device_config.get_ip();
|
||||||
if netbit == 0 || ip == 0 {
|
if netbit == 0 || ip == 0 {
|
||||||
error!("reload config's ip is 0");
|
error!("reload config's ip is 0");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mask = net_bit_len_to_mask(netbit);
|
||||||
|
let mut default_gw = (ip & mask) + 1;
|
||||||
|
if default_gw == ip {
|
||||||
|
default_gw += 1;
|
||||||
|
}
|
||||||
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));
|
||||||
|
|
||||||
let mut cmd = Command::new("netsh");
|
let mut cmd = Command::new("netsh");
|
||||||
@ -74,6 +97,309 @@ 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let gw = ip_to_string(&default_gw);
|
||||||
|
println!("gw = {}", gw);
|
||||||
|
if let Err(e) = set_dns(&self.name, network_domain, &gw, self.if_idx) {
|
||||||
|
println!("failed to set dns: {:?}", e);
|
||||||
|
} else {
|
||||||
|
println!("set dns ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
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(());
|
||||||
|
}
|
||||||
|
if dstip == DNS_IP {
|
||||||
|
// println!("request for dns");
|
||||||
|
let addr = format!("{}:15353", eee.server_ip);
|
||||||
|
// println!("send dns to {}", addr);
|
||||||
|
if let Err(e) = eee.udp_sock_for_dns.send_to(&data, &addr).await {
|
||||||
|
error!("failed to send request to 15353: {}", e);
|
||||||
|
}
|
||||||
|
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(ðerheader.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(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,10 +409,17 @@ fn create_wintun(path: &str,name: &str) -> Iface {
|
|||||||
let adapter = match wintun::Adapter::open(&wt, name) {
|
let adapter = match wintun::Adapter::open(&wt, name) {
|
||||||
Ok(a) => a,
|
Ok(a) => a,
|
||||||
Err(_e) => wintun::Adapter::create(&wt, name, "Example", None)
|
Err(_e) => wintun::Adapter::create(&wt, name, "Example", None)
|
||||||
.expect("failed to create wintun adapter"),
|
.expect("failed to create tun adapter"),
|
||||||
};
|
};
|
||||||
|
let idx = adapter.get_adapter_index().expect("failed to get adapter index");
|
||||||
|
println!("idx = {}", idx);
|
||||||
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 {
|
||||||
|
if_idx: idx,
|
||||||
|
_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 {
|
||||||
@ -97,3 +430,39 @@ pub fn new_iface(name: &str, _mode: Mode) -> Iface {
|
|||||||
pub fn get_install_channel() -> String {
|
pub fn get_install_channel() -> String {
|
||||||
"windows".to_owned()
|
"windows".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_dns(name: &str, _network_domain: &str, gw: &str, ifidx: u32) -> std::io::Result<()>{
|
||||||
|
let res = Command::new("ROUTE")
|
||||||
|
.arg("ADD")
|
||||||
|
.arg("100.100.100.100")
|
||||||
|
.arg("MASK")
|
||||||
|
.arg("255.255.255.255")
|
||||||
|
.arg(gw)
|
||||||
|
.arg("IF")
|
||||||
|
.arg(ifidx.to_string())
|
||||||
|
.creation_flags(0x08000000)
|
||||||
|
.output()?;
|
||||||
|
|
||||||
|
println!("res1: {}", res.status.success());
|
||||||
|
|
||||||
|
println!("route set ok");
|
||||||
|
let res = Command::new("netsh")
|
||||||
|
.arg("dnsclient")
|
||||||
|
.arg("set")
|
||||||
|
.arg("dnsserver")
|
||||||
|
.arg(&format!("name={}", name))
|
||||||
|
.arg("source=static")
|
||||||
|
.arg("address=100.100.100.100")
|
||||||
|
.arg("validate=no")
|
||||||
|
.creation_flags(0x08000000)
|
||||||
|
.output()?;
|
||||||
|
println!("res2: {}", res.status.success());
|
||||||
|
|
||||||
|
println!("netsh set ok");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn restore_dns() {
|
||||||
|
|
||||||
|
}
|
||||||
0
src/network/tuntap.c
Normal file → Executable file
0
src/network/tuntap.c
Normal file → Executable file
122
src/network/tuntap.rs
Executable file
122
src/network/tuntap.rs
Executable file
@ -0,0 +1,122 @@
|
|||||||
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
|
use dashmap::DashMap;
|
||||||
|
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;
|
||||||
|
}
|
||||||
@ -23,10 +23,14 @@ 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,
|
||||||
|
#[prost(string, tag = "5")]
|
||||||
|
pub network_domain: ::prost::alloc::string::String,
|
||||||
}
|
}
|
||||||
/// tcp通讯消息
|
/// tcp通讯消息
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
@ -47,6 +51,10 @@ 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,
|
||||||
|
#[prost(string, tag = "8")]
|
||||||
|
pub hostname: ::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 +63,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 +81,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 +96,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 +129,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 +161,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 +181,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 +197,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
0
src/pb/mod.rs
Normal file → Executable file
0
src/tcp/mod.rs
Normal file → Executable file
0
src/tcp/mod.rs
Normal file → Executable file
1
src/tcp/tcp_codec.rs
Normal file → Executable file
1
src/tcp/tcp_codec.rs
Normal file → Executable 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)]
|
||||||
|
|||||||
446
src/tcp/tcp_conn.rs
Normal file → Executable file
446
src/tcp/tcp_conn.rs
Normal file → Executable file
@ -1,6 +1,10 @@
|
|||||||
|
use myactor::{ActorError, SupervisedActor};
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use sdlan_sn_rs::utils::{get_current_timestamp, Result, SDLanError};
|
use prost::Message;
|
||||||
use std::future::Future;
|
use sdlan_sn_rs::config::AF_INET;
|
||||||
|
use sdlan_sn_rs::peer::{SdlanSock, V6Info};
|
||||||
|
use sdlan_sn_rs::utils::{Result, SDLanError, get_current_timestamp, ip_to_string, rsa_decrypt};
|
||||||
|
use std::net::IpAddr;
|
||||||
use std::sync::atomic::AtomicU64;
|
use std::sync::atomic::AtomicU64;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{
|
use std::{
|
||||||
@ -19,15 +23,325 @@ use tokio::{
|
|||||||
};
|
};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
use crate::config::TCP_PING_TIME;
|
use crate::config::{NULL_MAC, TCP_PING_TIME};
|
||||||
use crate::network::StartStopInfo;
|
use crate::network::{Node, RegisterSuperFeedback, StartStopInfo, check_peer_registration_needed, handle_packet_peer_info};
|
||||||
use crate::tcp::read_a_packet;
|
use crate::pb::{SdlDevAddr, SdlRegisterSuper, SdlRegisterSuperAck, SdlRegisterSuperNak, SdlSendRegisterEvent, SdlStunRequest, Sdlv6Info, encode_to_tcp_message, encode_to_udp_message};
|
||||||
use crate::ConnectionState;
|
use crate::tcp::{EventType, NakMsgCode, NatType, PacketType, read_a_packet};
|
||||||
|
use crate::utils::send_to_sock;
|
||||||
|
use crate::{ConnectionInfo, ConnectionState, get_edge};
|
||||||
|
|
||||||
use super::tcp_codec::SdlanTcp;
|
use super::tcp_codec::SdlanTcp;
|
||||||
|
|
||||||
static GLOBAL_TCP_HANDLE: OnceCell<ReadWriterHandle> = OnceCell::new();
|
static GLOBAL_TCP_HANDLE: OnceCell<ReadWriterHandle> = OnceCell::new();
|
||||||
|
|
||||||
|
|
||||||
|
async fn handle_tcp_message(msg: SdlanTcp) {
|
||||||
|
let edge = get_edge();
|
||||||
|
|
||||||
|
// let now = get_current_timestamp();
|
||||||
|
// edge.tcp_pong.store(now, Ordering::Relaxed);
|
||||||
|
|
||||||
|
debug!("got tcp message: {:?}", msg.packet_type);
|
||||||
|
match msg.packet_type {
|
||||||
|
PacketType::RegisterSuperACK => {
|
||||||
|
edge.send_register_super_feedback(
|
||||||
|
msg._packet_id,
|
||||||
|
RegisterSuperFeedback {
|
||||||
|
result: 0,
|
||||||
|
message: "".to_owned(),
|
||||||
|
should_exit: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let Ok(ack) = SdlRegisterSuperAck::decode(&msg.current_packet[..]) else {
|
||||||
|
error!("failed to decode REGISTER_SUPER_ACK");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
debug!("got register super ack: {:?}", ack);
|
||||||
|
let Ok(aes) = rsa_decrypt(&edge.rsa_private, &ack.aes_key) else {
|
||||||
|
error!("failed to rsa decrypt aes key");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(dev) = ack.dev_addr else {
|
||||||
|
error!("no dev_addr is specified");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let ip = ip_to_string(&dev.net_addr);
|
||||||
|
// debug!("aes key is {:?}, ip is {}/{}", aes, ip, dev.net_bit_len,);
|
||||||
|
println!("assigned ip: {}", ip);
|
||||||
|
let hostname = edge.hostname.read().unwrap().clone();
|
||||||
|
println!("network is: {}.{}", hostname, dev.network_domain);
|
||||||
|
edge.device_config
|
||||||
|
.ip
|
||||||
|
.net_addr
|
||||||
|
.store(dev.net_addr, Ordering::Relaxed);
|
||||||
|
if let Some(ref chan) = edge.connection_chan {
|
||||||
|
let _ = chan.send(ConnectionInfo::IPInfo(ip)).await;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
let mac = match dev.mac.try_into() {
|
||||||
|
Err(_) => NULL_MAC,
|
||||||
|
Ok(m) => m,
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
// *edge.device_config.mac.write().unwrap() = mac;
|
||||||
|
edge.device_config
|
||||||
|
.ip
|
||||||
|
.net_bit_len
|
||||||
|
.store(dev.net_bit_len as u8, Ordering::Relaxed);
|
||||||
|
edge.device.reload_config(&edge.device_config, &dev.network_domain);
|
||||||
|
edge.network_id.store(dev.network_id, Ordering::Relaxed);
|
||||||
|
|
||||||
|
edge.set_authorized(true, aes);
|
||||||
|
send_stun_request(edge).await;
|
||||||
|
tokio::spawn(async {
|
||||||
|
let nattype = edge.probe_nat_type().await;
|
||||||
|
debug!("nat type is {:?}", nattype);
|
||||||
|
// println!("nat type is: {:?}", nattype);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
PacketType::RegisterSuperNAK => {
|
||||||
|
let Ok(_nak) = SdlRegisterSuperNak::decode(&msg.current_packet[..]) else {
|
||||||
|
error!("failed to decode REGISTER_SUPER_NAK");
|
||||||
|
edge.send_register_super_feedback(
|
||||||
|
msg._packet_id,
|
||||||
|
RegisterSuperFeedback {
|
||||||
|
result: 1,
|
||||||
|
message: "failed to decode REGISTER SUPER NAK".to_owned(),
|
||||||
|
should_exit: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(error_code) = NakMsgCode::try_from(_nak.error_code as u8) else {
|
||||||
|
edge.send_register_super_feedback(
|
||||||
|
msg._packet_id,
|
||||||
|
RegisterSuperFeedback {
|
||||||
|
result: 2,
|
||||||
|
message: "error_code not recognized".to_owned(),
|
||||||
|
should_exit: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
match error_code {
|
||||||
|
NakMsgCode::InvalidToken => {
|
||||||
|
edge.send_register_super_feedback(
|
||||||
|
msg._packet_id,
|
||||||
|
RegisterSuperFeedback {
|
||||||
|
result: 3,
|
||||||
|
message: "invalid token".to_owned(),
|
||||||
|
should_exit: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
edge.stop().await;
|
||||||
|
}
|
||||||
|
NakMsgCode::NodeDisabled => {
|
||||||
|
edge.send_register_super_feedback(
|
||||||
|
msg._packet_id,
|
||||||
|
RegisterSuperFeedback {
|
||||||
|
result: 4,
|
||||||
|
message: "Node is disabled".to_owned(),
|
||||||
|
should_exit: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
edge.stop().await;
|
||||||
|
}
|
||||||
|
_other => {
|
||||||
|
edge.send_register_super_feedback(
|
||||||
|
msg._packet_id,
|
||||||
|
RegisterSuperFeedback {
|
||||||
|
result: 0,
|
||||||
|
message: "".to_owned(),
|
||||||
|
should_exit: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
edge.send_register_super_feedback(msg._packet_id, RegisterSuperFeedback {
|
||||||
|
result: 1,
|
||||||
|
message: "failed to decode REGISTER SUPER NAK".to_owned(),
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
edge.set_authorized(false, Vec::new());
|
||||||
|
// std::process::exit(0);
|
||||||
|
}
|
||||||
|
PacketType::Command => {
|
||||||
|
if msg.current_packet.len() < 1 {
|
||||||
|
error!("malformed COMMAND received");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handle_tcp_command(edge, msg.current_packet[0], &msg.current_packet[1..]).await;
|
||||||
|
}
|
||||||
|
PacketType::Event => {
|
||||||
|
if msg.current_packet.len() < 1 {
|
||||||
|
error!("malformed EVENT received");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let Ok(event) = msg.current_packet[0].try_into() else {
|
||||||
|
error!("failed to parse event type");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
handle_tcp_event(edge, event, &msg.current_packet[1..]).await;
|
||||||
|
}
|
||||||
|
PacketType::PeerInfo => {
|
||||||
|
let _ = handle_packet_peer_info(edge, &msg.current_packet[..]).await;
|
||||||
|
}
|
||||||
|
PacketType::Pong => {
|
||||||
|
debug!("tcp pong received");
|
||||||
|
let now = get_current_timestamp();
|
||||||
|
edge.tcp_pong.store(now, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
debug!("tcp not handling {:?}", other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_tcp_command(_edge: &Node, _cmdtype: u8, _cmdprotobuf: &[u8]) {}
|
||||||
|
|
||||||
|
async fn handle_tcp_event(edge: &'static Node, eventtype: EventType, eventprotobuf: &[u8]) {
|
||||||
|
match eventtype {
|
||||||
|
EventType::SendRegister => {
|
||||||
|
let Ok(reg) = SdlSendRegisterEvent::decode(eventprotobuf) else {
|
||||||
|
error!("failed to decode SendRegister Event");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let v4 = reg.nat_ip.to_be_bytes();
|
||||||
|
let mut v6_sock = None;
|
||||||
|
if let Some(v6_info) = reg.v6_info {
|
||||||
|
if let Ok(v6_bytes) = v6_info.v6.try_into() {
|
||||||
|
v6_sock = Some(V6Info {
|
||||||
|
port: v6_info.port as u16,
|
||||||
|
v6: v6_bytes,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(
|
||||||
|
edge,
|
||||||
|
false,
|
||||||
|
dst_mac,
|
||||||
|
// &v6_sock,
|
||||||
|
remote_nat,
|
||||||
|
&v6_sock,
|
||||||
|
&SdlanSock {
|
||||||
|
family: AF_INET,
|
||||||
|
port: reg.nat_port as u16,
|
||||||
|
v4,
|
||||||
|
v6: [0; 16],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
debug!("unhandled event {:?}", other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub async fn send_stun_request(eee: &Node) {
|
||||||
|
let sdl_v6_info = match *eee.ipv6.read().unwrap() {
|
||||||
|
Some(ref l) => Some(Sdlv6Info {
|
||||||
|
port: l.port as u32,
|
||||||
|
v6: Vec::from(l.v6),
|
||||||
|
}),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
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(),
|
||||||
|
mac: Vec::from(eee.device_config.get_mac()),
|
||||||
|
nat_type: eee.get_nat_type() as u32,
|
||||||
|
v6_info: sdl_v6_info,
|
||||||
|
};
|
||||||
|
debug!("stun request: {:?}", req);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_disconnected_callback() {
|
||||||
|
let edge = get_edge();
|
||||||
|
edge.set_authorized(false, vec![]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_connected_callback<'a>(stream: &'a mut tokio::net::TcpStream, pkt_id: Option<u32>) {
|
||||||
|
let edge = get_edge();
|
||||||
|
// let installed_channel = install_channel.to_owned();
|
||||||
|
|
||||||
|
let token = edge._token.lock().unwrap().clone();
|
||||||
|
let code = edge.network_code.lock().unwrap().clone();
|
||||||
|
// let edge = get_edge();
|
||||||
|
// let edge = get_edge();
|
||||||
|
// let token = args.token.clone();
|
||||||
|
if let Ok(ipaddr) = stream.local_addr() {
|
||||||
|
match ipaddr.ip() {
|
||||||
|
IpAddr::V4(v4) => {
|
||||||
|
let ip = v4.into();
|
||||||
|
// println!("outer ip is {} => {}", v4, ip);
|
||||||
|
edge.outer_ip_v4.store(ip, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
_other => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let register_super = SdlRegisterSuper {
|
||||||
|
version: 1,
|
||||||
|
installed_channel: edge.install_channel.clone(),
|
||||||
|
// installed_channel,
|
||||||
|
client_id: edge.config.node_uuid.clone(),
|
||||||
|
dev_addr: Some(SdlDevAddr {
|
||||||
|
mac: Vec::from(edge.device_config.get_mac()),
|
||||||
|
net_addr: 0,
|
||||||
|
network_id: 0,
|
||||||
|
net_bit_len: 0,
|
||||||
|
network_domain: "".to_owned(),
|
||||||
|
}),
|
||||||
|
pub_key: edge.rsa_pubkey.clone(),
|
||||||
|
token,
|
||||||
|
network_code: code,
|
||||||
|
hostname: edge.hostname.read().unwrap().clone(),
|
||||||
|
};
|
||||||
|
// debug!("send register super: {:?}", register_super);
|
||||||
|
let packet_id = match pkt_id {
|
||||||
|
Some(id) => id,
|
||||||
|
None => edge.get_next_packet_id(),
|
||||||
|
};
|
||||||
|
// let packet_id = edge.get_next_packet_id();
|
||||||
|
let data = encode_to_tcp_message(
|
||||||
|
Some(register_super),
|
||||||
|
packet_id,
|
||||||
|
PacketType::RegisterSuper as u8,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
if let Err(e) = stream.write(&data).await {
|
||||||
|
error!("failed to write to tcp: {}", e.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ReadWriteActor {
|
pub struct ReadWriteActor {
|
||||||
// actor接收的发送给tcp的接收端,由handle存放发送端
|
// actor接收的发送给tcp的接收端,由handle存放发送端
|
||||||
// to_tcp: Receiver<Vec<u8>>,
|
// to_tcp: Receiver<Vec<u8>>,
|
||||||
@ -36,8 +350,8 @@ pub struct ReadWriteActor {
|
|||||||
pong_time: Arc<AtomicU64>,
|
pong_time: Arc<AtomicU64>,
|
||||||
// actor收到数据之后,发送给上层的发送端口,接收端由handle保存
|
// actor收到数据之后,发送给上层的发送端口,接收端由handle保存
|
||||||
from_tcp: Sender<SdlanTcp>,
|
from_tcp: Sender<SdlanTcp>,
|
||||||
cancel: CancellationToken,
|
_cancel: CancellationToken,
|
||||||
connecting_chan: Option<Sender<ConnectionState>>,
|
connecting_chan: Option<Sender<ConnectionInfo>>,
|
||||||
ipv6_network_restarter: Option<Sender<bool>>,
|
ipv6_network_restarter: Option<Sender<bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,40 +362,33 @@ impl ReadWriteActor {
|
|||||||
from_tcp: Sender<SdlanTcp>,
|
from_tcp: Sender<SdlanTcp>,
|
||||||
connected: Arc<AtomicBool>,
|
connected: Arc<AtomicBool>,
|
||||||
pong_time: Arc<AtomicU64>,
|
pong_time: Arc<AtomicU64>,
|
||||||
connecting_chan: Option<Sender<ConnectionState>>,
|
connecting_chan: Option<Sender<ConnectionInfo>>,
|
||||||
ipv6_network_restarter: Option<Sender<bool>>,
|
ipv6_network_restarter: Option<Sender<bool>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
// to_tcp,
|
// to_tcp,
|
||||||
cancel,
|
_cancel: cancel,
|
||||||
pong_time,
|
pong_time,
|
||||||
connected,
|
connected,
|
||||||
remote: remote.to_owned(),
|
remote: remote.to_owned(),
|
||||||
from_tcp,
|
from_tcp,
|
||||||
connecting_chan,
|
connecting_chan,
|
||||||
ipv6_network_restarter
|
ipv6_network_restarter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run<'a, T, T2, F>(
|
pub async fn run<'a>(
|
||||||
&self,
|
&self,
|
||||||
keep_reconnect: bool,
|
keep_reconnect: bool,
|
||||||
mut to_tcp: Receiver<Vec<u8>>,
|
mut to_tcp: Receiver<Vec<u8>>,
|
||||||
on_connected: T,
|
|
||||||
on_disconnected: T2,
|
|
||||||
mut start_stop_chan: Receiver<StartStopInfo>,
|
mut start_stop_chan: Receiver<StartStopInfo>,
|
||||||
// cancel: CancellationToken,
|
) {
|
||||||
) where
|
|
||||||
T: for<'b> Fn(&'b mut TcpStream, Option<u32>) -> BoxFuture<'b, ()>,
|
|
||||||
T2: Fn() -> F,
|
|
||||||
F: Future<Output = ()>,
|
|
||||||
{
|
|
||||||
// let (tx, rx) = channel(20);
|
|
||||||
let mut started = false;
|
let mut started = false;
|
||||||
let mut start_pkt_id = None;
|
let mut start_pkt_id = None;
|
||||||
loop {
|
loop {
|
||||||
if let Some(ref connecting_chan) = self.connecting_chan {
|
if let Some(ref connecting_chan) = self.connecting_chan {
|
||||||
let _ = connecting_chan.send(ConnectionState::NotConnected).await;
|
let state = ConnectionInfo::ConnState(ConnectionState::NotConnected);
|
||||||
|
let _ = connecting_chan.send(state).await;
|
||||||
}
|
}
|
||||||
self.connected.store(false, Ordering::Relaxed);
|
self.connected.store(false, Ordering::Relaxed);
|
||||||
if !started {
|
if !started {
|
||||||
@ -112,34 +419,31 @@ impl ReadWriteActor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
debug!("start stop chan recv none");
|
debug!("start stop chan received: {}", started);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref connecting_chan) = self.connecting_chan {
|
if let Some(ref connecting_chan) = self.connecting_chan {
|
||||||
let _ = connecting_chan.send(ConnectionState::Connecting).await;
|
let state = ConnectionInfo::ConnState(ConnectionState::Connecting);
|
||||||
|
let _ = connecting_chan.send(state).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 {
|
||||||
/*
|
|
||||||
tokio::select! {
|
|
||||||
_ = tokio::time::sleep(Duration::from_secs(3)) => {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
tokio::time::sleep(Duration::from_secs(3)).await;
|
tokio::time::sleep(Duration::from_secs(3)).await;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
self.connected.store(true, Ordering::Relaxed);
|
self.connected.store(true, Ordering::Relaxed);
|
||||||
on_connected(&mut stream, start_pkt_id.take()).await;
|
debug!("connected");
|
||||||
|
on_connected_callback(&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 {
|
||||||
let _ = connecting_chan.send(ConnectionState::Connected).await;
|
let state = ConnectionInfo::ConnState(ConnectionState::Connected);
|
||||||
|
let _ = connecting_chan.send(state).await;
|
||||||
}
|
}
|
||||||
if let Some(ref ipv6_restarter) = self.ipv6_network_restarter {
|
if let Some(ref ipv6_restarter) = self.ipv6_network_restarter {
|
||||||
let _ = ipv6_restarter.send(true).await;
|
let _ = ipv6_restarter.send(true).await;
|
||||||
@ -204,7 +508,7 @@ impl ReadWriteActor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
other => {
|
_other => {
|
||||||
// send chan is closed;
|
// send chan is closed;
|
||||||
started = false;
|
started = false;
|
||||||
return;
|
return;
|
||||||
@ -221,7 +525,7 @@ impl ReadWriteActor {
|
|||||||
_ = check_pong => {},
|
_ = check_pong => {},
|
||||||
_ = check_stop => {},
|
_ = check_stop => {},
|
||||||
}
|
}
|
||||||
on_disconnected().await;
|
on_disconnected_callback().await;
|
||||||
debug!("connect retrying");
|
debug!("connect retrying");
|
||||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||||
debug!("disconnected");
|
debug!("disconnected");
|
||||||
@ -238,10 +542,10 @@ pub struct ReadWriterHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ReadWriterHandle {
|
impl ReadWriterHandle {
|
||||||
pub async fn send(&self, data: &[u8]) -> Result<()> {
|
pub async fn send(&self, data: Vec<u8>) -> Result<()> {
|
||||||
if self.connected.load(Ordering::Relaxed) {
|
if self.connected.load(Ordering::Relaxed) {
|
||||||
// connected, send to it
|
// connected, send to it
|
||||||
if let Err(e) = self.send_to_tcp.send(Vec::from(data)).await {
|
if let Err(e) = self.send_to_tcp.send(data).await {
|
||||||
error!("failed to send to send_to_tcp: {}", e.to_string());
|
error!("failed to send to send_to_tcp: {}", e.to_string());
|
||||||
return Err(SDLanError::NormalError("failed to send"));
|
return Err(SDLanError::NormalError("failed to send"));
|
||||||
};
|
};
|
||||||
@ -253,41 +557,55 @@ impl ReadWriterHandle {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new<'a, T, T3, T2, F, F2>(
|
fn new<>(
|
||||||
cancel: CancellationToken,
|
cancel: CancellationToken,
|
||||||
addr: &str,
|
addr: &str,
|
||||||
on_connected: T,
|
// on_connected: OnConnectedCallback<'a>,
|
||||||
on_disconnected: T3,
|
// on_disconnected: T3,
|
||||||
on_message: T2,
|
// on_message: T2,
|
||||||
pong_time: Arc<AtomicU64>,
|
pong_time: Arc<AtomicU64>,
|
||||||
start_stop_chan: Receiver<StartStopInfo>,
|
start_stop_chan: Receiver<StartStopInfo>,
|
||||||
// cancel: CancellationToken,
|
// cancel: CancellationToken,
|
||||||
connecting_chan: Option<Sender<ConnectionState>>,
|
connecting_chan: Option<Sender<ConnectionInfo>>,
|
||||||
ipv6_network_restarter: Option<Sender<bool>>,
|
ipv6_network_restarter: Option<Sender<bool>>,
|
||||||
) -> Self
|
) -> Self
|
||||||
where
|
where
|
||||||
T: for<'b> Fn(&'b mut TcpStream, Option<u32>) -> BoxFuture<'b, ()> + Send + 'static,
|
// T3: Fn() -> F2 + Send + 'static,
|
||||||
T3: Fn() -> F2 + Send + 'static,
|
// T2: Fn(SdlanTcp) -> F + Send + 'static,
|
||||||
T2: Fn(SdlanTcp) -> F + Send + 'static,
|
// F: Future<Output = ()> + Send,
|
||||||
F: Future<Output = ()> + Send,
|
// F2: Future<Output = ()> + Send,
|
||||||
F2: Future<Output = ()> + Send,
|
|
||||||
{
|
{
|
||||||
let (send_to_tcp, to_tcp) = channel(20);
|
let (send_to_tcp, to_tcp) = channel(20);
|
||||||
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
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
});
|
});
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
if let Some(msg) = data_from_tcp.recv().await {
|
if let Some(msg) = data_from_tcp.recv().await {
|
||||||
on_message(msg).await;
|
handle_tcp_message(msg).await;
|
||||||
} else {
|
} else {
|
||||||
eprintln!("data from tcp exited");
|
error!("data from tcp exited");
|
||||||
|
// eprintln!("data from tcp exited");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -301,30 +619,28 @@ impl ReadWriterHandle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_tcp_conn<'a, T, T3, T2, F, F2>(
|
pub fn init_tcp_conn(
|
||||||
cancel: CancellationToken,
|
cancel: CancellationToken,
|
||||||
addr: &str,
|
addr: &str,
|
||||||
on_connected: T,
|
// on_connected: OnConnectedCallback<'a>,
|
||||||
on_disconnected: T3,
|
// on_disconnected: T3,
|
||||||
on_message: T2,
|
// on_message: T2,
|
||||||
pong_time: Arc<AtomicU64>,
|
pong_time: Arc<AtomicU64>,
|
||||||
// cancel: CancellationToken,
|
// cancel: CancellationToken,
|
||||||
start_stop_chan: Receiver<StartStopInfo>,
|
start_stop_chan: Receiver<StartStopInfo>,
|
||||||
connecting_chan: Option<Sender<ConnectionState>>,
|
connecting_chan: Option<Sender<ConnectionInfo>>,
|
||||||
ipv6_network_restarter: Option<Sender<bool>>,
|
ipv6_network_restarter: Option<Sender<bool>>,
|
||||||
) where
|
)
|
||||||
T: for<'b> Fn(&'b mut TcpStream, Option<u32>) -> BoxFuture<'b, ()> + Send + 'static,
|
// T2: Fn(SdlanTcp) -> F + Send + 'static,
|
||||||
T3: Fn() -> F2 + Send + 'static,
|
// F: Future<Output = ()> + Send,
|
||||||
T2: Fn(SdlanTcp) -> F + Send + 'static,
|
|
||||||
F: Future<Output = ()> + Send,
|
|
||||||
F2: Future<Output = ()> + Send,
|
|
||||||
{
|
{
|
||||||
|
|
||||||
let tcp_handle = ReadWriterHandle::new(
|
let tcp_handle = ReadWriterHandle::new(
|
||||||
cancel,
|
cancel,
|
||||||
addr,
|
addr,
|
||||||
on_connected,
|
// on_connected,
|
||||||
on_disconnected,
|
// on_disconnected,
|
||||||
on_message,
|
// on_message,
|
||||||
pong_time,
|
pong_time,
|
||||||
start_stop_chan,
|
start_stop_chan,
|
||||||
connecting_chan,
|
connecting_chan,
|
||||||
|
|||||||
25
src/utils/command.rs
Normal file → Executable file
25
src/utils/command.rs
Normal file → Executable file
@ -2,8 +2,17 @@ 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,
|
||||||
|
|
||||||
|
#[structopt(short= "h", long = "hostname", default_value="", help="specify the hostname")]
|
||||||
|
pub hostname: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(StructOpt, Debug)]
|
#[derive(StructOpt, Debug)]
|
||||||
@ -25,6 +34,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 +53,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 +72,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(),
|
||||||
|
|||||||
79
src/utils/mod.rs
Normal file → Executable file
79
src/utils/mod.rs
Normal file → Executable file
@ -1,8 +1,85 @@
|
|||||||
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 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
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub mod mod_hostname {
|
||||||
|
use std::{ffi::OsString, os::windows::ffi::OsStringExt};
|
||||||
|
|
||||||
|
use winapi::um::winbase::GetComputerNameW;
|
||||||
|
|
||||||
|
pub fn get_hostname() -> Option<String> {
|
||||||
|
unsafe {
|
||||||
|
let mut buffer: Vec<u16> = vec![0; 64];
|
||||||
|
let mut buffer_size = 64;
|
||||||
|
if GetComputerNameW(buffer.as_mut_ptr(), &mut buffer_size) != 0 {
|
||||||
|
let hostname = OsString::from_wide(&buffer[..buffer_size as usize]);
|
||||||
|
return hostname.into_string().ok();
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub mod mod_hostname {
|
||||||
|
use libc::{size_t, c_int, c_char};
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn gethostname(name: *mut c_char, size: size_t) -> c_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_hostname() -> Option<String> {
|
||||||
|
let mut buffer = vec![0u8; 255];
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if gethostname(buffer.as_mut_ptr() as *mut c_char, 255) == 0 {
|
||||||
|
let len = buffer.iter().position(|&b| b == 0).unwrap_or(255);
|
||||||
|
buffer.truncate(len);
|
||||||
|
return String::from_utf8(buffer).ok();
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub mod hostname {
|
||||||
|
|
||||||
|
}
|
||||||
9
src/utils/pid_recorder.rs
Normal file → Executable file
9
src/utils/pid_recorder.rs
Normal file → Executable file
@ -2,9 +2,12 @@ use std::{
|
|||||||
fs::{self, OpenOptions},
|
fs::{self, OpenOptions},
|
||||||
io::Write,
|
io::Write,
|
||||||
};
|
};
|
||||||
|
use tracing::{error};
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
pub struct PidRecorder(String);
|
pub struct PidRecorder(String);
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
impl PidRecorder {
|
impl PidRecorder {
|
||||||
pub fn new(pidfile: &str) -> Self {
|
pub fn new(pidfile: &str) -> Self {
|
||||||
let pid = std::process::id();
|
let pid = std::process::id();
|
||||||
@ -19,7 +22,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 +34,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
src/utils/socks.rs
Normal file → Executable file
8
src/utils/socks.rs
Normal file → Executable 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> {
|
||||||
@ -80,7 +78,7 @@ impl Socket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if tos != 0 {
|
if tos != 0 {
|
||||||
if let Err(e) = udp.set_tos(tos) {
|
if let Err(e) = udp.set_tos_v4(tos) {
|
||||||
error!("failed to set tos: {}", e.to_string());
|
error!("failed to set tos: {}", e.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
start_docker.sh
Executable file
2
start_docker.sh
Executable 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
BIN
wintun.dll
Executable file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user