Compare commits
13 Commits
c5b04eb843
...
50db315c79
| Author | SHA1 | Date | |
|---|---|---|---|
| 50db315c79 | |||
| c8c618015a | |||
| 651b9ba5cd | |||
| 46170feb5b | |||
| 31845c6707 | |||
| e8e8655100 | |||
| 00c5c67307 | |||
| 8902c27b1d | |||
| 8645b65534 | |||
| 9d52223f84 | |||
| be71e8404a | |||
| 13c287e089 | |||
| 6f895c3404 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -12,3 +12,4 @@ sdlan.exe
|
||||
*.tar.gz
|
||||
*.tgz
|
||||
/punchnet
|
||||
/ca
|
||||
|
||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -1,4 +1,4 @@
|
||||
{
|
||||
// "rust-analyzer.cargo.target": "x86_64-pc-windows-gnu"
|
||||
// "rust-analyzer.cargo.target": "x86_64-pc-windows-gnu",
|
||||
// "rust-analyzer.cargo.features": ["tun"]
|
||||
}
|
||||
399
Cargo.lock
generated
399
Cargo.lock
generated
@ -159,6 +159,28 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-rs"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9a7b350e3bb1767102698302bc37256cbd48422809984b98d292c40e2579aa9"
|
||||
dependencies = [
|
||||
"aws-lc-sys",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-sys"
|
||||
version = "0.37.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b092fe214090261288111db7a2b2c2118e5a7f30dc2569f1732c4069a6840549"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cmake",
|
||||
"dunce",
|
||||
"fs_extra",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.7"
|
||||
@ -224,9 +246,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.11.0"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
|
||||
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
|
||||
|
||||
[[package]]
|
||||
name = "c2rust-bitfields"
|
||||
@ -258,7 +280,7 @@ dependencies = [
|
||||
"anstyle",
|
||||
"ar",
|
||||
"cargo_toml",
|
||||
"clap 4.5.54",
|
||||
"clap 4.5.60",
|
||||
"elf",
|
||||
"env_logger",
|
||||
"glob",
|
||||
@ -302,9 +324,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cesu8"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
@ -357,18 +387,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.54"
|
||||
version = "4.5.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
|
||||
checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.54"
|
||||
version = "4.5.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
|
||||
checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@ -377,10 +408,31 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.7"
|
||||
name = "clap_derive"
|
||||
version = "4.5.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
|
||||
checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
@ -388,12 +440,32 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
@ -486,6 +558,15 @@ dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "daemonize"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab8bfdaacb3c887a54d41bdf48d3af8873b3f5566469f8ba21b92057509f116e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.11"
|
||||
@ -640,6 +721,12 @@ version = "0.15.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
|
||||
|
||||
[[package]]
|
||||
name = "dunce"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
@ -719,6 +806,18 @@ version = "2.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "fastbloom"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e7f34442dbe69c60fe8eaf58a8cafff81a1f278816d8ab4db255b3bef4ac3c4"
|
||||
dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
"libm",
|
||||
"rand 0.9.2",
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.3.0"
|
||||
@ -775,6 +874,12 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs_extra"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.31"
|
||||
@ -1320,6 +1425,38 @@ version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
|
||||
dependencies = [
|
||||
"cesu8",
|
||||
"cfg-if",
|
||||
"combine",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"thiserror 1.0.69",
|
||||
"walkdir",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jni-sys"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
|
||||
dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.85"
|
||||
@ -1620,6 +1757,12 @@ version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.5"
|
||||
@ -1868,9 +2011,12 @@ dependencies = [
|
||||
name = "punchnet"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"cargo-deb",
|
||||
"clap 4.5.60",
|
||||
"crc",
|
||||
"crc32fast",
|
||||
"daemonize",
|
||||
"dashmap 6.1.0",
|
||||
"dns-lookup",
|
||||
"etherparse",
|
||||
@ -1882,11 +2028,16 @@ dependencies = [
|
||||
"once_cell",
|
||||
"prost",
|
||||
"prost-build",
|
||||
"quinn",
|
||||
"rand 0.8.5",
|
||||
"reqwest",
|
||||
"rpassword",
|
||||
"rsa",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"sdlan-sn-rs",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"structopt",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
@ -1928,6 +2079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fastbloom",
|
||||
"getrandom 0.3.4",
|
||||
"lru-slab",
|
||||
"rand 0.9.2",
|
||||
@ -1935,6 +2087,7 @@ dependencies = [
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"rustls-platform-verifier",
|
||||
"slab",
|
||||
"thiserror 2.0.17",
|
||||
"tinyvec",
|
||||
@ -2162,6 +2315,17 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rpassword"
|
||||
version = "7.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66d4c8b64f049c6721ec8ccec37ddfc3d641c4a7fca57e8f2a89de509c73df39"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rtoolbox",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "0.9.10"
|
||||
@ -2182,6 +2346,16 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtoolbox"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7cc970b249fbe527d6e02e0a227762c9108b2f49d81094fe357ffc6d14d7f6f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.1"
|
||||
@ -2203,10 +2377,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.36"
|
||||
version = "0.23.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b"
|
||||
checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4"
|
||||
dependencies = [
|
||||
"aws-lc-rs",
|
||||
"log",
|
||||
"once_cell",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
@ -2215,6 +2391,27 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-native-certs"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63"
|
||||
dependencies = [
|
||||
"openssl-probe",
|
||||
"rustls-pki-types",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.13.2"
|
||||
@ -2225,12 +2422,40 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-platform-verifier"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784"
|
||||
dependencies = [
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"jni",
|
||||
"log",
|
||||
"once_cell",
|
||||
"rustls",
|
||||
"rustls-native-certs",
|
||||
"rustls-platform-verifier-android",
|
||||
"rustls-webpki",
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"webpki-root-certs",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-platform-verifier-android"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.103.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52"
|
||||
dependencies = [
|
||||
"aws-lc-rs",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"untrusted",
|
||||
@ -2248,6 +2473,24 @@ version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
@ -2279,6 +2522,29 @@ dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "3.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
@ -2417,6 +2683,12 @@ version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.11"
|
||||
@ -3242,6 +3514,16 @@ version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.1"
|
||||
@ -3351,6 +3633,15 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-root-certs"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "1.0.5"
|
||||
@ -3386,6 +3677,15 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
@ -3470,6 +3770,15 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||
dependencies = [
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
@ -3488,6 +3797,15 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.60.2"
|
||||
@ -3506,6 +3824,21 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.42.2",
|
||||
"windows_aarch64_msvc 0.42.2",
|
||||
"windows_i686_gnu 0.42.2",
|
||||
"windows_i686_msvc 0.42.2",
|
||||
"windows_x86_64_gnu 0.42.2",
|
||||
"windows_x86_64_gnullvm 0.42.2",
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
@ -3554,6 +3887,12 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.53.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
@ -3572,6 +3911,12 @@ version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
@ -3590,6 +3935,12 @@ version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
@ -3620,6 +3971,12 @@ version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
@ -3638,6 +3995,12 @@ version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
@ -3656,6 +4019,12 @@ version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
@ -3674,6 +4043,12 @@ version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
|
||||
@ -28,6 +28,14 @@ tokio = { version = "1.38.0", features = ["full"] }
|
||||
tokio-util = "0.7.11"
|
||||
tracing = "0.1.40"
|
||||
myactor = { git = "https://gitea.s5s8.com/rust/actor-rs.git" }
|
||||
bytes = "1.11.1"
|
||||
quinn = "0.11.9"
|
||||
rustls = "0.23.37"
|
||||
rustls-pemfile = "2.2.0"
|
||||
clap = { version = "4.5.60", features = ["derive", "env"] }
|
||||
rpassword = "7.4.0"
|
||||
serde_json = "1.0.149"
|
||||
daemonize = "0.5.0"
|
||||
# rolling-file = { path = "../rolling-file" }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
|
||||
171
message.proto
171
message.proto
@ -1,5 +1,7 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package message;
|
||||
|
||||
// 基础公共类型定义
|
||||
|
||||
message SDLV4Info {
|
||||
@ -13,54 +15,101 @@ message SDLV6Info {
|
||||
bytes v6 = 2;
|
||||
}
|
||||
|
||||
// 设备网络地址信息
|
||||
message SDLDevAddr {
|
||||
uint32 network_id = 1;
|
||||
bytes mac = 2;
|
||||
uint32 net_addr = 3;
|
||||
uint32 net_bit_len = 4;
|
||||
string network_domain = 5;
|
||||
}
|
||||
// 和super之间采用了quic协议通讯
|
||||
// 传输层采用: <<Len:16, PacketType:8, Payload/binary>>
|
||||
|
||||
// tcp通讯消息
|
||||
message SDLEmpty {
|
||||
|
||||
}
|
||||
|
||||
message SDLRegisterSuper {
|
||||
message SDLWelcome {
|
||||
uint32 version = 1;
|
||||
string installed_channel = 2;
|
||||
string client_id = 3;
|
||||
SDLDevAddr dev_addr = 4;
|
||||
string pub_key = 5;
|
||||
string token = 6;
|
||||
string network_code = 7;
|
||||
string hostname = 8;
|
||||
// 服务器允许的最大双向流
|
||||
uint32 max_bidi_streams = 2;
|
||||
// 服务器允许的最大包
|
||||
uint32 max_packet_size = 3;
|
||||
// 心跳包的间隔
|
||||
uint32 heartbeat_sec = 4;
|
||||
}
|
||||
|
||||
// quic 通讯消息
|
||||
message SDLEmpty {
|
||||
uint32 pkt_id = 1;
|
||||
}
|
||||
|
||||
// 这里修改成了扁平的结构, 否则有些字段不好找放的位置
|
||||
message SDLRegisterSuper {
|
||||
uint32 pkt_id = 1;
|
||||
string client_id = 2;
|
||||
// 网络地址信息已经有https请求分配了
|
||||
// 注册的时候需要带上(network_id, mac, ip, mask_len, hostname)
|
||||
uint32 network_id = 3;
|
||||
bytes mac = 4;
|
||||
uint32 ip = 5;
|
||||
uint32 mask_len = 6;
|
||||
string hostname = 7;
|
||||
|
||||
string pub_key = 8;
|
||||
// 客户端使用http协议请求后端,通过token或者账号密码登录时, 统一返回一个access_token;
|
||||
// RegisterSuper的时候,验证凭证是否合法 (access_token)
|
||||
string access_token = 9;
|
||||
}
|
||||
|
||||
// 客户端的升级逻辑,在https的接口里面去完成
|
||||
// 部分逻辑会脱离quic去通讯,增加session_token校验
|
||||
message SDLRegisterSuperAck {
|
||||
SDLDevAddr dev_addr = 1;
|
||||
uint32 pkt_id = 1;
|
||||
bytes aes_key = 2;
|
||||
uint32 upgrade_type = 3;
|
||||
optional string upgrade_prompt = 4;
|
||||
optional string upgrade_address = 5;
|
||||
bytes session_token = 3;
|
||||
}
|
||||
|
||||
message SDLRegisterSuperNak {
|
||||
uint32 error_code = 1;
|
||||
string error_message = 2;
|
||||
uint32 pkt_id = 1;
|
||||
uint32 error_code = 2;
|
||||
string error_message = 3;
|
||||
}
|
||||
|
||||
// 网络地址查询
|
||||
|
||||
message SDLQueryInfo {
|
||||
bytes dst_mac = 1;
|
||||
uint32 pkt_id = 1;
|
||||
bytes dst_mac = 2;
|
||||
}
|
||||
|
||||
message SDLPeerInfo {
|
||||
bytes dst_mac = 1;
|
||||
SDLV4Info v4_info = 2;
|
||||
optional SDLV6Info v6_info = 3;
|
||||
uint32 pkt_id = 1;
|
||||
bytes dst_mac = 2;
|
||||
SDLV4Info v4_info = 3;
|
||||
optional SDLV6Info v6_info = 4;
|
||||
}
|
||||
|
||||
// ARP查询相关
|
||||
// 真实的arp请求是通过广播的形式获取到的,但是针对于macos这种tun的实现;是能够分析出arp请求包的;
|
||||
// 对于当前网络来说,服务端是知道mac对应的ip地址的,因此没有必要广播;直接通过服务器端返回
|
||||
message SDLArpRequest {
|
||||
uint32 pkt_id = 1;
|
||||
uint32 target_ip = 2;
|
||||
}
|
||||
|
||||
message SDLArpResponse {
|
||||
uint32 pkt_id = 1;
|
||||
uint32 target_ip = 2;
|
||||
bytes target_mac = 3;
|
||||
}
|
||||
|
||||
// 权限请求查询相关
|
||||
message SDLPolicyRequest {
|
||||
uint32 pkt_id = 1;
|
||||
uint32 src_identity_id = 2;
|
||||
uint32 dst_identity_id = 3;
|
||||
uint32 version = 4;
|
||||
}
|
||||
|
||||
// 基于quic通讯,rules部分已经没有了长度限制
|
||||
message SDLPolicyResponse {
|
||||
uint32 pkt_id = 1;
|
||||
uint32 src_identity_id = 2;
|
||||
uint32 dst_identity_id = 3;
|
||||
// 版本号,客户端需要比较版本号确定是否覆盖; 请求端自己去管理版本号,服务端只是原样回写
|
||||
uint32 version = 4;
|
||||
// 4+1+2 的稀疏序列化规则
|
||||
bytes rules = 5;
|
||||
}
|
||||
|
||||
// 事件定义
|
||||
@ -82,30 +131,9 @@ message SDLNetworkShutdownEvent {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
// 命令定义
|
||||
|
||||
message SDLChangeNetworkCommand {
|
||||
SDLDevAddr dev_addr = 1;
|
||||
bytes aes_key = 2;
|
||||
}
|
||||
|
||||
message SDLCommandAck {
|
||||
// status = true, 表示成功;status = false 表示失败,message是失败原因描述
|
||||
bool status = 1;
|
||||
optional string message = 2;
|
||||
}
|
||||
|
||||
message SDLFlows {
|
||||
// 服务器转发流量
|
||||
uint32 forward_num = 1;
|
||||
// p2p直接流量
|
||||
uint32 p2p_num = 2;
|
||||
// 接收的流量
|
||||
uint32 inbound_num = 3;
|
||||
}
|
||||
|
||||
// UDP通讯消息
|
||||
|
||||
// client和stun之间的心跳包,客户端需要和super的udp之间的存活逻辑
|
||||
message SDLStunRequest {
|
||||
uint32 cookie = 1;
|
||||
string client_id = 2;
|
||||
@ -114,6 +142,7 @@ message SDLStunRequest {
|
||||
uint32 ip = 5;
|
||||
uint32 nat_type = 6;
|
||||
optional SDLV6Info v6_info = 7;
|
||||
bytes session_token = 8;
|
||||
}
|
||||
|
||||
message SDLStunReply {
|
||||
@ -127,8 +156,31 @@ message SDLData {
|
||||
bool is_p2p = 4;
|
||||
uint32 ttl = 5;
|
||||
bytes data = 6;
|
||||
bytes session_token = 7;
|
||||
// 端通过https登录的时候,服务端会分配该端对应的权限标识
|
||||
// 后续的请求过程中需要带上这个值,对端通过这个值要判断对数据包是否放行
|
||||
uint32 identity_id = 8;
|
||||
}
|
||||
|
||||
// 网络类型探测
|
||||
|
||||
message SDLStunProbe {
|
||||
uint32 cookie = 1;
|
||||
uint32 attr = 2;
|
||||
// 增加step是为了方便端上判断,收到的请求和响应之间的映射关系;服务器端原样返回
|
||||
uint32 step = 3;
|
||||
}
|
||||
|
||||
message SDLStunProbeReply {
|
||||
uint32 cookie = 1;
|
||||
// 增加step是为了方便端上判断,收到的请求和响应之间的映射关系;服务器端原样返回
|
||||
uint32 step = 2;
|
||||
uint32 port = 3;
|
||||
uint32 ip = 4;
|
||||
}
|
||||
|
||||
// Node-Node之间的握手逻辑, 是基于udp传输的
|
||||
|
||||
message SDLRegister {
|
||||
uint32 network_id = 1;
|
||||
bytes src_mac = 2;
|
||||
@ -139,17 +191,4 @@ message SDLRegisterAck {
|
||||
uint32 network_id = 1;
|
||||
bytes src_mac = 2;
|
||||
bytes dst_mac = 3;
|
||||
}
|
||||
|
||||
// 网络类型探测
|
||||
|
||||
message SDLStunProbe {
|
||||
uint32 cookie = 1;
|
||||
uint32 attr = 2;
|
||||
}
|
||||
|
||||
message SDLStunProbeReply {
|
||||
uint32 cookie = 1;
|
||||
uint32 port = 2;
|
||||
uint32 ip = 3;
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
fn main() {
|
||||
prost_build::Config::new()
|
||||
.out_dir("src/pb")
|
||||
.bytes(&[".message.SDLData.data"])
|
||||
// .out_dir("../tcp_mock/pb")
|
||||
.protoc_arg("--experimental_allow_proto3_optional")
|
||||
.compile_protos(&["message.proto"], &["."])
|
||||
|
||||
243
src/bin/punchnet/api/mod.rs
Normal file
243
src/bin/punchnet/api/mod.rs
Normal file
@ -0,0 +1,243 @@
|
||||
use reqwest::Client;
|
||||
use sdlan_sn_rs::utils::{Mac, Result, SDLanError};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const TEST_PREFIX: &'static str = "https://punchnet.s5s8.com/api";
|
||||
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct TokenLoginData<'a> {
|
||||
client_id: &'a str,
|
||||
token: &'a str,
|
||||
mac: &'a str,
|
||||
system: &'a str,
|
||||
version: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct UserPassLoginData<'a> {
|
||||
client_id: &'a str,
|
||||
username: &'a str,
|
||||
password: &'a str,
|
||||
mac: &'a str,
|
||||
system: &'a str,
|
||||
version: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct LoginResponse {
|
||||
pub code: i32,
|
||||
pub message: String,
|
||||
pub data: Option<LoginData>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct LoginData {
|
||||
pub access_token: String,
|
||||
pub username: String,
|
||||
pub user_type: String,
|
||||
pub audit: u32,
|
||||
pub network_id: u32,
|
||||
pub network_name: String,
|
||||
// pub network_domain: String,
|
||||
pub exit_node: Vec<ExitNode>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ExitNode {
|
||||
pub nnid: u32,
|
||||
pub node_name: String,
|
||||
}
|
||||
|
||||
async fn post_with_data<T, R>(
|
||||
url: &str,
|
||||
data: T,
|
||||
) -> Result<R>
|
||||
where T: Serialize,
|
||||
R: for<'de> Deserialize<'de>
|
||||
{
|
||||
|
||||
let client = Client::new();
|
||||
let Ok(response) = client
|
||||
.post(url)
|
||||
.json(&data)
|
||||
.send()
|
||||
.await else {
|
||||
return Err(SDLanError::IOError("failed to do request".to_owned()));
|
||||
};
|
||||
|
||||
println!("status: {}", response.status());
|
||||
let text = response.text().await.unwrap();
|
||||
println!("text = {}", text);
|
||||
|
||||
let data = serde_json::from_str(&text).unwrap();
|
||||
|
||||
// println!("response: {}", response.text().await.unwrap());
|
||||
// let Ok(data) = response.json().await else {
|
||||
// return Err(SDLanError::IOError("failed to jsonify response".to_owned()));
|
||||
// };
|
||||
// println!("got respose: {:?}", data);
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub async fn login_with_user_pass(
|
||||
url_prefix: &str,
|
||||
client_id: &str,
|
||||
username: &str,
|
||||
password: &str,
|
||||
mac: Mac,
|
||||
system: &str,
|
||||
version: &str,
|
||||
) -> Result<LoginResponse> {
|
||||
let mac = format!("{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
|
||||
);
|
||||
|
||||
let post_data = UserPassLoginData {
|
||||
client_id,
|
||||
username,
|
||||
password,
|
||||
mac: &mac,
|
||||
system,
|
||||
version,
|
||||
};
|
||||
|
||||
post_with_data(&format!("{}/auth/login", url_prefix), post_data).await
|
||||
}
|
||||
|
||||
pub async fn login_with_token(
|
||||
url_prefix: &str,
|
||||
client_id: &str,
|
||||
token: &str,
|
||||
mac: Mac,
|
||||
system: &str,
|
||||
version: &str,
|
||||
) -> Result<LoginResponse> {
|
||||
let mac = format!("{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
|
||||
);
|
||||
|
||||
let post_data = TokenLoginData {
|
||||
client_id,
|
||||
token,
|
||||
mac: &mac,
|
||||
system,
|
||||
version,
|
||||
};
|
||||
|
||||
post_with_data(&format!("{}/auth/token", url_prefix), post_data).await
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ConnectDisconnectRequest<'a> {
|
||||
client_id: &'a str,
|
||||
access_token: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ConnectResponse {
|
||||
pub code: i32,
|
||||
pub message: String,
|
||||
pub data: Option<ConnectData>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ConnectData {
|
||||
pub ip: String,
|
||||
pub mask_len: u8,
|
||||
pub hostname: String,
|
||||
pub identity_id: u32,
|
||||
pub resource_list: Vec<ResourceList>,
|
||||
pub node_list: Vec<NodeList>,
|
||||
// pub acl: Vec<ACL>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ResourceList {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub url: String,
|
||||
pub connection_status: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct NodeList {
|
||||
pub name: String,
|
||||
pub connection_status: String,
|
||||
pub ip: String,
|
||||
pub system: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct DisconnectResponse {
|
||||
pub code: i32,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
pub async fn connect(
|
||||
url_prefix: &str,
|
||||
client_id: &str,
|
||||
access_token: &str,
|
||||
) -> Result<ConnectResponse> {
|
||||
let url = format!("{}/connect", url_prefix);
|
||||
let data = ConnectDisconnectRequest {
|
||||
client_id,
|
||||
access_token,
|
||||
};
|
||||
post_with_data(&url, data).await
|
||||
}
|
||||
|
||||
pub async fn disconnect(
|
||||
url_prefix: &str,
|
||||
client_id: &str,
|
||||
access_token: &str,
|
||||
) -> Result<DisconnectResponse> {
|
||||
let url = format!("{}/disconnect", url_prefix);
|
||||
let data = ConnectDisconnectRequest {
|
||||
client_id,
|
||||
access_token,
|
||||
};
|
||||
post_with_data(&url, data).await
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct GetResourceRequest<'a> {
|
||||
client_id: &'a str,
|
||||
access_token: &'a str,
|
||||
id: i32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct GetResourceResponse {
|
||||
pub code: i32,
|
||||
pub message: String,
|
||||
pub data: Option<ResourceData>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ResourceData {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub ip: String,
|
||||
pub system: String,
|
||||
pub connection_status: String,
|
||||
pub resource_list: Vec<ResourceList>,
|
||||
}
|
||||
|
||||
pub async fn get_node_resource(
|
||||
url_prefix: &str,
|
||||
client_id: &str,
|
||||
access_token: &str,
|
||||
id: i32,
|
||||
) -> Result<GetResourceResponse> {
|
||||
let data = GetResourceRequest {
|
||||
client_id,
|
||||
access_token,
|
||||
id,
|
||||
};
|
||||
|
||||
let url = format!("{}/get_node_resource", url_prefix);
|
||||
post_with_data(&url, data).await
|
||||
}
|
||||
@ -1,31 +1,119 @@
|
||||
mod api;
|
||||
|
||||
use std::fs::File;
|
||||
use std::fs::OpenOptions;
|
||||
use std::process;
|
||||
|
||||
use std::env;
|
||||
use std::time::Duration;
|
||||
use clap::Parser;
|
||||
use daemonize::Daemonize;
|
||||
use punchnet::CachedLoginInfo;
|
||||
use punchnet::CommandLineInput2;
|
||||
use punchnet::Commands;
|
||||
use punchnet::create_or_load_mac;
|
||||
use punchnet::get_access_token;
|
||||
use punchnet::get_base_dir;
|
||||
use punchnet::get_edge;
|
||||
use punchnet::ip_string_to_u32;
|
||||
use punchnet::mod_hostname;
|
||||
use punchnet::restore_dns;
|
||||
use punchnet::run_sdlan;
|
||||
use punchnet::set_access_token;
|
||||
use punchnet::set_base_dir;
|
||||
use punchnet::CommandLine;
|
||||
use punchnet::CommandLineInput;
|
||||
use sdlan_sn_rs::log;
|
||||
|
||||
use sdlan_sn_rs::utils::Mac;
|
||||
use sdlan_sn_rs::utils::Result;
|
||||
use sdlan_sn_rs::utils::create_or_load_uuid;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::io::stdout;
|
||||
use tokio::time::sleep;
|
||||
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();
|
||||
use crate::api::ConnectData;
|
||||
use crate::api::ConnectResponse;
|
||||
use crate::api::LoginData;
|
||||
use crate::api::LoginResponse;
|
||||
use crate::api::TEST_PREFIX;
|
||||
use crate::api::connect;
|
||||
use crate::api::login_with_token;
|
||||
use crate::api::login_with_user_pass;
|
||||
|
||||
|
||||
// println!("port is {}", cmd.port);
|
||||
const APP_USER_ENV_NAME: &str = "PUNCH_USER";
|
||||
const APP_PASS_ENV_NAME: &str = "PUNCH_PASS";
|
||||
const APP_TOKEN_ENV_NAME: &str = "PUNCH_TOKEN";
|
||||
|
||||
fn parse_connect_result(res: Result<ConnectResponse>) -> ConnectData {
|
||||
match res {
|
||||
Err(e) => {
|
||||
eprintln!("failed to connect");
|
||||
process::exit(-3);
|
||||
}
|
||||
Ok(data) => {
|
||||
if data.code != 0 {
|
||||
eprintln!("failed to connect: {}", data.message);
|
||||
process::exit(-3);
|
||||
}
|
||||
if data.data.is_none() {
|
||||
eprintln!("connect empty response");
|
||||
process::exit(-3);
|
||||
}
|
||||
data.data.unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_login_result(res: Result<LoginResponse>) -> LoginData {
|
||||
match res {
|
||||
Err(e) => {
|
||||
eprintln!("login error: {}", e.as_str());
|
||||
process::exit(-1);
|
||||
}
|
||||
Ok(data) => {
|
||||
if data.code != 0 {
|
||||
eprintln!("login error: {}", data.message);
|
||||
process::exit(-1);
|
||||
}
|
||||
let Some(data) = data.data else {
|
||||
eprintln!("login error: empty data");
|
||||
process::exit(-1);
|
||||
};
|
||||
|
||||
if let Err(_e) = set_access_token(&CachedLoginInfo {
|
||||
access_token: data.access_token.clone(),
|
||||
username: data.username.clone(),
|
||||
user_type: data.user_type.clone(),
|
||||
audit: data.audit,
|
||||
network_id: data.network_id,
|
||||
network_name: data.network_name.clone(),
|
||||
}) {
|
||||
eprintln!("failed to save access_token");
|
||||
}
|
||||
data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn daemonize_me(
|
||||
connect_info: ConnectData,
|
||||
remembered: CachedLoginInfo,
|
||||
client_id: String,
|
||||
mac: Mac,
|
||||
) {
|
||||
println!("identity_id = {}", connect_info.identity_id);
|
||||
|
||||
let self_host_name = connect_info.hostname;
|
||||
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
|
||||
let hostname = "punchnet.aioe.tech".to_owned();
|
||||
let hostname = "118.178.229.213".to_owned();
|
||||
let host = format!("{}:80", hostname);
|
||||
let mut server = String::new();
|
||||
if let Ok(addrs) = host.to_socket_addrs() {
|
||||
@ -41,7 +129,7 @@ async fn main() {
|
||||
|
||||
println!("server is {}", server);
|
||||
|
||||
mod_hostname::get_hostname();
|
||||
// mod_hostname::get_hostname();
|
||||
/*
|
||||
let hostname = if cmd.hostname.len() == 0 {
|
||||
mod_hostname::get_hostname()
|
||||
@ -49,6 +137,7 @@ async fn main() {
|
||||
Some(cmd.hostname)
|
||||
};
|
||||
*/
|
||||
/*
|
||||
let hostname = if cmd.hostname.len() == 0 {
|
||||
None
|
||||
} else {
|
||||
@ -56,28 +145,32 @@ async fn main() {
|
||||
};
|
||||
// let hostname = mod_hostname::get_hostname();
|
||||
println!("hostname = {:?}", hostname);
|
||||
*/
|
||||
|
||||
let _ = run_sdlan(
|
||||
client_id,
|
||||
mac,
|
||||
CommandLine {
|
||||
sn: server.clone()+":1265",
|
||||
tcp: server.clone()+":18083",
|
||||
nat_server1: server.clone() +":1265",
|
||||
nat_server2: "47.98.178.3:1265".to_owned(),
|
||||
sn: server.clone()+":1365",
|
||||
tcp: server.clone()+":443",
|
||||
nat_server1: server.clone() +":1365",
|
||||
// nat_server2: "47.98.178.3:1265".to_owned(),
|
||||
nat_server2: server.clone() +":1366",
|
||||
_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(),
|
||||
local_port: 0,
|
||||
// token: cmd.token.clone(),
|
||||
// network_code: cmd.network_code.clone(),
|
||||
allow_p2p: true,
|
||||
},
|
||||
tx,
|
||||
&punchnet::get_install_channel(),
|
||||
server,
|
||||
hostname,
|
||||
Some(self_host_name),
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
@ -109,7 +202,21 @@ async fn main() {
|
||||
// exit(0);
|
||||
}
|
||||
*/
|
||||
if let Err(e) = edge.start_without_feedback(cmd.token, cmd.network_code, None).await {
|
||||
let Ok(ip_net) = ip_string_to_u32(&connect_info.ip) else {
|
||||
eprintln!("got ip from network is invlid: {}", connect_info.ip);
|
||||
process::exit(-5);
|
||||
};
|
||||
if let Err(e) = edge.start_without_feedback(
|
||||
remembered.access_token.clone(),
|
||||
// String::new(),
|
||||
remembered.network_id,
|
||||
&"".to_owned(),
|
||||
ip_net,
|
||||
connect_info.mask_len,
|
||||
connect_info.identity_id,
|
||||
// 0,
|
||||
None,
|
||||
).await {
|
||||
error!("failed to start: {:?}", e);
|
||||
}
|
||||
|
||||
@ -148,4 +255,124 @@ async fn main() {
|
||||
// started = !started;
|
||||
// */
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
set_base_dir("/usr/local/punchnet");
|
||||
let _guard = log::init_log(&format!("{}/.output", get_base_dir()));
|
||||
|
||||
let client_id = create_or_load_uuid(&format!("{}/.id", get_base_dir()), None).unwrap();
|
||||
|
||||
let test_token = "49722584273728716817720074439183";
|
||||
|
||||
let mac = create_or_load_mac();
|
||||
|
||||
let system = "linux";
|
||||
let version = "1.0.0";
|
||||
|
||||
// let cmd = CommandLineInput::from_args();
|
||||
let cmd = CommandLineInput2::parse();
|
||||
// println!("port is {}", cmd.port);
|
||||
|
||||
let connect_info: ConnectData;
|
||||
let remembered: CachedLoginInfo;
|
||||
|
||||
let should_daemonize: bool;
|
||||
|
||||
match cmd.cmd {
|
||||
Commands::Login(user) => {
|
||||
// TODO: do login with user
|
||||
let _ = parse_login_result(
|
||||
login_with_user_pass(TEST_PREFIX, &client_id, &user.username, &user.password, mac, system, version).await
|
||||
);
|
||||
process::exit(0);
|
||||
}
|
||||
Commands::TokenLogin(tk) => {
|
||||
let _ = parse_login_result(
|
||||
login_with_token(TEST_PREFIX, &client_id, &tk.token, mac, system, version).await
|
||||
);
|
||||
process::exit(0);
|
||||
}
|
||||
Commands::AutoRun(tk) => {
|
||||
let mut remembered_token = get_access_token();
|
||||
if remembered_token.is_none() {
|
||||
let data = parse_login_result(
|
||||
login_with_token(TEST_PREFIX, &client_id, &tk.token, mac, system, version).await
|
||||
);
|
||||
remembered_token = Some(CachedLoginInfo{
|
||||
access_token: data.access_token,
|
||||
username: data.username,
|
||||
user_type: data.user_type,
|
||||
audit: data.audit,
|
||||
network_id: data.network_id,
|
||||
network_name: data.network_name,
|
||||
});
|
||||
}
|
||||
|
||||
remembered = remembered_token.unwrap();
|
||||
|
||||
connect_info = parse_connect_result(
|
||||
connect(TEST_PREFIX, &client_id, &remembered.access_token).await
|
||||
);
|
||||
should_daemonize = false;
|
||||
}
|
||||
Commands::Start => {
|
||||
let remembered_token = get_access_token();
|
||||
if remembered_token.is_none() {
|
||||
eprintln!("not logged in, should login with user/pass or token first");
|
||||
process::exit(-2);
|
||||
}
|
||||
|
||||
remembered = remembered_token.unwrap();
|
||||
|
||||
connect_info = parse_connect_result(
|
||||
connect(TEST_PREFIX, &client_id, &remembered.access_token).await
|
||||
);
|
||||
should_daemonize = false;
|
||||
}
|
||||
Commands::Stop => {
|
||||
process::exit(-4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if should_daemonize {
|
||||
let stdout = OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.write(true)
|
||||
.open("/tmp/punchnet.out").unwrap();
|
||||
let stderr = OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.write(true)
|
||||
.open("/tmp/punchnet.err").unwrap();
|
||||
|
||||
let daemonize = Daemonize::new()
|
||||
.pid_file("/tmp/punchnet.pid")
|
||||
.chown_pid_file(true)
|
||||
.working_directory(get_base_dir())
|
||||
.stdout(stdout)
|
||||
.stderr(stderr)
|
||||
.privileged_action(|| {
|
||||
|
||||
});
|
||||
match daemonize.start() {
|
||||
Ok(_) => {
|
||||
loop {
|
||||
println!("guard is {:?}", _guard);
|
||||
sleep(Duration::from_secs(3)).await;
|
||||
}
|
||||
daemonize_me(connect_info, remembered, client_id, mac).await;
|
||||
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("failed to daemonize: {}", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
daemonize_me(connect_info, remembered, client_id, mac).await;
|
||||
}
|
||||
}
|
||||
|
||||
15
src/lib.rs
15
src/lib.rs
@ -3,6 +3,7 @@ mod network;
|
||||
mod pb;
|
||||
mod tcp;
|
||||
mod utils;
|
||||
mod quic;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::{sync::atomic::AtomicU8, time::Duration};
|
||||
@ -12,13 +13,13 @@ use std::net::{SocketAddr, ToSocketAddrs};
|
||||
pub use network::get_edge;
|
||||
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 sdlan_sn_rs::utils::{Mac, save_to_file};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::net::UdpSocket;
|
||||
use tokio::sync::mpsc::{channel, Sender};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::{debug, error};
|
||||
pub use utils::{CommandLine, CommandLineInput, mod_hostname};
|
||||
pub use utils::*;
|
||||
|
||||
pub use config::{get_base_dir, set_base_dir};
|
||||
|
||||
@ -43,6 +44,9 @@ pub enum ConnectionState {
|
||||
}
|
||||
|
||||
pub async fn run_sdlan(
|
||||
edge_uuid: String,
|
||||
mac: Mac,
|
||||
|
||||
args: CommandLine,
|
||||
sender: std::sync::mpsc::Sender<bool>,
|
||||
install_channel: &str,
|
||||
@ -54,7 +58,7 @@ pub async fn run_sdlan(
|
||||
// start_stop_receiver: Receiver<String>,
|
||||
) -> Result<()> {
|
||||
let (start_stop_sender, start_stop_chan) = channel(20);
|
||||
let edge_uuid = create_or_load_uuid(&format!("{}/.id", get_base_dir()), None)?;
|
||||
// let edge_uuid = create_or_load_uuid(&format!("{}/.id", get_base_dir()), None)?;
|
||||
let node_conf = parse_config(edge_uuid, &args).await?;
|
||||
|
||||
let hostfile = format!("{}/.host", get_base_dir());
|
||||
@ -68,8 +72,9 @@ pub async fn run_sdlan(
|
||||
let sock = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
|
||||
|
||||
if let Err(e) = init_edge(
|
||||
&args.token,
|
||||
&args.network_code,
|
||||
// &args.token,
|
||||
// &args.network_code,
|
||||
mac,
|
||||
node_conf,
|
||||
args.tos,
|
||||
start_stop_sender,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
@ -7,7 +7,7 @@ use crate::network::ipv6::run_ipv6;
|
||||
use crate::network::{
|
||||
get_edge, ping_to_sn, read_and_parse_packet, TunTapPacketHandler,
|
||||
};
|
||||
use crate::tcp::{init_tcp_conn, send_stun_request};
|
||||
use crate::tcp::{init_identity_cache, init_quic_conn, send_stun_request};
|
||||
use crate::utils::{send_to_sock, CommandLine};
|
||||
use crate::{ConnectionInfo};
|
||||
use sdlan_sn_rs::peer::{SdlanSock};
|
||||
@ -15,6 +15,7 @@ use sdlan_sn_rs::utils::{get_current_timestamp, is_multi_broadcast};
|
||||
use sdlan_sn_rs::utils::{Mac, Result};
|
||||
use tokio::net::{UdpSocket};
|
||||
use tokio::sync::mpsc::{channel, Receiver, Sender};
|
||||
use tokio::time::sleep;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
use super::{Node, StartStopInfo};
|
||||
@ -31,11 +32,14 @@ pub async fn async_main(
|
||||
// let _ = PidRecorder::new(".pid");
|
||||
let edge = get_edge();
|
||||
|
||||
init_identity_cache();
|
||||
|
||||
// let token = args.token.clone();
|
||||
let cancel_tcp = cancel.clone();
|
||||
let (ipv6_network_restarter, rx) = channel(10);
|
||||
tokio::spawn(run_ipv6(edge, rx));
|
||||
init_tcp_conn(
|
||||
|
||||
init_quic_conn(
|
||||
cancel_tcp,
|
||||
&args.tcp,
|
||||
// |msg| handle_tcp_message(msg),
|
||||
@ -46,11 +50,6 @@ pub async fn async_main(
|
||||
Some(ipv6_network_restarter),
|
||||
);
|
||||
|
||||
// tcp_conn.send("hello".as_bytes()).await;
|
||||
// tokio::spawn(handle_tcp_message(tcp_conn.data_from_tcp));
|
||||
|
||||
// tcp_conn.send("".as_bytes());
|
||||
|
||||
debug!("waiting for authorization...");
|
||||
|
||||
/*
|
||||
@ -119,6 +118,17 @@ pub async fn async_main(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn run_quic_loop(
|
||||
edge: &Node,
|
||||
quic_addr: &str,
|
||||
pong_time: Arc<AtomicU64>,
|
||||
start_stop_chan: Receiver<StartStopInfo>,
|
||||
connecting_chan: Sender<ConnectionInfo>,
|
||||
ipv6_ntework_restarter: Option<Sender<bool>>
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
async fn run_edge_loop(eee: &'static Node, cancel: CancellationToken) {
|
||||
ping_to_sn().await;
|
||||
{
|
||||
|
||||
@ -8,21 +8,21 @@ use crate::utils::generate_mac_address;
|
||||
|
||||
pub struct DeviceConfig {
|
||||
pub mtu: u32,
|
||||
pub mac: RwLock<Mac>,
|
||||
pub mac: Mac,
|
||||
pub ip: IpSubnet,
|
||||
|
||||
pub dns_mac: Mac,
|
||||
}
|
||||
|
||||
impl DeviceConfig {
|
||||
pub fn new(mtu: u32) -> Self {
|
||||
let mac = generate_mac_address();
|
||||
pub fn new(mac: Mac, 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 {
|
||||
mtu,
|
||||
mac: RwLock::new(mac),
|
||||
mac: mac,
|
||||
ip: IpSubnet::new(0, 0),
|
||||
dns_mac,
|
||||
}
|
||||
@ -47,7 +47,7 @@ impl DeviceConfig {
|
||||
}
|
||||
|
||||
pub fn get_mac(&self) -> Mac {
|
||||
let mac = *self.mac.read().unwrap();
|
||||
let mac = self.mac;
|
||||
mac
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use dashmap::DashMap;
|
||||
use quinn::Endpoint;
|
||||
use rsa::RsaPrivateKey;
|
||||
use sdlan_sn_rs::config::{AF_INET, AF_INET6};
|
||||
use tokio::net::UdpSocket;
|
||||
@ -11,12 +12,13 @@ use tokio::sync::mpsc::Sender;
|
||||
use tokio::sync::oneshot;
|
||||
use tracing::{debug, error};
|
||||
|
||||
use crate::quic::quic_init;
|
||||
use crate::{ConnectionInfo, get_base_dir};
|
||||
use crate::pb::{
|
||||
encode_to_tcp_message, encode_to_udp_message, SdlEmpty, SdlStunProbe, SdlStunProbeReply,
|
||||
};
|
||||
use crate::tcp::{get_tcp_conn, NatType, PacketType, StunProbeAttr};
|
||||
use crate::utils::{Socket};
|
||||
use crate::tcp::{NatType, PacketType, StunProbeAttr, get_quic_write_conn};
|
||||
use crate::utils::{Socket, create_or_load_mac};
|
||||
|
||||
use sdlan_sn_rs::peer::{IpSubnet, V6Info};
|
||||
|
||||
@ -32,8 +34,9 @@ use sdlan_sn_rs::utils::{Result, SDLanError};
|
||||
static EDGE: OnceCell<Node> = OnceCell::new();
|
||||
|
||||
pub async fn init_edge(
|
||||
token: &str,
|
||||
network_code: &str,
|
||||
// token: &str,
|
||||
// network_code: &str,
|
||||
mac: Mac,
|
||||
node_conf: NodeConfig,
|
||||
tos: u32,
|
||||
start_stop: Sender<StartStopInfo>,
|
||||
@ -75,12 +78,13 @@ pub async fn init_edge(
|
||||
// let tcpsock = TCPSocket::build("121.4.79.234:1234").await?;
|
||||
let tcp_pong = Arc::new(AtomicU64::new(0));
|
||||
let edge = Node::new(
|
||||
mac,
|
||||
pubkey,
|
||||
node_conf,
|
||||
sock_v4,
|
||||
sock_multicast,
|
||||
token,
|
||||
network_code,
|
||||
// token,
|
||||
// network_code,
|
||||
privatekey,
|
||||
tcp_pong.clone(),
|
||||
start_stop,
|
||||
@ -123,13 +127,53 @@ pub struct StartStopInfo {
|
||||
pub pkt_id: Option<u32>,
|
||||
}
|
||||
|
||||
pub struct StringToken<T>(RwLock<T>);
|
||||
|
||||
impl <T: Clone> StringToken<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
Self(RwLock::new(value))
|
||||
}
|
||||
|
||||
pub fn get(&self) -> T {
|
||||
self.0.read().unwrap().clone()
|
||||
}
|
||||
|
||||
pub fn set(&self, token: T) {
|
||||
*self.0.write().unwrap() = token;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IdentityID(AtomicU32);
|
||||
|
||||
impl IdentityID {
|
||||
pub fn new(id: u32) -> Self {
|
||||
Self(AtomicU32::new(id))
|
||||
}
|
||||
|
||||
pub fn load(&self) -> u32 {
|
||||
self.0.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn store(&self, id: u32) {
|
||||
self.0.store(id, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Node {
|
||||
packet_id: AtomicU32,
|
||||
|
||||
pub network_id: AtomicU32,
|
||||
pub network_domain: RwLock<String>,
|
||||
|
||||
pub identity_id: IdentityID,
|
||||
|
||||
pub access_token: StringToken<String>,
|
||||
pub session_token: StringToken<Vec<u8>>,
|
||||
|
||||
pub hostname: RwLock<String>,
|
||||
|
||||
pub quic_endpoint: Endpoint,
|
||||
|
||||
pub udp_sock_for_dns: Arc<UdpSocket>,
|
||||
pub server_ip: String,
|
||||
|
||||
@ -139,8 +183,8 @@ pub struct Node {
|
||||
pub connection_chan: Option<Sender<ConnectionInfo>>,
|
||||
|
||||
// user token info
|
||||
pub _token: Mutex<String>,
|
||||
pub network_code: Mutex<String>,
|
||||
// pub _token: Mutex<String>,
|
||||
// pub network_code: Mutex<String>,
|
||||
|
||||
pub device_config: DeviceConfig,
|
||||
pub device: Iface,
|
||||
@ -205,14 +249,33 @@ impl Node {
|
||||
self.nat_type.lock().unwrap().clone()
|
||||
}
|
||||
|
||||
pub async fn start_without_feedback(&self, token: String, network_code: String, hostname: Option<String>) -> Result<()> {
|
||||
pub async fn start_without_feedback(
|
||||
&self,
|
||||
access_token: String,
|
||||
network_id: u32,
|
||||
network_domain: &String,
|
||||
ip_net: u32,
|
||||
ip_net_bit_len: u8,
|
||||
identity_id: u32,
|
||||
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.network_code.lock().unwrap() = network_code;
|
||||
|
||||
self.access_token.set(access_token);
|
||||
self.device_config.ip.net_addr.store(ip_net, Ordering::Relaxed);
|
||||
self.device_config.ip.net_bit_len.store(ip_net_bit_len, Ordering::Relaxed);
|
||||
// *self.device_config.mac.write().unwrap() = create_or_load_mac();
|
||||
self.network_id.store(network_id, Ordering::Relaxed);
|
||||
self.network_domain.write().unwrap().clone_from(network_domain);
|
||||
// self.network_domain = network_domain;
|
||||
|
||||
self.identity_id.store(identity_id);
|
||||
// *self._token.lock().unwrap() = token;
|
||||
// *self.network_code.lock().unwrap() = network_code;
|
||||
let _ = self
|
||||
.start_stop_sender
|
||||
.send(StartStopInfo {
|
||||
@ -225,8 +288,17 @@ impl Node {
|
||||
|
||||
pub async fn start_with_feedback(
|
||||
&self,
|
||||
token: String,
|
||||
network_code: String,
|
||||
|
||||
access_token: String,
|
||||
|
||||
network_id: u32,
|
||||
network_domain: &String,
|
||||
|
||||
ip_net: u32,
|
||||
ip_net_bit_len: u8,
|
||||
identity_id: u32,
|
||||
// token: String,
|
||||
// network_code: String,
|
||||
hostname: Option<String>,
|
||||
timeout: Duration,
|
||||
) -> Result<RegisterSuperFeedback> {
|
||||
@ -235,8 +307,17 @@ impl Node {
|
||||
let _ = save_to_file(&idfile, &host);
|
||||
*self.hostname.write().unwrap() = host;
|
||||
}
|
||||
*self._token.lock().unwrap() = token;
|
||||
*self.network_code.lock().unwrap() = network_code;
|
||||
|
||||
self.access_token.set(access_token);
|
||||
self.device_config.ip.net_addr.store(ip_net, Ordering::Relaxed);
|
||||
self.device_config.ip.net_bit_len.store(ip_net_bit_len, Ordering::Relaxed);
|
||||
// *self.device_config.mac.write().unwrap() = create_or_load_mac();
|
||||
self.network_id.store(network_id, Ordering::Relaxed);
|
||||
self.network_domain.write().unwrap().clone_from(network_domain);
|
||||
|
||||
self.identity_id.store(identity_id);
|
||||
// *self._token.lock().unwrap() = token;
|
||||
// *self.network_code.lock().unwrap() = network_code;
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let id = self.get_next_packet_id();
|
||||
self.packet_id_match.insert(id, tx);
|
||||
@ -265,7 +346,8 @@ impl Node {
|
||||
}
|
||||
|
||||
pub async fn stop(&self) {
|
||||
*self._token.lock().unwrap() = "".to_owned();
|
||||
// *self._token.lock().unwrap() = "".to_owned();
|
||||
self.session_token.set(vec![]);
|
||||
let _ = self
|
||||
.start_stop_sender
|
||||
.send(StartStopInfo {
|
||||
@ -276,13 +358,14 @@ impl Node {
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
mac: Mac,
|
||||
pubkey: String,
|
||||
config: NodeConfig,
|
||||
sock: Socket,
|
||||
multicast_sock: Option<Socket>,
|
||||
// tcpsock: TCPSocket,
|
||||
token: &str,
|
||||
network_code: &str,
|
||||
// token: &str,
|
||||
// network_code: &str,
|
||||
private: RsaPrivateKey,
|
||||
tcp_pong: Arc<AtomicU64>,
|
||||
start_stop: Sender<StartStopInfo>,
|
||||
@ -304,10 +387,18 @@ impl Node {
|
||||
network_id: AtomicU32::new(0),
|
||||
hostname: RwLock::new(hostname),
|
||||
|
||||
network_domain: RwLock::new(String::new()),
|
||||
|
||||
udp_sock_for_dns: udpsock_for_dns,
|
||||
|
||||
_token: Mutex::new(token.to_owned()),
|
||||
network_code: Mutex::new(network_code.to_owned()),
|
||||
quic_endpoint: quic_init(),
|
||||
|
||||
identity_id: IdentityID::new(0),
|
||||
access_token: StringToken::new(String::new()),
|
||||
session_token: StringToken::new(Vec::new()),
|
||||
|
||||
// _token: Mutex::new(token.to_owned()),
|
||||
// network_code: Mutex::new(network_code.to_owned()),
|
||||
|
||||
start_stop_sender: start_stop,
|
||||
connection_chan: connecting_chan,
|
||||
@ -316,7 +407,7 @@ impl Node {
|
||||
|
||||
nat_type: Mutex::new(NatType::Blocked),
|
||||
|
||||
device_config: DeviceConfig::new(mtu),
|
||||
device_config: DeviceConfig::new(mac, mtu),
|
||||
device: new_iface("dev", mode),
|
||||
|
||||
authorized: AtomicBool::new(false),
|
||||
@ -498,9 +589,9 @@ impl Node {
|
||||
|
||||
pub async fn send_unregister_super(&self) -> Result<()> {
|
||||
let content =
|
||||
encode_to_tcp_message::<SdlEmpty>(None, 0, PacketType::UnRegisterSuper as u8).unwrap();
|
||||
encode_to_tcp_message::<SdlEmpty>(None, PacketType::UnRegisterSuper as u8).unwrap();
|
||||
|
||||
let conn = get_tcp_conn();
|
||||
let conn = get_quic_write_conn();
|
||||
let _ = conn.send(content).await;
|
||||
|
||||
Ok(())
|
||||
@ -515,6 +606,7 @@ impl Node {
|
||||
let probe = SdlStunProbe {
|
||||
attr: msgattr as u32,
|
||||
cookie,
|
||||
step: 0,
|
||||
};
|
||||
// println!("==> sending probe request: {:?}", probe);
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
use std::{net::SocketAddr, sync::atomic::Ordering, time::Duration};
|
||||
|
||||
use crate::tcp::NatType;
|
||||
use crate::network::IdentityID;
|
||||
use crate::pb::SdlPolicyRequest;
|
||||
use crate::tcp::{NatType, get_quic_write_conn, is_identity_ok};
|
||||
use crate::{network::TunTapPacketHandler, utils::mac_to_string};
|
||||
|
||||
use crate::{
|
||||
@ -9,10 +11,10 @@ use crate::{
|
||||
encode_to_tcp_message, encode_to_udp_message, SdlData, SdlEmpty, SdlPeerInfo, SdlQueryInfo,
|
||||
SdlRegister, SdlRegisterAck, SdlStunProbeReply,
|
||||
},
|
||||
tcp::{get_tcp_conn, PacketType},
|
||||
tcp::{PacketType},
|
||||
utils::{send_to_sock, Socket},
|
||||
};
|
||||
use etherparse::Ethernet2Header;
|
||||
use etherparse::{Ethernet2Header, PacketHeaders, ip_number};
|
||||
use prost::Message;
|
||||
use sdlan_sn_rs::utils::{BROADCAST_MAC};
|
||||
use sdlan_sn_rs::{
|
||||
@ -24,7 +26,7 @@ use sdlan_sn_rs::{
|
||||
},
|
||||
};
|
||||
|
||||
use tracing::{debug, error, info};
|
||||
use tracing::{debug, error, info, warn};
|
||||
|
||||
use super::{EdgePeer, Node};
|
||||
|
||||
@ -111,6 +113,7 @@ pub async fn handle_packet(eee: &'static Node, addr: SocketAddr, buf: &[u8]) ->
|
||||
error!("failed to convert src mac");
|
||||
return Err(SDLanError::NormalError("failed to convert vec to Mac"));
|
||||
};
|
||||
|
||||
// let from_sock = get_sdlan_sock_from_socketaddr(addr).unwrap();
|
||||
if data.is_p2p {
|
||||
debug!("[P2P] Rx data from {}", from_sock.to_string());
|
||||
@ -818,6 +821,61 @@ pub fn print_hex(key: &[u8]) {
|
||||
println!("[{}]", value.join(" "))
|
||||
}
|
||||
|
||||
async fn renew_identity_request(eee: &Node, identity: u32) {
|
||||
let policy_request = SdlPolicyRequest {
|
||||
pkt_id: eee.get_next_packet_id(),
|
||||
src_identity_id: identity,
|
||||
dst_identity_id: eee.identity_id.load(),
|
||||
version: 1,
|
||||
};
|
||||
|
||||
println!("policy request: {:?}", policy_request);
|
||||
// debug!("send register super: {:?}", register_super);
|
||||
// let packet_id = edge.get_next_packet_id();
|
||||
let data = encode_to_tcp_message(
|
||||
Some(policy_request),
|
||||
PacketType::PolicyRequest as u8,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let stream = get_quic_write_conn();
|
||||
if let Err(e) = stream.send(data).await {
|
||||
error!("failed to write to quic: {}", e.as_str());
|
||||
}
|
||||
}
|
||||
|
||||
async fn check_identity_is_ok(eee: &Node, identity: u32, protocol: u8, port: u16) -> bool{
|
||||
true
|
||||
}
|
||||
|
||||
async fn check_identity_is_ok2(eee: &Node, identity: u32, protocol: u8, port: u16) -> bool{
|
||||
let result = is_identity_ok(identity, protocol, port);
|
||||
if result.1 {
|
||||
renew_identity_request(eee, identity).await;
|
||||
}
|
||||
match result.0 {
|
||||
Some(true) => {
|
||||
// identity is ok
|
||||
true
|
||||
}
|
||||
Some(false) => {
|
||||
// identity is not allowed
|
||||
warn!("identity is not allowed for protocol={:?}, port={}", protocol, port);
|
||||
false
|
||||
}
|
||||
None => {
|
||||
if !result.1 {
|
||||
renew_identity_request(eee, identity).await;
|
||||
} else {
|
||||
// has been sent
|
||||
}
|
||||
false
|
||||
// no such identity, should request for it
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async fn handle_tun_packet(
|
||||
eee: &Node,
|
||||
_from_sock: &SdlanSock,
|
||||
@ -838,7 +896,50 @@ async fn handle_tun_packet(
|
||||
error!("failed to decrypt original data");
|
||||
return;
|
||||
}
|
||||
|
||||
let data = origin.unwrap();
|
||||
let Ok(headers) = PacketHeaders::from_ethernet_slice(&data) else {
|
||||
error!("failed to parse packet");
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
if let Some(ip) = headers.net {
|
||||
match ip {
|
||||
etherparse::NetHeaders::Ipv4(ipv4, _) => {
|
||||
let protocol = ipv4.protocol;
|
||||
match protocol {
|
||||
ip_number::TCP => {
|
||||
let tcp_header = headers.transport.unwrap().tcp().unwrap();
|
||||
let port = tcp_header.destination_port;
|
||||
let src_port = tcp_header.source_port;
|
||||
println!("tcp srcport={}, dstport={}", src_port, port);
|
||||
if !check_identity_is_ok(eee, pkt.identity_id, protocol.0, port).await {
|
||||
return;
|
||||
}
|
||||
}
|
||||
ip_number::UDP => {
|
||||
let udp_header = headers.transport.unwrap().udp().unwrap();
|
||||
let port = udp_header.destination_port;
|
||||
if !check_identity_is_ok(eee, pkt.identity_id, protocol.0, port).await {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_other => {
|
||||
// just ok
|
||||
}
|
||||
}
|
||||
}
|
||||
_other => {
|
||||
// just ignore, ok
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
debug!("sending packet to tun, {} bytes", data.len());
|
||||
if let Err(e) = eee
|
||||
.device
|
||||
.handle_packet_from_net(&data, key.as_slice())
|
||||
@ -1132,27 +1233,28 @@ async fn send_query_peer(eee: &Node, dst_mac: Mac) -> Result<()> {
|
||||
}
|
||||
let query = SdlQueryInfo {
|
||||
dst_mac: Vec::from(dst_mac),
|
||||
pkt_id: 0,
|
||||
};
|
||||
|
||||
let Ok(content) = encode_to_tcp_message(
|
||||
Some(query),
|
||||
eee.get_next_packet_id(),
|
||||
// eee.get_next_packet_id(),
|
||||
PacketType::QueryInfo as u8,
|
||||
) else {
|
||||
error!("failed to encode query");
|
||||
return Err(SDLanError::NormalError("encode query error"));
|
||||
};
|
||||
let tcp_conn = get_tcp_conn();
|
||||
let tcp_conn = get_quic_write_conn();
|
||||
tcp_conn.send(content).await
|
||||
}
|
||||
|
||||
pub async fn ping_to_sn() {
|
||||
let Ok(msg) = encode_to_tcp_message::<SdlEmpty>(None, 0, PacketType::Ping as u8) else {
|
||||
let Ok(msg) = encode_to_tcp_message::<SdlEmpty>(None, PacketType::Ping as u8) else {
|
||||
error!("failed to encode ping");
|
||||
return;
|
||||
};
|
||||
debug!("ping to sn");
|
||||
let tcp_conn = get_tcp_conn();
|
||||
let tcp_conn = get_quic_write_conn();
|
||||
if let Err(e) = tcp_conn.send(msg).await {
|
||||
error!("failed to ping to sn: {:?}", e);
|
||||
}
|
||||
|
||||
@ -154,9 +154,12 @@ impl Iface {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: set dns should be opened
|
||||
/*
|
||||
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")
|
||||
@ -220,10 +223,48 @@ impl TunTapPacketHandler for Iface {
|
||||
};
|
||||
|
||||
if let Some(eth) = headers.link {
|
||||
use etherparse::EtherType;
|
||||
|
||||
if let Some(hdr) = eth.ethernet2() {
|
||||
use bytes::Bytes;
|
||||
|
||||
if hdr.ether_type == EtherType::ARP {
|
||||
use crate::network::{ARP_REPLY, ARP_REQUEST, ArpHdr};
|
||||
|
||||
let arp = ArpHdr::from_slice(&data);
|
||||
match arp.opcode {
|
||||
ARP_REQUEST => {
|
||||
use crate::{network::ArpRequest, pb::{SdlArpRequest, encode_to_tcp_message}, tcp::get_quic_write_conn};
|
||||
let dest_ip = ((arp.dipaddr[0] as u32) << 16) + arp.dipaddr[1] as u32;
|
||||
|
||||
let request = SdlArpRequest {
|
||||
pkt_id: edge.get_next_packet_id(),
|
||||
target_ip: dest_ip,
|
||||
};
|
||||
|
||||
let req = encode_to_tcp_message(Some(request), PacketType::ArpRequest as u8).unwrap();
|
||||
let conn = get_quic_write_conn();
|
||||
debug!("sending arp request");
|
||||
let _ = conn.send(req).await;
|
||||
return Ok(());
|
||||
}
|
||||
_other => {
|
||||
// just do the following logic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ip) = headers.net {
|
||||
match ip {
|
||||
etherparse::NetHeaders::Ipv4(ipv4, _) => {
|
||||
use etherparse::ip_number::{self, ICMP};
|
||||
|
||||
|
||||
if let Some(transport) = headers.transport {
|
||||
if let Some(tcp) = transport.tcp() {
|
||||
// is tcp
|
||||
}
|
||||
}
|
||||
|
||||
if u32::from_be_bytes(ipv4.destination) == DNS_IP {
|
||||
// should send to dns
|
||||
@ -251,13 +292,16 @@ impl TunTapPacketHandler for Iface {
|
||||
error!("failed to encrypt packet request");
|
||||
return Ok(());
|
||||
};
|
||||
let data_bytes = Bytes::from(encrypted);
|
||||
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),
|
||||
data: data_bytes,
|
||||
identity_id: edge.identity_id.load(),
|
||||
session_token: edge.session_token.get(),
|
||||
};
|
||||
let msg = encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap();
|
||||
|
||||
@ -331,6 +375,7 @@ impl TunTapPacketHandler for Iface {
|
||||
return Ok(());
|
||||
}
|
||||
if dest_ip == self_ip {
|
||||
use bytes::Bytes;
|
||||
use sdlan_sn_rs::utils::mac_to_string;
|
||||
|
||||
use crate::network::{ARP_REPLY, ArpRequestInfo, send_arp_request};
|
||||
@ -359,13 +404,17 @@ impl TunTapPacketHandler for Iface {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let data_bytes = Bytes::from(encrypted);
|
||||
|
||||
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,
|
||||
data: data_bytes,
|
||||
session_token: edge.session_token.get(),
|
||||
identity_id: edge.identity_id.load(),
|
||||
};
|
||||
|
||||
let v = encode_to_udp_message(Some(data), PacketType::Data as u8)
|
||||
@ -492,6 +541,8 @@ impl TunTapPacketHandler for Iface {
|
||||
ip,
|
||||
do_arp_request,
|
||||
} => {
|
||||
use bytes::Bytes;
|
||||
|
||||
use crate::utils::caculate_crc;
|
||||
|
||||
if do_arp_request {
|
||||
@ -518,7 +569,9 @@ impl TunTapPacketHandler for Iface {
|
||||
dst_mac: Vec::from([0xff; 6]),
|
||||
is_p2p: true,
|
||||
ttl: SDLAN_DEFAULT_TTL as u32,
|
||||
data: encrypted,
|
||||
data: Bytes::from(encrypted),
|
||||
session_token: eee.session_token.get(),
|
||||
identity_id: eee.identity_id.load(),
|
||||
};
|
||||
let data =
|
||||
encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap();
|
||||
@ -555,7 +608,9 @@ impl TunTapPacketHandler for Iface {
|
||||
ttl: SDLAN_DEFAULT_TTL as u32,
|
||||
src_mac: Vec::from(src_mac),
|
||||
dst_mac: Vec::from(mac),
|
||||
data: Vec::from(encrypted),
|
||||
data: Bytes::from(encrypted),
|
||||
session_token: eee.session_token.get(),
|
||||
identity_id: eee.identity_id.load(),
|
||||
};
|
||||
let msg =
|
||||
encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap();
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use bytes::Bytes;
|
||||
use etherparse::ether_type::ARP;
|
||||
use etherparse::{Ethernet2Header, IpHeaders};
|
||||
use sdlan_sn_rs::config::SDLAN_DEFAULT_TTL;
|
||||
@ -209,7 +210,9 @@ impl TunTapPacketHandler for Iface {
|
||||
network_id: edge.network_id.load(Ordering::Relaxed),
|
||||
src_mac: Vec::from(self_mac),
|
||||
dst_mac: Vec::from(arp.dhwaddr),
|
||||
data: encrypted,
|
||||
data: Bytes::from(encrypted),
|
||||
session_token: edge.session_token.get(),
|
||||
identity_id: edge.identity_id.load(),
|
||||
};
|
||||
|
||||
let v = encode_to_udp_message(Some(data), PacketType::Data as u8)
|
||||
@ -344,7 +347,10 @@ impl TunTapPacketHandler for Iface {
|
||||
dst_mac: Vec::from([0xff; 6]),
|
||||
is_p2p: true,
|
||||
ttl: SDLAN_DEFAULT_TTL as u32,
|
||||
data: encrypted,
|
||||
data: Bytes::from(encrypted),
|
||||
|
||||
session_token: eee.session_token.get(),
|
||||
identity_id: eee.identity_id.load(),
|
||||
};
|
||||
let data =
|
||||
encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap();
|
||||
@ -384,7 +390,9 @@ impl TunTapPacketHandler for Iface {
|
||||
ttl: SDLAN_DEFAULT_TTL as u32,
|
||||
src_mac: Vec::from(src_mac),
|
||||
dst_mac: Vec::from(mac),
|
||||
data: Vec::from(encrypted),
|
||||
data: Bytes::from(encrypted),
|
||||
session_token: eee.session_token.get(),
|
||||
identity_id: eee.identity_id.load(),
|
||||
};
|
||||
let msg =
|
||||
encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap();
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use bytes::Bytes;
|
||||
use dashmap::DashMap;
|
||||
use once_cell::sync::OnceCell;
|
||||
use sdlan_sn_rs::{
|
||||
@ -91,13 +92,16 @@ impl ArpWaitList {
|
||||
error!("failed to encrypt packet request");
|
||||
return;
|
||||
};
|
||||
let data_bytes = Bytes::from(encrypted);
|
||||
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),
|
||||
data: data_bytes,
|
||||
identity_id: edge.identity_id.load(),
|
||||
session_token: edge.session_token.get(),
|
||||
};
|
||||
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;
|
||||
|
||||
@ -17,83 +17,148 @@ pub struct Sdlv6Info {
|
||||
#[prost(bytes = "vec", tag = "2")]
|
||||
pub v6: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
/// 设备网络地址信息
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlDevAddr {
|
||||
pub struct SdlWelcome {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub network_id: u32,
|
||||
#[prost(bytes = "vec", tag = "2")]
|
||||
pub mac: ::prost::alloc::vec::Vec<u8>,
|
||||
pub version: u32,
|
||||
/// 服务器允许的最大双向流
|
||||
#[prost(uint32, tag = "2")]
|
||||
pub max_bidi_streams: u32,
|
||||
/// 服务器允许的最大包
|
||||
#[prost(uint32, tag = "3")]
|
||||
pub net_addr: u32,
|
||||
pub max_packet_size: u32,
|
||||
/// 心跳包的间隔
|
||||
#[prost(uint32, tag = "4")]
|
||||
pub net_bit_len: u32,
|
||||
#[prost(string, tag = "5")]
|
||||
pub network_domain: ::prost::alloc::string::String,
|
||||
pub heartbeat_sec: u32,
|
||||
}
|
||||
/// tcp通讯消息
|
||||
/// quic 通讯消息
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlEmpty {}
|
||||
pub struct SdlEmpty {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub pkt_id: u32,
|
||||
}
|
||||
/// 这里修改成了扁平的结构, 否则有些字段不好找放的位置
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlRegisterSuper {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub version: u32,
|
||||
pub pkt_id: u32,
|
||||
#[prost(string, tag = "2")]
|
||||
pub installed_channel: ::prost::alloc::string::String,
|
||||
#[prost(string, tag = "3")]
|
||||
pub client_id: ::prost::alloc::string::String,
|
||||
#[prost(message, optional, tag = "4")]
|
||||
pub dev_addr: ::core::option::Option<SdlDevAddr>,
|
||||
#[prost(string, tag = "5")]
|
||||
pub pub_key: ::prost::alloc::string::String,
|
||||
#[prost(string, tag = "6")]
|
||||
pub token: ::prost::alloc::string::String,
|
||||
/// 网络地址信息已经有https请求分配了
|
||||
/// 注册的时候需要带上(network_id, mac, ip, mask_len, hostname)
|
||||
#[prost(uint32, tag = "3")]
|
||||
pub network_id: u32,
|
||||
#[prost(bytes = "vec", tag = "4")]
|
||||
pub mac: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(uint32, tag = "5")]
|
||||
pub ip: u32,
|
||||
#[prost(uint32, tag = "6")]
|
||||
pub mask_len: u32,
|
||||
#[prost(string, tag = "7")]
|
||||
pub network_code: ::prost::alloc::string::String,
|
||||
#[prost(string, tag = "8")]
|
||||
pub hostname: ::prost::alloc::string::String,
|
||||
#[prost(string, tag = "8")]
|
||||
pub pub_key: ::prost::alloc::string::String,
|
||||
/// 客户端使用http协议请求后端,通过token或者账号密码登录时, 统一返回一个access_token;
|
||||
/// RegisterSuper的时候,验证凭证是否合法 (access_token)
|
||||
#[prost(string, tag = "9")]
|
||||
pub access_token: ::prost::alloc::string::String,
|
||||
}
|
||||
/// 客户端的升级逻辑,在https的接口里面去完成
|
||||
/// 部分逻辑会脱离quic去通讯,增加session_token校验
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlRegisterSuperAck {
|
||||
#[prost(message, optional, tag = "1")]
|
||||
pub dev_addr: ::core::option::Option<SdlDevAddr>,
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub pkt_id: u32,
|
||||
#[prost(bytes = "vec", tag = "2")]
|
||||
pub aes_key: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(uint32, tag = "3")]
|
||||
pub upgrade_type: u32,
|
||||
#[prost(string, optional, tag = "4")]
|
||||
pub upgrade_prompt: ::core::option::Option<::prost::alloc::string::String>,
|
||||
#[prost(string, optional, tag = "5")]
|
||||
pub upgrade_address: ::core::option::Option<::prost::alloc::string::String>,
|
||||
#[prost(bytes = "vec", tag = "3")]
|
||||
pub session_token: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlRegisterSuperNak {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub pkt_id: u32,
|
||||
#[prost(uint32, tag = "2")]
|
||||
pub error_code: u32,
|
||||
#[prost(string, tag = "2")]
|
||||
#[prost(string, tag = "3")]
|
||||
pub error_message: ::prost::alloc::string::String,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlQueryInfo {
|
||||
#[prost(bytes = "vec", tag = "1")]
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub pkt_id: u32,
|
||||
#[prost(bytes = "vec", tag = "2")]
|
||||
pub dst_mac: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlPeerInfo {
|
||||
#[prost(bytes = "vec", tag = "1")]
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub pkt_id: u32,
|
||||
#[prost(bytes = "vec", tag = "2")]
|
||||
pub dst_mac: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(message, optional, tag = "2")]
|
||||
pub v4_info: ::core::option::Option<Sdlv4Info>,
|
||||
#[prost(message, optional, tag = "3")]
|
||||
pub v4_info: ::core::option::Option<Sdlv4Info>,
|
||||
#[prost(message, optional, tag = "4")]
|
||||
pub v6_info: ::core::option::Option<Sdlv6Info>,
|
||||
}
|
||||
/// ARP查询相关
|
||||
/// 真实的arp请求是通过广播的形式获取到的,但是针对于macos这种tun的实现;是能够分析出arp请求包的;
|
||||
/// 对于当前网络来说,服务端是知道mac对应的ip地址的,因此没有必要广播;直接通过服务器端返回
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlArpRequest {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub pkt_id: u32,
|
||||
#[prost(uint32, tag = "2")]
|
||||
pub target_ip: u32,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlArpResponse {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub pkt_id: u32,
|
||||
#[prost(uint32, tag = "2")]
|
||||
pub target_ip: u32,
|
||||
#[prost(bytes = "vec", tag = "3")]
|
||||
pub target_mac: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
/// 权限请求查询相关
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlPolicyRequest {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub pkt_id: u32,
|
||||
#[prost(uint32, tag = "2")]
|
||||
pub src_identity_id: u32,
|
||||
#[prost(uint32, tag = "3")]
|
||||
pub dst_identity_id: u32,
|
||||
#[prost(uint32, tag = "4")]
|
||||
pub version: u32,
|
||||
}
|
||||
/// 基于quic通讯,rules部分已经没有了长度限制
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlPolicyResponse {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub pkt_id: u32,
|
||||
#[prost(uint32, tag = "2")]
|
||||
pub src_identity_id: u32,
|
||||
#[prost(uint32, tag = "3")]
|
||||
pub dst_identity_id: u32,
|
||||
/// 版本号,客户端需要比较版本号确定是否覆盖; 请求端自己去管理版本号,服务端只是原样回写
|
||||
#[prost(uint32, tag = "4")]
|
||||
pub version: u32,
|
||||
/// 4+1+2 的稀疏序列化规则
|
||||
#[prost(bytes = "vec", tag = "5")]
|
||||
pub rules: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlNatChangedEvent {
|
||||
@ -122,36 +187,7 @@ pub struct SdlNetworkShutdownEvent {
|
||||
#[prost(string, tag = "1")]
|
||||
pub message: ::prost::alloc::string::String,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlChangeNetworkCommand {
|
||||
#[prost(message, optional, tag = "1")]
|
||||
pub dev_addr: ::core::option::Option<SdlDevAddr>,
|
||||
#[prost(bytes = "vec", tag = "2")]
|
||||
pub aes_key: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlCommandAck {
|
||||
/// status = true, 表示成功;status = false 表示失败,message是失败原因描述
|
||||
#[prost(bool, tag = "1")]
|
||||
pub status: bool,
|
||||
#[prost(string, optional, tag = "2")]
|
||||
pub message: ::core::option::Option<::prost::alloc::string::String>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlFlows {
|
||||
/// 服务器转发流量
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub forward_num: u32,
|
||||
/// p2p直接流量
|
||||
#[prost(uint32, tag = "2")]
|
||||
pub p2p_num: u32,
|
||||
/// 接收的流量
|
||||
#[prost(uint32, tag = "3")]
|
||||
pub inbound_num: u32,
|
||||
}
|
||||
/// client和stun之间的心跳包,客户端需要和super的udp之间的存活逻辑
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlStunRequest {
|
||||
@ -169,6 +205,8 @@ pub struct SdlStunRequest {
|
||||
pub nat_type: u32,
|
||||
#[prost(message, optional, tag = "7")]
|
||||
pub v6_info: ::core::option::Option<Sdlv6Info>,
|
||||
#[prost(bytes = "vec", tag = "8")]
|
||||
pub session_token: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
@ -189,8 +227,38 @@ pub struct SdlData {
|
||||
pub is_p2p: bool,
|
||||
#[prost(uint32, tag = "5")]
|
||||
pub ttl: u32,
|
||||
#[prost(bytes = "vec", tag = "6")]
|
||||
pub data: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(bytes = "bytes", tag = "6")]
|
||||
pub data: ::prost::bytes::Bytes,
|
||||
#[prost(bytes = "vec", tag = "7")]
|
||||
pub session_token: ::prost::alloc::vec::Vec<u8>,
|
||||
/// 端通过https登录的时候,服务端会分配该端对应的权限标识
|
||||
/// 后续的请求过程中需要带上这个值,对端通过这个值要判断对数据包是否放行
|
||||
#[prost(uint32, tag = "8")]
|
||||
pub identity_id: u32,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlStunProbe {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub cookie: u32,
|
||||
#[prost(uint32, tag = "2")]
|
||||
pub attr: u32,
|
||||
/// 增加step是为了方便端上判断,收到的请求和响应之间的映射关系;服务器端原样返回
|
||||
#[prost(uint32, tag = "3")]
|
||||
pub step: u32,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlStunProbeReply {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub cookie: u32,
|
||||
/// 增加step是为了方便端上判断,收到的请求和响应之间的映射关系;服务器端原样返回
|
||||
#[prost(uint32, tag = "2")]
|
||||
pub step: u32,
|
||||
#[prost(uint32, tag = "3")]
|
||||
pub port: u32,
|
||||
#[prost(uint32, tag = "4")]
|
||||
pub ip: u32,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
@ -212,21 +280,3 @@ pub struct SdlRegisterAck {
|
||||
#[prost(bytes = "vec", tag = "3")]
|
||||
pub dst_mac: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlStunProbe {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub cookie: u32,
|
||||
#[prost(uint32, tag = "2")]
|
||||
pub attr: u32,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SdlStunProbeReply {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub cookie: u32,
|
||||
#[prost(uint32, tag = "2")]
|
||||
pub port: u32,
|
||||
#[prost(uint32, tag = "3")]
|
||||
pub ip: u32,
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ use sdlan_sn_rs::utils::Result;
|
||||
// tcp message has two-byte of size at header
|
||||
pub fn encode_to_tcp_message<T: Message>(
|
||||
msg: Option<T>,
|
||||
packet_id: u32,
|
||||
// _packet_id: u32,
|
||||
packet_type: u8,
|
||||
) -> Result<Vec<u8>> {
|
||||
let mut raw_data = Vec::new();
|
||||
@ -16,10 +16,10 @@ pub fn encode_to_tcp_message<T: Message>(
|
||||
msg.encode(&mut raw_data)?;
|
||||
}
|
||||
|
||||
let mut result = Vec::with_capacity(raw_data.len() + 7);
|
||||
let size = u16::to_be_bytes(raw_data.len() as u16 + 5);
|
||||
let mut result = Vec::with_capacity(raw_data.len() + 3);
|
||||
let size = u16::to_be_bytes(raw_data.len() as u16 + 1);
|
||||
result.extend_from_slice(&size);
|
||||
result.extend_from_slice(&u32::to_be_bytes(packet_id));
|
||||
// result.extend_from_slice(&u32::to_be_bytes(packet_id));
|
||||
result.push(packet_type);
|
||||
result.extend_from_slice(&raw_data);
|
||||
Ok(result)
|
||||
|
||||
76
src/quic/mod.rs
Normal file
76
src/quic/mod.rs
Normal file
@ -0,0 +1,76 @@
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use quinn::Endpoint;
|
||||
use quinn::crypto::rustls::QuicClientConfig;
|
||||
use rustls::crypto::CryptoProvider;
|
||||
use rustls::crypto::ring;
|
||||
use rustls::pki_types::CertificateDer;
|
||||
use rustls::pki_types::PrivateKeyDer;
|
||||
|
||||
use rustls::pki_types::ServerName;
|
||||
use rustls_pemfile::{certs, private_key};
|
||||
|
||||
pub fn quic_init() -> Endpoint {
|
||||
let default_provider = ring::default_provider();
|
||||
CryptoProvider::install_default(default_provider).unwrap();
|
||||
|
||||
let certificate_chain = load_certs_from_pem("./ca/ca.crt").unwrap();
|
||||
let mut root_store = rustls::RootCertStore::empty();
|
||||
for cert in certificate_chain {
|
||||
root_store.add(cert).unwrap();
|
||||
}
|
||||
|
||||
let mut rustls_config = rustls::ClientConfig::builder()
|
||||
.dangerous()
|
||||
.with_custom_certificate_verifier(Arc::new(SkipServerVerification{}))
|
||||
.with_no_client_auth();
|
||||
|
||||
rustls_config.alpn_protocols = vec![b"punchnet/1.0".to_vec()];
|
||||
|
||||
let quinn_client_config = quinn::ClientConfig::new(Arc::new(QuicClientConfig::try_from(rustls_config).unwrap()));
|
||||
|
||||
let mut endpoint = Endpoint::client("0.0.0.0:0".parse().unwrap()).unwrap();
|
||||
endpoint.set_default_client_config(quinn_client_config);
|
||||
|
||||
endpoint
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SkipServerVerification;
|
||||
impl rustls::client::danger::ServerCertVerifier for SkipServerVerification {
|
||||
fn verify_server_cert(&self, _: &CertificateDer<'_>, _: &[CertificateDer<'_>], _: &ServerName<'_>, _: &[u8], _: rustls::pki_types::UnixTime) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
|
||||
Ok(rustls::client::danger::ServerCertVerified::assertion())
|
||||
}
|
||||
fn verify_tls12_signature(&self, _: &[u8], _: &CertificateDer<'_>, _: &rustls::DigitallySignedStruct) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
|
||||
Ok(rustls::client::danger::HandshakeSignatureValid::assertion())
|
||||
}
|
||||
fn verify_tls13_signature(&self, _: &[u8], _: &CertificateDer<'_>, _: &rustls::DigitallySignedStruct) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
|
||||
Ok(rustls::client::danger::HandshakeSignatureValid::assertion())
|
||||
}
|
||||
fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
|
||||
rustls::crypto::ring::default_provider().signature_verification_algorithms.supported_schemes()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_certs_from_pem(path: impl AsRef<Path>) -> Result<Vec<CertificateDer<'static>>, Box<dyn std::error::Error>> {
|
||||
let file = File::open(path.as_ref())?;
|
||||
let mut reader = BufReader::new(file);
|
||||
let certs = certs(&mut reader)
|
||||
.into_iter()
|
||||
.map(|it| it.unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok(certs)
|
||||
}
|
||||
|
||||
pub fn load_private_key_from_pem(path: impl AsRef<Path>) -> Option<PrivateKeyDer<'static>>{
|
||||
let Ok(file) = File::open(path.as_ref()) else {
|
||||
return None;
|
||||
};
|
||||
let mut reader = BufReader::new(file);
|
||||
let key = private_key(&mut reader).unwrap();
|
||||
key
|
||||
}
|
||||
74
src/tcp/identity_cache.rs
Normal file
74
src/tcp/identity_cache.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use std::{collections::{HashMap, HashSet}, sync::{OnceLock, atomic::{AtomicU64, Ordering}}, time::{SystemTime, UNIX_EPOCH}};
|
||||
|
||||
use dashmap::{DashMap, DashSet};
|
||||
use tracing::debug;
|
||||
|
||||
type IdentityID = u32;
|
||||
type Port = u16;
|
||||
type Proto = u8;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RuleInfo {
|
||||
pub proto: Proto,
|
||||
pub port: Port,
|
||||
}
|
||||
|
||||
static RULE_CACHE: OnceLock<DashMap<IdentityID, (u64, HashMap<Port, HashSet<Proto>>)>> = OnceLock::new();
|
||||
|
||||
// static RULE_CACHE: OnceLock<DashMap<IdentityID, HashMap<Port, HashMap<Proto, AtomicU64>>>> = OnceLock::new();
|
||||
|
||||
pub fn init_identity_cache() {
|
||||
RULE_CACHE.set(DashMap::new()).unwrap();
|
||||
}
|
||||
|
||||
pub fn set_identity_cache(identity: IdentityID, infos: Vec<RuleInfo>) {
|
||||
debug!("setting identity cache for identity={}, infos: {:?}", identity, infos);
|
||||
|
||||
let cache = RULE_CACHE.get().expect("should set first");
|
||||
let mut temp = HashMap::new();
|
||||
|
||||
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
|
||||
|
||||
for info in &infos {
|
||||
let mut protomap = HashSet::new();
|
||||
protomap.insert(info.proto);
|
||||
temp.insert(info.port, protomap);
|
||||
}
|
||||
cache.remove(&identity);
|
||||
cache.insert(identity, (now, temp));
|
||||
}
|
||||
|
||||
// result.1 is should renew
|
||||
pub fn is_identity_ok(identity: IdentityID, proto: Proto, port: Port) -> (Option<bool>, bool) {
|
||||
let cache = RULE_CACHE.get().expect("should set first");
|
||||
let mut should_renew = false;
|
||||
let result: Option<bool>;
|
||||
match cache.get(&identity) {
|
||||
Some(data) => {
|
||||
let tm = data.0;
|
||||
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
|
||||
if tm + 10 < now {
|
||||
should_renew = true;
|
||||
}
|
||||
|
||||
if let Some(proto_info) = data.1.get(&port) {
|
||||
if let Some(_has) = proto_info.get(&proto) {
|
||||
result = Some(true);
|
||||
// return Some(true);
|
||||
} else {
|
||||
result = Some(false);
|
||||
}
|
||||
} else {
|
||||
result = Some(false);
|
||||
|
||||
}
|
||||
}
|
||||
None => {
|
||||
result = None;
|
||||
}
|
||||
}
|
||||
|
||||
return (result, should_renew);
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,12 @@
|
||||
mod tcp_codec;
|
||||
mod tcp_conn;
|
||||
// mod tcp_conn;
|
||||
mod quic;
|
||||
|
||||
mod identity_cache;
|
||||
|
||||
pub use tcp_codec::*;
|
||||
pub use tcp_conn::*;
|
||||
pub use quic::*;
|
||||
pub use identity_cache::*;
|
||||
|
||||
|
||||
// pub use tcp_conn::*;
|
||||
|
||||
723
src/tcp/quic.rs
Normal file
723
src/tcp/quic.rs
Normal file
@ -0,0 +1,723 @@
|
||||
use std::{net::IpAddr, sync::{Arc, OnceLock, atomic::{AtomicBool, AtomicU64, Ordering}}, time::Duration};
|
||||
|
||||
use futures_util::pin_mut;
|
||||
use prost::Message;
|
||||
use quinn::SendStream;
|
||||
use sdlan_sn_rs::{config::AF_INET, peer::{SdlanSock, V6Info}, utils::{Result, SDLanError, get_current_timestamp, ip_to_string, rsa_decrypt}};
|
||||
use tokio::{sync::mpsc::{Receiver, Sender, channel}};
|
||||
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::{debug, error};
|
||||
|
||||
use crate::{ConnectionInfo, ConnectionState, config::{NULL_MAC, TCP_PING_TIME}, get_edge, network::{ARP_REPLY, ArpHdr, EthHdr, Node, RegisterSuperFeedback, StartStopInfo, check_peer_registration_needed, handle_packet_peer_info}, pb::{SdlArpResponse, SdlPolicyResponse, SdlRegisterSuper, SdlRegisterSuperAck, SdlRegisterSuperNak, SdlSendRegisterEvent, encode_to_tcp_message}, tcp::{EventType, NakMsgCode, NatType, PacketType, RuleInfo, SdlanTcp, read_a_packet, send_stun_request, set_identity_cache}};
|
||||
|
||||
static GLOBAL_QUIC_HANDLE: OnceLock<ReadWriterHandle> = OnceLock::new();
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ReadWriterHandle {
|
||||
connected: Arc<AtomicBool>,
|
||||
send_to_tcp: Sender<Vec<u8>>,
|
||||
// pub data_from_tcp: Receiver<SdlanTcp>,
|
||||
}
|
||||
|
||||
impl ReadWriterHandle {
|
||||
pub async fn send(&self, data: Vec<u8>) -> Result<()> {
|
||||
if self.connected.load(Ordering::Relaxed) {
|
||||
// connected, send to it
|
||||
if let Err(e) = self.send_to_tcp.send(data).await {
|
||||
error!("failed to send to send_to_tcp: {}", e.to_string());
|
||||
return Err(SDLanError::NormalError("failed to send"));
|
||||
};
|
||||
debug!("tcp info sent");
|
||||
} else {
|
||||
error!("tcp not connected, so not sending data");
|
||||
return Err(SDLanError::NormalError("not connected, so not sending"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn new<>(
|
||||
cancel: CancellationToken,
|
||||
addr: &str,
|
||||
// on_connected: OnConnectedCallback<'a>,
|
||||
// on_disconnected: T3,
|
||||
// on_message: T2,
|
||||
pong_time: Arc<AtomicU64>,
|
||||
start_stop_chan: Receiver<StartStopInfo>,
|
||||
// cancel: CancellationToken,
|
||||
connecting_chan: Option<Sender<ConnectionInfo>>,
|
||||
ipv6_network_restarter: Option<Sender<bool>>,
|
||||
) -> Self {
|
||||
let (send_to_tcp, to_tcp) = channel(20);
|
||||
let (from_tcp, mut data_from_tcp) = channel(20);
|
||||
|
||||
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,
|
||||
);
|
||||
tokio::spawn(async move {
|
||||
actor
|
||||
.run(
|
||||
true,
|
||||
to_tcp,
|
||||
// on_connected,
|
||||
// on_disconnected,
|
||||
start_stop_chan
|
||||
)
|
||||
.await
|
||||
});
|
||||
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
if let Some(msg) = data_from_tcp.recv().await {
|
||||
handle_tcp_message(msg).await;
|
||||
} else {
|
||||
error!("data from tcp exited");
|
||||
// eprintln!("data from tcp exited");
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ReadWriterHandle {
|
||||
connected,
|
||||
send_to_tcp,
|
||||
// data_from_tcp,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_quic_write_conn() -> &'static ReadWriterHandle {
|
||||
match GLOBAL_QUIC_HANDLE.get() {
|
||||
Some(v) => v,
|
||||
None => panic!("should call init_tcp_conn first"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 => {
|
||||
let Ok(ack) = SdlRegisterSuperAck::decode(&msg.current_packet[..]) else {
|
||||
error!("failed to decode REGISTER_SUPER_ACK");
|
||||
return;
|
||||
};
|
||||
|
||||
edge.send_register_super_feedback(
|
||||
ack.pkt_id,
|
||||
RegisterSuperFeedback {
|
||||
result: 0,
|
||||
message: "".to_owned(),
|
||||
should_exit: false,
|
||||
},
|
||||
);
|
||||
debug!("got register super ack: {:?}", ack);
|
||||
edge.session_token.set(ack.session_token);
|
||||
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(&edge.device_config.get_ip());
|
||||
// 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.network_id.store(dev.network_id, Ordering::Relaxed);
|
||||
*/
|
||||
// edge.device.reload_config(&edge.device_config, &dev.network_domain);
|
||||
edge.device.reload_config(&edge.device_config, &edge.network_domain.read().unwrap().clone());
|
||||
|
||||
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::ArpResponse => {
|
||||
let Ok(resp) = SdlArpResponse::decode(&msg.current_packet[..]) else {
|
||||
error!("failed to decode ARP RESPONSE");
|
||||
return;
|
||||
};
|
||||
if resp.target_mac.len() != 6 {
|
||||
// invalid target_mac
|
||||
error!("invalid target_mac");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: construct the arp reply, and write to tun;
|
||||
let src_mac = resp.target_mac.try_into().unwrap();
|
||||
let dst_mac = edge.device_config.get_mac();
|
||||
let dst_ip = edge.device_config.get_ip();
|
||||
|
||||
let hdr = ArpHdr{
|
||||
ethhdr: EthHdr {
|
||||
dest: dst_mac,
|
||||
src: src_mac,
|
||||
eth_type: 0x0806,
|
||||
},
|
||||
hwtype: 0x0001,
|
||||
protocol: 0x0800,
|
||||
hwlen: 6,
|
||||
protolen: 4,
|
||||
opcode: ARP_REPLY,
|
||||
shwaddr: src_mac,
|
||||
sipaddr: [((resp.target_ip >> 16) as u16) & 0xffff, (resp.target_ip as u16) & 0xffff],
|
||||
dhwaddr: dst_mac,
|
||||
dipaddr: [((dst_ip >> 16) & 0x0000ffff) as u16, (dst_ip & 0x0000ffff) as u16]
|
||||
};
|
||||
|
||||
let data = hdr.marshal_to_bytes();
|
||||
if let Err(e) = edge.device.send(&data) {
|
||||
error!("failed to write arp response to device");
|
||||
}
|
||||
}
|
||||
PacketType::PolicyReply => {
|
||||
let Ok(policy) = SdlPolicyResponse::decode(&msg.current_packet[..]) else {
|
||||
error!("failed to decode POLICY RESPONSE");
|
||||
return;
|
||||
};
|
||||
let identity = policy.src_identity_id;
|
||||
let mut infos = Vec::new();
|
||||
let mut start = 0;
|
||||
while start < policy.rules.len() {
|
||||
if start + 3 > policy.rules.len() {
|
||||
break;
|
||||
}
|
||||
let proto = policy.rules[start];
|
||||
let port = u16::from_be_bytes([policy.rules[start+1], policy.rules[start+2]]);
|
||||
start += 3;
|
||||
|
||||
infos.push(RuleInfo{
|
||||
proto,
|
||||
port,
|
||||
});
|
||||
}
|
||||
|
||||
set_identity_cache(identity, infos);
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
error!("got nak: {:?}", _nak);
|
||||
let pkt_id = _nak.pkt_id;
|
||||
|
||||
let Ok(error_code) = NakMsgCode::try_from(_nak.error_code as u8) else {
|
||||
edge.send_register_super_feedback(
|
||||
//msg._packet_id,
|
||||
pkt_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,
|
||||
pkt_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,
|
||||
pkt_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,
|
||||
pkt_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 fn init_quic_conn(
|
||||
cancel: CancellationToken,
|
||||
addr: &str,
|
||||
// on_connected: OnConnectedCallback<'a>,
|
||||
// on_disconnected: T3,
|
||||
// on_message: T2,
|
||||
pong_time: Arc<AtomicU64>,
|
||||
// cancel: CancellationToken,
|
||||
start_stop_chan: Receiver<StartStopInfo>,
|
||||
connecting_chan: Option<Sender<ConnectionInfo>>,
|
||||
ipv6_network_restarter: Option<Sender<bool>>,
|
||||
)
|
||||
// T2: Fn(SdlanTcp) -> F + Send + 'static,
|
||||
// F: Future<Output = ()> + Send,
|
||||
{
|
||||
let tcp_handle = ReadWriterHandle::new(
|
||||
cancel,
|
||||
addr,
|
||||
// on_connected,
|
||||
// on_disconnected,
|
||||
// on_message,
|
||||
pong_time,
|
||||
start_stop_chan,
|
||||
connecting_chan,
|
||||
ipv6_network_restarter,
|
||||
);
|
||||
|
||||
GLOBAL_QUIC_HANDLE
|
||||
.set(tcp_handle)
|
||||
.expect("failed to set global tcp handle");
|
||||
}
|
||||
|
||||
pub struct ReadWriteActor {
|
||||
// actor接收的发送给tcp的接收端,由handle存放发送端
|
||||
// to_tcp: Receiver<Vec<u8>>,
|
||||
remote: String,
|
||||
connected: Arc<AtomicBool>,
|
||||
pong_time: Arc<AtomicU64>,
|
||||
// actor收到数据之后,发送给上层的发送端口,接收端由handle保存
|
||||
from_tcp: Sender<SdlanTcp>,
|
||||
_cancel: CancellationToken,
|
||||
connecting_chan: Option<Sender<ConnectionInfo>>,
|
||||
ipv6_network_restarter: Option<Sender<bool>>,
|
||||
}
|
||||
|
||||
impl ReadWriteActor {
|
||||
pub fn new(
|
||||
cancel: CancellationToken,
|
||||
remote: &str,
|
||||
from_tcp: Sender<SdlanTcp>,
|
||||
connected: Arc<AtomicBool>,
|
||||
pong_time: Arc<AtomicU64>,
|
||||
connecting_chan: Option<Sender<ConnectionInfo>>,
|
||||
ipv6_network_restarter: Option<Sender<bool>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
// to_tcp,
|
||||
_cancel: cancel,
|
||||
pong_time,
|
||||
connected,
|
||||
remote: remote.to_owned(),
|
||||
from_tcp,
|
||||
connecting_chan,
|
||||
ipv6_network_restarter,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run<'a>(
|
||||
&self,
|
||||
keep_reconnect: bool,
|
||||
mut to_tcp: Receiver<Vec<u8>>,
|
||||
mut start_stop_chan: Receiver<StartStopInfo>,
|
||||
) {
|
||||
let edge = get_edge();
|
||||
|
||||
let mut started = false;
|
||||
let mut start_pkt_id = None;
|
||||
loop {
|
||||
if let Some(ref connecting_chan) = self.connecting_chan {
|
||||
let state = ConnectionInfo::ConnState(ConnectionState::NotConnected);
|
||||
let _ = connecting_chan.send(state).await;
|
||||
}
|
||||
self.connected.store(false, Ordering::Relaxed);
|
||||
if !started {
|
||||
// println!("waiting for start");
|
||||
loop {
|
||||
let start_or_stop = start_stop_chan.recv().await;
|
||||
if let Some(m) = start_or_stop {
|
||||
if m.is_start {
|
||||
started = true;
|
||||
start_pkt_id = m.pkt_id;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// None, just return
|
||||
return;
|
||||
}
|
||||
}
|
||||
/*
|
||||
while let Some(m) = start_stop_chan.recv().await {
|
||||
println!("4");
|
||||
if m.is_start {
|
||||
// println!("start received");
|
||||
started = true;
|
||||
start_pkt_id = m.pkt_id;
|
||||
break;
|
||||
} else {
|
||||
// println!("stop received");
|
||||
}
|
||||
}
|
||||
*/
|
||||
debug!("start stop chan received: {}", started);
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(ref connecting_chan) = self.connecting_chan {
|
||||
let state = ConnectionInfo::ConnState(ConnectionState::Connecting);
|
||||
let _ = connecting_chan.send(state).await;
|
||||
}
|
||||
|
||||
let host = self.remote.split(":").next().unwrap();
|
||||
|
||||
debug!("try connecting to {}, host = {}", self.remote, host);
|
||||
|
||||
let conn = match edge.quic_endpoint.connect(self.remote.parse().unwrap(), host) {
|
||||
Ok(conn) => conn,
|
||||
Err(e) => {
|
||||
error!("failed to connect: {}", e);
|
||||
println!("failed to connect: {}", e);
|
||||
|
||||
self.connected.store(false, Ordering::Relaxed);
|
||||
if keep_reconnect {
|
||||
tokio::time::sleep(Duration::from_secs(3)).await;
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
let conn = match conn.await {
|
||||
Err(e) => {
|
||||
println!("failed to connect await: {}", e);
|
||||
error!("failed to connect await: {}", e);
|
||||
self.connected.store(false, Ordering::Relaxed);
|
||||
if keep_reconnect {
|
||||
tokio::time::sleep(Duration::from_secs(3)).await;
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
}
|
||||
Ok(conn) => conn,
|
||||
};
|
||||
|
||||
let local_ip = conn.local_ip();
|
||||
|
||||
let Ok((mut send, mut recv)) = conn.open_bi().await else {
|
||||
println!("failed to open-bi");
|
||||
self.connected.store(false, Ordering::Relaxed);
|
||||
if keep_reconnect {
|
||||
tokio::time::sleep(Duration::from_secs(3)).await;
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
self.connected.store(true, Ordering::Relaxed);
|
||||
debug!("connected");
|
||||
on_connected_callback(local_ip, &mut send, start_pkt_id.take()).await;
|
||||
|
||||
if let Some(ref connecting_chan) = self.connecting_chan {
|
||||
let state = ConnectionInfo::ConnState(ConnectionState::Connected);
|
||||
let _ = connecting_chan.send(state).await;
|
||||
}
|
||||
if let Some(ref ipv6_restarter) = self.ipv6_network_restarter {
|
||||
let _ = ipv6_restarter.send(true).await;
|
||||
}
|
||||
// stream.write("hello".as_bytes()).await;
|
||||
// let (reader, mut write) = stream.into_split();
|
||||
|
||||
let read_from_tcp = async move {
|
||||
// let mut buffed_reader = BufReader::new(recv);
|
||||
loop {
|
||||
match read_a_packet(&mut recv).await {
|
||||
Ok(packet) => {
|
||||
debug!("got packet: {:?}", packet);
|
||||
if let Err(_e) = self.from_tcp.send(packet).await {
|
||||
error!("failed to receive a packet: {:?}", _e);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("failed to read a packet: {}, reconnecting...", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let write_to_tcp = async {
|
||||
while let Some(data) = to_tcp.recv().await {
|
||||
match send.write(&data).await {
|
||||
Ok(size) => {
|
||||
debug!("{} bytes sent to tcp", size);
|
||||
}
|
||||
Err(e) => {
|
||||
error!("failed to write to tcp: {}", e.to_string());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
error!("to_tcp recv None");
|
||||
};
|
||||
|
||||
let check_pong = async {
|
||||
loop {
|
||||
tokio::time::sleep(Duration::from_secs(3600)).await;
|
||||
|
||||
let connected = self.connected.load(Ordering::Relaxed);
|
||||
let now = get_current_timestamp();
|
||||
if connected && now - self.pong_time.load(Ordering::Relaxed) > TCP_PING_TIME * 2
|
||||
{
|
||||
// pong time expire, need to re-connect
|
||||
error!("pong check expired");
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let check_stop = async {
|
||||
loop {
|
||||
match start_stop_chan.recv().await {
|
||||
Some(v) => {
|
||||
if !v.is_start {
|
||||
started = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
_other => {
|
||||
// send chan is closed;
|
||||
started = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pin_mut!(read_from_tcp, write_to_tcp);
|
||||
|
||||
tokio::select! {
|
||||
_ = read_from_tcp => {},
|
||||
_ = write_to_tcp => {},
|
||||
_ = check_pong => {},
|
||||
_ = check_stop => {},
|
||||
}
|
||||
on_disconnected_callback().await;
|
||||
conn.close(0u32.into(), "close".as_bytes());
|
||||
debug!("connect retrying");
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
debug!("disconnected");
|
||||
// future::select(read_from_tcp, write_to_tcp).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn on_disconnected_callback() {
|
||||
let edge = get_edge();
|
||||
edge.set_authorized(false, vec![]);
|
||||
}
|
||||
|
||||
async fn on_connected_callback(local_ip: Option<IpAddr>, stream: &mut SendStream, 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 Some(ipaddr) = local_ip {
|
||||
match ipaddr {
|
||||
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 {
|
||||
mac: Vec::from(edge.device_config.get_mac()),
|
||||
pkt_id: edge.get_next_packet_id(),
|
||||
network_id: edge.network_id.load(Ordering::Relaxed),
|
||||
ip: edge.device_config.get_ip(),
|
||||
mask_len: edge.device_config.get_net_bit() as u32,
|
||||
access_token: edge.access_token.get(),
|
||||
|
||||
// installed_channel,
|
||||
client_id: edge.config.node_uuid.clone(),
|
||||
pub_key: edge.rsa_pubkey.clone(),
|
||||
hostname: edge.hostname.read().unwrap().clone(),
|
||||
};
|
||||
|
||||
println!("register super: {:?}", register_super);
|
||||
// debug!("send register super: {:?}", register_super);
|
||||
// let packet_id = edge.get_next_packet_id();
|
||||
let data = encode_to_tcp_message(
|
||||
Some(register_super),
|
||||
PacketType::RegisterSuper as u8,
|
||||
)
|
||||
.unwrap();
|
||||
if let Err(e) = stream.write(&data).await {
|
||||
error!("failed to write to tcp: {}", e.to_string());
|
||||
}
|
||||
}
|
||||
@ -1,14 +1,18 @@
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use quinn::RecvStream;
|
||||
use tokio::{
|
||||
io::{AsyncReadExt, BufReader},
|
||||
net::tcp::OwnedReadHalf,
|
||||
io::{AsyncReadExt},
|
||||
};
|
||||
|
||||
use num_enum::TryFromPrimitive;
|
||||
use tracing::debug;
|
||||
use tracing::{debug, error};
|
||||
|
||||
use crate::{network::Node, pb::{SdlStunRequest, Sdlv6Info, encode_to_udp_message}, utils::send_to_sock};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SdlanTcp {
|
||||
pub _packet_id: u32,
|
||||
// pub _packet_id: u32,
|
||||
pub packet_type: PacketType,
|
||||
pub current_packet: Vec<u8>,
|
||||
}
|
||||
@ -89,28 +93,65 @@ pub enum PacketType {
|
||||
StunProbe = 0x32,
|
||||
StunProbeReply = 0x33,
|
||||
|
||||
Welcome = 0x4f,
|
||||
|
||||
ArpRequest = 0x50,
|
||||
ArpResponse = 0x51,
|
||||
|
||||
PolicyRequest = 0xb0,
|
||||
PolicyReply = 0xb1,
|
||||
|
||||
Data = 0xff,
|
||||
}
|
||||
|
||||
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 {
|
||||
session_token: Vec::from(eee.session_token.get()),
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn read_a_packet(
|
||||
reader: &mut BufReader<OwnedReadHalf>,
|
||||
reader: &mut RecvStream,
|
||||
) -> Result<SdlanTcp, std::io::Error> {
|
||||
debug!("read a packet");
|
||||
let size = reader.read_u16().await?;
|
||||
let payload_size = reader.read_u16().await?;
|
||||
debug!("1");
|
||||
let packet_id = reader.read_u32().await?;
|
||||
debug!("2");
|
||||
let packet_type = reader.read_u8().await?;
|
||||
debug!("3");
|
||||
|
||||
if size < 5 {
|
||||
if payload_size < 1 {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"size less than five",
|
||||
));
|
||||
}
|
||||
|
||||
let bufsize = (size - 5) as usize;
|
||||
let bufsize = (payload_size - 1) as usize;
|
||||
let mut binary = vec![0; bufsize];
|
||||
|
||||
let mut to_read = bufsize;
|
||||
@ -119,6 +160,10 @@ pub async fn read_a_packet(
|
||||
break;
|
||||
}
|
||||
let size_got = reader.read(&mut binary[(bufsize - to_read)..]).await?;
|
||||
if size_got.is_none() {
|
||||
break;
|
||||
}
|
||||
let size_got = size_got.unwrap();
|
||||
|
||||
if size_got == 0 {
|
||||
return Err(std::io::Error::new(
|
||||
@ -131,11 +176,11 @@ pub async fn read_a_packet(
|
||||
let Ok(packet_type) = packet_type.try_into() else {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"packet type error",
|
||||
format!("packet type error: 0x{:02x}", packet_type),
|
||||
));
|
||||
};
|
||||
let result = SdlanTcp {
|
||||
_packet_id: packet_id,
|
||||
// _packet_id: packet_id,
|
||||
packet_type,
|
||||
current_packet: binary,
|
||||
};
|
||||
|
||||
@ -25,7 +25,7 @@ use tracing::error;
|
||||
|
||||
use crate::config::{NULL_MAC, TCP_PING_TIME};
|
||||
use crate::network::{Node, RegisterSuperFeedback, StartStopInfo, check_peer_registration_needed, handle_packet_peer_info};
|
||||
use crate::pb::{SdlDevAddr, SdlRegisterSuper, SdlRegisterSuperAck, SdlRegisterSuperNak, SdlSendRegisterEvent, SdlStunRequest, Sdlv6Info, encode_to_tcp_message, encode_to_udp_message};
|
||||
use crate::pb::{SdlRegisterSuper, SdlRegisterSuperAck, SdlRegisterSuperNak, SdlSendRegisterEvent, SdlStunRequest, Sdlv6Info, encode_to_tcp_message, encode_to_udp_message};
|
||||
use crate::tcp::{EventType, NakMsgCode, NatType, PacketType, read_a_packet};
|
||||
use crate::utils::send_to_sock;
|
||||
use crate::{ConnectionInfo, ConnectionState, get_edge};
|
||||
@ -35,254 +35,8 @@ use super::tcp_codec::SdlanTcp;
|
||||
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();
|
||||
@ -293,8 +47,9 @@ async fn on_connected_callback<'a>(stream: &'a mut tokio::net::TcpStream, pkt_id
|
||||
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 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();
|
||||
@ -309,20 +64,16 @@ async fn on_connected_callback<'a>(stream: &'a mut tokio::net::TcpStream, pkt_id
|
||||
}
|
||||
}
|
||||
let register_super = SdlRegisterSuper {
|
||||
version: 1,
|
||||
installed_channel: edge.install_channel.clone(),
|
||||
mac: Vec::from(edge.device_config.get_mac()),
|
||||
pkt_id: edge.get_next_packet_id(),
|
||||
network_id: edge.network_id.load(Ordering::Relaxed),
|
||||
ip: edge.device_config.get_ip(),
|
||||
mask_len: edge.device_config.get_net_bit() as u32,
|
||||
access_token: edge.access_token.get(),
|
||||
|
||||
// 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);
|
||||
@ -342,197 +93,6 @@ async fn on_connected_callback<'a>(stream: &'a mut tokio::net::TcpStream, pkt_id
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ReadWriteActor {
|
||||
// actor接收的发送给tcp的接收端,由handle存放发送端
|
||||
// to_tcp: Receiver<Vec<u8>>,
|
||||
remote: String,
|
||||
connected: Arc<AtomicBool>,
|
||||
pong_time: Arc<AtomicU64>,
|
||||
// actor收到数据之后,发送给上层的发送端口,接收端由handle保存
|
||||
from_tcp: Sender<SdlanTcp>,
|
||||
_cancel: CancellationToken,
|
||||
connecting_chan: Option<Sender<ConnectionInfo>>,
|
||||
ipv6_network_restarter: Option<Sender<bool>>,
|
||||
}
|
||||
|
||||
impl ReadWriteActor {
|
||||
pub fn new(
|
||||
cancel: CancellationToken,
|
||||
remote: &str,
|
||||
from_tcp: Sender<SdlanTcp>,
|
||||
connected: Arc<AtomicBool>,
|
||||
pong_time: Arc<AtomicU64>,
|
||||
connecting_chan: Option<Sender<ConnectionInfo>>,
|
||||
ipv6_network_restarter: Option<Sender<bool>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
// to_tcp,
|
||||
_cancel: cancel,
|
||||
pong_time,
|
||||
connected,
|
||||
remote: remote.to_owned(),
|
||||
from_tcp,
|
||||
connecting_chan,
|
||||
ipv6_network_restarter,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run<'a>(
|
||||
&self,
|
||||
keep_reconnect: bool,
|
||||
mut to_tcp: Receiver<Vec<u8>>,
|
||||
mut start_stop_chan: Receiver<StartStopInfo>,
|
||||
) {
|
||||
let mut started = false;
|
||||
let mut start_pkt_id = None;
|
||||
loop {
|
||||
if let Some(ref connecting_chan) = self.connecting_chan {
|
||||
let state = ConnectionInfo::ConnState(ConnectionState::NotConnected);
|
||||
let _ = connecting_chan.send(state).await;
|
||||
}
|
||||
self.connected.store(false, Ordering::Relaxed);
|
||||
if !started {
|
||||
// println!("waiting for start");
|
||||
loop {
|
||||
let start_or_stop = start_stop_chan.recv().await;
|
||||
if let Some(m) = start_or_stop {
|
||||
if m.is_start {
|
||||
started = true;
|
||||
start_pkt_id = m.pkt_id;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// None, just return
|
||||
return;
|
||||
}
|
||||
}
|
||||
/*
|
||||
while let Some(m) = start_stop_chan.recv().await {
|
||||
println!("4");
|
||||
if m.is_start {
|
||||
// println!("start received");
|
||||
started = true;
|
||||
start_pkt_id = m.pkt_id;
|
||||
break;
|
||||
} else {
|
||||
// println!("stop received");
|
||||
}
|
||||
}
|
||||
*/
|
||||
debug!("start stop chan received: {}", started);
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(ref connecting_chan) = self.connecting_chan {
|
||||
let state = ConnectionInfo::ConnState(ConnectionState::Connecting);
|
||||
let _ = connecting_chan.send(state).await;
|
||||
}
|
||||
debug!("try connecting...");
|
||||
|
||||
let Ok(mut stream) = TcpStream::connect(&self.remote).await else {
|
||||
self.connected.store(false, Ordering::Relaxed);
|
||||
if keep_reconnect {
|
||||
tokio::time::sleep(Duration::from_secs(3)).await;
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
};
|
||||
self.connected.store(true, Ordering::Relaxed);
|
||||
debug!("connected");
|
||||
on_connected_callback(&mut stream, start_pkt_id.take()).await;
|
||||
|
||||
if let Some(ref connecting_chan) = self.connecting_chan {
|
||||
let state = ConnectionInfo::ConnState(ConnectionState::Connected);
|
||||
let _ = connecting_chan.send(state).await;
|
||||
}
|
||||
if let Some(ref ipv6_restarter) = self.ipv6_network_restarter {
|
||||
let _ = ipv6_restarter.send(true).await;
|
||||
}
|
||||
// stream.write("hello".as_bytes()).await;
|
||||
let (reader, mut write) = stream.into_split();
|
||||
|
||||
let read_from_tcp = async move {
|
||||
let mut buffed_reader = BufReader::new(reader);
|
||||
loop {
|
||||
match read_a_packet(&mut buffed_reader).await {
|
||||
Ok(packet) => {
|
||||
debug!("got packet: {:?}", packet);
|
||||
if let Err(_e) = self.from_tcp.send(packet).await {
|
||||
error!("failed to receive a packet: {:?}", _e);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("failed to read a packet: {}, reconnecting...", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let write_to_tcp = async {
|
||||
while let Some(data) = to_tcp.recv().await {
|
||||
match write.write(&data).await {
|
||||
Ok(size) => {
|
||||
debug!("{} bytes sent to tcp", size);
|
||||
}
|
||||
Err(e) => {
|
||||
error!("failed to write to tcp: {}", e.to_string());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
error!("to_tcp recv None");
|
||||
};
|
||||
|
||||
let check_pong = async {
|
||||
loop {
|
||||
tokio::time::sleep(Duration::from_secs(10)).await;
|
||||
|
||||
let connected = self.connected.load(Ordering::Relaxed);
|
||||
let now = get_current_timestamp();
|
||||
if connected && now - self.pong_time.load(Ordering::Relaxed) > TCP_PING_TIME * 2
|
||||
{
|
||||
// pong time expire, need to re-connect
|
||||
error!("pong check expired");
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let check_stop = async {
|
||||
loop {
|
||||
match start_stop_chan.recv().await {
|
||||
Some(v) => {
|
||||
if !v.is_start {
|
||||
started = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
_other => {
|
||||
// send chan is closed;
|
||||
started = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pin_mut!(read_from_tcp, write_to_tcp);
|
||||
|
||||
tokio::select! {
|
||||
_ = read_from_tcp => {},
|
||||
_ = write_to_tcp => {},
|
||||
_ = check_pong => {},
|
||||
_ = check_stop => {},
|
||||
}
|
||||
on_disconnected_callback().await;
|
||||
debug!("connect retrying");
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
debug!("disconnected");
|
||||
// future::select(read_from_tcp, write_to_tcp).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ReadWriterHandle {
|
||||
@ -619,38 +179,6 @@ impl ReadWriterHandle {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init_tcp_conn(
|
||||
cancel: CancellationToken,
|
||||
addr: &str,
|
||||
// on_connected: OnConnectedCallback<'a>,
|
||||
// on_disconnected: T3,
|
||||
// on_message: T2,
|
||||
pong_time: Arc<AtomicU64>,
|
||||
// cancel: CancellationToken,
|
||||
start_stop_chan: Receiver<StartStopInfo>,
|
||||
connecting_chan: Option<Sender<ConnectionInfo>>,
|
||||
ipv6_network_restarter: Option<Sender<bool>>,
|
||||
)
|
||||
// T2: Fn(SdlanTcp) -> F + Send + 'static,
|
||||
// F: Future<Output = ()> + Send,
|
||||
{
|
||||
|
||||
let tcp_handle = ReadWriterHandle::new(
|
||||
cancel,
|
||||
addr,
|
||||
// on_connected,
|
||||
// on_disconnected,
|
||||
// on_message,
|
||||
pong_time,
|
||||
start_stop_chan,
|
||||
connecting_chan,
|
||||
ipv6_network_restarter,
|
||||
);
|
||||
|
||||
GLOBAL_TCP_HANDLE
|
||||
.set(tcp_handle)
|
||||
.expect("failed to set global tcp handle");
|
||||
}
|
||||
|
||||
pub fn get_tcp_conn() -> &'static ReadWriterHandle {
|
||||
match GLOBAL_TCP_HANDLE.get() {
|
||||
|
||||
@ -1,16 +1,64 @@
|
||||
use structopt::StructOpt;
|
||||
use clap::{Parser, Subcommand, Args};
|
||||
|
||||
const APP_TOKEN_ENV_NAME: &str = "PUNCH_TOKEN";
|
||||
const APP_USER_ENV_NAME: &str = "PUNCH_USER";
|
||||
const APP_PASS_ENV_NAME: &str = "PUNCH_PASS";
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
pub struct CommandLineInput2 {
|
||||
#[command(subcommand)]
|
||||
pub cmd: Commands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum Commands {
|
||||
Login(UserLogin),
|
||||
TokenLogin(TokenLogin),
|
||||
|
||||
/// if logined in, just start,
|
||||
/// else, use the token to login, and start
|
||||
AutoRun(TokenLogin),
|
||||
|
||||
/// after login, we can use start to
|
||||
/// connect to the remote
|
||||
Start,
|
||||
|
||||
/// exits the
|
||||
Stop,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct UserLogin {
|
||||
#[arg(short, long, env = APP_USER_ENV_NAME)]
|
||||
pub username: String,
|
||||
|
||||
#[arg(short, long, env = APP_PASS_ENV_NAME, required=false)]
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct TokenLogin {
|
||||
#[arg(long, env=APP_TOKEN_ENV_NAME, required=false)]
|
||||
pub token: String,
|
||||
}
|
||||
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
pub struct CommandLineInput {
|
||||
#[structopt(long = "token", default_value = "", help="specify a token")]
|
||||
#[structopt(short="u", long = "user", default_value = "", help="specify a token")]
|
||||
pub user: String,
|
||||
|
||||
#[structopt(short="P", long = "pass", default_value = "", help="specify a token")]
|
||||
pub pass: String,
|
||||
|
||||
#[structopt(short="t", long = "token", default_value = "", help="specify a token")]
|
||||
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,
|
||||
}
|
||||
@ -53,11 +101,11 @@ pub struct CommandLine {
|
||||
#[structopt(long = "tos", default_value = "0")]
|
||||
pub tos: u32,
|
||||
|
||||
#[structopt(long = "token", default_value = "")]
|
||||
pub token: String,
|
||||
// #[structopt(long = "token", default_value = "")]
|
||||
// pub token: String,
|
||||
|
||||
#[structopt(long = "code", default_value = "")]
|
||||
pub network_code: String,
|
||||
// #[structopt(long = "code", default_value = "")]
|
||||
// pub network_code: String,
|
||||
|
||||
#[structopt(short = "p")]
|
||||
pub allow_p2p: bool,
|
||||
@ -78,8 +126,8 @@ impl Clone for CommandLine {
|
||||
local_port: self.local_port,
|
||||
name: self.name.clone(),
|
||||
tos: self.tos,
|
||||
token: self.token.clone(),
|
||||
network_code: self.network_code.clone(),
|
||||
// token: self.token.clone(),
|
||||
// network_code: self.network_code.clone(),
|
||||
allow_p2p: self.allow_p2p,
|
||||
nat_server1: self.nat_server1.clone(),
|
||||
nat_server2: self.nat_server2.clone(),
|
||||
|
||||
@ -1,14 +1,29 @@
|
||||
mod command;
|
||||
|
||||
use std::{fs::OpenOptions, io::Write, net::Ipv4Addr, path::Path};
|
||||
|
||||
pub use command::*;
|
||||
|
||||
mod socks;
|
||||
use rand::Rng;
|
||||
use sdlan_sn_rs::utils::Mac;
|
||||
use sdlan_sn_rs::utils::{Mac, Result, SDLanError};
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub use socks::*;
|
||||
|
||||
use crate::get_base_dir;
|
||||
|
||||
mod pid_recorder;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct CachedLoginInfo {
|
||||
pub access_token: String,
|
||||
pub username: String,
|
||||
pub user_type: String,
|
||||
pub audit: u32,
|
||||
pub network_id: u32,
|
||||
pub network_name: String,
|
||||
}
|
||||
|
||||
// pub const CRC_HASH: crc::Crc<u32> = crc::Crc::<u32>::new(&crc::CRC_32_XFER);
|
||||
|
||||
#[allow(unused)]
|
||||
@ -17,6 +32,57 @@ pub fn caculate_crc(data: &[u8]) -> u32 {
|
||||
res
|
||||
}
|
||||
|
||||
pub fn ip_string_to_u32(ip: &str) -> Result<u32> {
|
||||
let ip = ip.parse::<Ipv4Addr>()?;
|
||||
Ok(u32::from(ip))
|
||||
}
|
||||
|
||||
pub fn get_access_token() -> Option<CachedLoginInfo> {
|
||||
let path = format!("{}/.access_token", get_base_dir());
|
||||
if let Ok(content) = std::fs::read(&path) {
|
||||
let data = serde_json::from_slice(&content).unwrap();
|
||||
return Some(data);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn set_access_token(cache_info: &CachedLoginInfo) -> Result<()> {
|
||||
let path = format!("{}/.access_token", get_base_dir());
|
||||
let data = serde_json::to_string(cache_info).unwrap();
|
||||
std::fs::write(path, &data)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_or_load_mac() -> Mac {
|
||||
let path = format!("{}/.mac", get_base_dir());
|
||||
if let Ok(content) = std::fs::read(&path) {
|
||||
if content.len() == 6 {
|
||||
let mut mac = [0; 6];
|
||||
mac.copy_from_slice(&content);
|
||||
return mac;
|
||||
}
|
||||
}
|
||||
let mac = generate_mac_address();
|
||||
let _ = save_to_file_binary(&path, &mac);
|
||||
mac
|
||||
}
|
||||
|
||||
|
||||
pub fn save_to_file_binary(idfile: &str, content: &[u8]) -> Result<()> {
|
||||
if idfile.len() == 0 {
|
||||
return Err(SDLanError::IOError("file is empty".to_owned()));
|
||||
}
|
||||
|
||||
let filepath = Path::new(idfile);
|
||||
OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(filepath)?
|
||||
.write_all(content)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn mac_to_string(mac: &Mac) -> String {
|
||||
format!(
|
||||
"[{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}]",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user