Compare commits

...

13 Commits

26 changed files with 2538 additions and 751 deletions

1
.gitignore vendored
View File

@ -12,3 +12,4 @@ sdlan.exe
*.tar.gz *.tar.gz
*.tgz *.tgz
/punchnet /punchnet
/ca

View File

@ -1,4 +1,4 @@
{ {
// "rust-analyzer.cargo.target": "x86_64-pc-windows-gnu" // "rust-analyzer.cargo.target": "x86_64-pc-windows-gnu",
// "rust-analyzer.cargo.features": ["tun"] // "rust-analyzer.cargo.features": ["tun"]
} }

399
Cargo.lock generated
View File

@ -159,6 +159,28 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" 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]] [[package]]
name = "base64" name = "base64"
version = "0.21.7" version = "0.21.7"
@ -224,9 +246,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.11.0" version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
[[package]] [[package]]
name = "c2rust-bitfields" name = "c2rust-bitfields"
@ -258,7 +280,7 @@ dependencies = [
"anstyle", "anstyle",
"ar", "ar",
"cargo_toml", "cargo_toml",
"clap 4.5.54", "clap 4.5.60",
"elf", "elf",
"env_logger", "env_logger",
"glob", "glob",
@ -302,9 +324,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3" checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3"
dependencies = [ dependencies = [
"find-msvc-tools", "find-msvc-tools",
"jobserver",
"libc",
"shlex", "shlex",
] ]
[[package]]
name = "cesu8"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.4" version = "1.0.4"
@ -357,18 +387,19 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.54" version = "4.5.60"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive",
] ]
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.5.54" version = "4.5.60"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@ -377,10 +408,31 @@ dependencies = [
] ]
[[package]] [[package]]
name = "clap_lex" name = "clap_derive"
version = "0.7.7" version = "4.5.55"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "colorchoice" name = "colorchoice"
@ -388,12 +440,32 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" 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]] [[package]]
name = "const-oid" name = "const-oid"
version = "0.9.6" version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" 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]] [[package]]
name = "core-foundation-sys" name = "core-foundation-sys"
version = "0.8.7" version = "0.8.7"
@ -486,6 +558,15 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "daemonize"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab8bfdaacb3c887a54d41bdf48d3af8873b3f5566469f8ba21b92057509f116e"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "darling" name = "darling"
version = "0.20.11" version = "0.20.11"
@ -640,6 +721,12 @@ version = "0.15.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
[[package]]
name = "dunce"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
[[package]] [[package]]
name = "either" name = "either"
version = "1.15.0" version = "1.15.0"
@ -719,6 +806,18 @@ version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" 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]] [[package]]
name = "fastrand" name = "fastrand"
version = "2.3.0" version = "2.3.0"
@ -775,6 +874,12 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "fs_extra"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
[[package]] [[package]]
name = "futures" name = "futures"
version = "0.3.31" version = "0.3.31"
@ -1320,6 +1425,38 @@ version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" 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]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.85" version = "0.3.85"
@ -1620,6 +1757,12 @@ version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "openssl-probe"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.5" version = "0.12.5"
@ -1868,9 +2011,12 @@ dependencies = [
name = "punchnet" name = "punchnet"
version = "1.0.0" version = "1.0.0"
dependencies = [ dependencies = [
"bytes",
"cargo-deb", "cargo-deb",
"clap 4.5.60",
"crc", "crc",
"crc32fast", "crc32fast",
"daemonize",
"dashmap 6.1.0", "dashmap 6.1.0",
"dns-lookup", "dns-lookup",
"etherparse", "etherparse",
@ -1882,11 +2028,16 @@ dependencies = [
"once_cell", "once_cell",
"prost", "prost",
"prost-build", "prost-build",
"quinn",
"rand 0.8.5", "rand 0.8.5",
"reqwest", "reqwest",
"rpassword",
"rsa", "rsa",
"rustls",
"rustls-pemfile",
"sdlan-sn-rs", "sdlan-sn-rs",
"serde", "serde",
"serde_json",
"structopt", "structopt",
"tokio", "tokio",
"tokio-util", "tokio-util",
@ -1928,6 +2079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31"
dependencies = [ dependencies = [
"bytes", "bytes",
"fastbloom",
"getrandom 0.3.4", "getrandom 0.3.4",
"lru-slab", "lru-slab",
"rand 0.9.2", "rand 0.9.2",
@ -1935,6 +2087,7 @@ dependencies = [
"rustc-hash", "rustc-hash",
"rustls", "rustls",
"rustls-pki-types", "rustls-pki-types",
"rustls-platform-verifier",
"slab", "slab",
"thiserror 2.0.17", "thiserror 2.0.17",
"tinyvec", "tinyvec",
@ -2162,6 +2315,17 @@ dependencies = [
"tracing-subscriber", "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]] [[package]]
name = "rsa" name = "rsa"
version = "0.9.10" version = "0.9.10"
@ -2182,6 +2346,16 @@ dependencies = [
"zeroize", "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]] [[package]]
name = "rustc-hash" name = "rustc-hash"
version = "2.1.1" version = "2.1.1"
@ -2203,10 +2377,12 @@ dependencies = [
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.23.36" version = "0.23.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4"
dependencies = [ dependencies = [
"aws-lc-rs",
"log",
"once_cell", "once_cell",
"ring", "ring",
"rustls-pki-types", "rustls-pki-types",
@ -2215,6 +2391,27 @@ dependencies = [
"zeroize", "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]] [[package]]
name = "rustls-pki-types" name = "rustls-pki-types"
version = "1.13.2" version = "1.13.2"
@ -2225,12 +2422,40 @@ dependencies = [
"zeroize", "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]] [[package]]
name = "rustls-webpki" name = "rustls-webpki"
version = "0.103.8" version = "0.103.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52"
dependencies = [ dependencies = [
"aws-lc-rs",
"ring", "ring",
"rustls-pki-types", "rustls-pki-types",
"untrusted", "untrusted",
@ -2248,6 +2473,24 @@ version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" 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]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.2.0" version = "1.2.0"
@ -2279,6 +2522,29 @@ dependencies = [
"uuid", "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]] [[package]]
name = "serde" name = "serde"
version = "1.0.228" version = "1.0.228"
@ -2417,6 +2683,12 @@ version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
[[package]]
name = "siphasher"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.11" version = "0.4.11"
@ -3242,6 +3514,16 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 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]] [[package]]
name = "want" name = "want"
version = "0.3.1" version = "0.3.1"
@ -3351,6 +3633,15 @@ dependencies = [
"wasm-bindgen", "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]] [[package]]
name = "webpki-roots" name = "webpki-roots"
version = "1.0.5" version = "1.0.5"
@ -3386,6 +3677,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 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]] [[package]]
name = "winapi-x86_64-pc-windows-gnu" name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
@ -3470,6 +3770,15 @@ dependencies = [
"windows-link", "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]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.48.0" version = "0.48.0"
@ -3488,6 +3797,15 @@ dependencies = [
"windows-targets 0.52.6", "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]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.60.2" version = "0.60.2"
@ -3506,6 +3824,21 @@ dependencies = [
"windows-link", "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]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.48.5" version = "0.48.5"
@ -3554,6 +3887,12 @@ dependencies = [
"windows_x86_64_msvc 0.53.1", "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]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.48.5" version = "0.48.5"
@ -3572,6 +3911,12 @@ version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.48.5" version = "0.48.5"
@ -3590,6 +3935,12 @@ version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.48.5" version = "0.48.5"
@ -3620,6 +3971,12 @@ version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.48.5" version = "0.48.5"
@ -3638,6 +3995,12 @@ version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" 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]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.48.5" version = "0.48.5"
@ -3656,6 +4019,12 @@ version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" 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]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.48.5" version = "0.48.5"
@ -3674,6 +4043,12 @@ version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" 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]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.48.5" version = "0.48.5"

View File

@ -28,6 +28,14 @@ tokio = { version = "1.38.0", features = ["full"] }
tokio-util = "0.7.11" tokio-util = "0.7.11"
tracing = "0.1.40" tracing = "0.1.40"
myactor = { git = "https://gitea.s5s8.com/rust/actor-rs.git" } 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" } # rolling-file = { path = "../rolling-file" }
[target.'cfg(unix)'.dependencies] [target.'cfg(unix)'.dependencies]

View File

@ -1,5 +1,7 @@
syntax = "proto3"; syntax = "proto3";
package message;
// //
message SDLV4Info { message SDLV4Info {
@ -13,54 +15,101 @@ message SDLV6Info {
bytes v6 = 2; bytes v6 = 2;
} }
// // super之间采用了quic协议通讯
message SDLDevAddr { // : <<Len:16, PacketType:8, Payload/binary>>
uint32 network_id = 1;
bytes mac = 2;
uint32 net_addr = 3;
uint32 net_bit_len = 4;
string network_domain = 5;
}
// tcp通讯消息 message SDLWelcome {
message SDLEmpty {
}
message SDLRegisterSuper {
uint32 version = 1; uint32 version = 1;
string installed_channel = 2; //
string client_id = 3; uint32 max_bidi_streams = 2;
SDLDevAddr dev_addr = 4; //
string pub_key = 5; uint32 max_packet_size = 3;
string token = 6; //
string network_code = 7; uint32 heartbeat_sec = 4;
string hostname = 8;
} }
// 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 { message SDLRegisterSuperAck {
SDLDevAddr dev_addr = 1; uint32 pkt_id = 1;
bytes aes_key = 2; bytes aes_key = 2;
uint32 upgrade_type = 3; bytes session_token = 3;
optional string upgrade_prompt = 4;
optional string upgrade_address = 5;
} }
message SDLRegisterSuperNak { message SDLRegisterSuperNak {
uint32 error_code = 1; uint32 pkt_id = 1;
string error_message = 2; uint32 error_code = 2;
string error_message = 3;
} }
// //
message SDLQueryInfo { message SDLQueryInfo {
bytes dst_mac = 1; uint32 pkt_id = 1;
bytes dst_mac = 2;
} }
message SDLPeerInfo { message SDLPeerInfo {
bytes dst_mac = 1; uint32 pkt_id = 1;
SDLV4Info v4_info = 2; bytes dst_mac = 2;
optional SDLV6Info v6_info = 3; 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; 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通讯消息 // UDP通讯消息
// client和stun之间的心跳包super的udp之间的存活逻辑
message SDLStunRequest { message SDLStunRequest {
uint32 cookie = 1; uint32 cookie = 1;
string client_id = 2; string client_id = 2;
@ -114,6 +142,7 @@ message SDLStunRequest {
uint32 ip = 5; uint32 ip = 5;
uint32 nat_type = 6; uint32 nat_type = 6;
optional SDLV6Info v6_info = 7; optional SDLV6Info v6_info = 7;
bytes session_token = 8;
} }
message SDLStunReply { message SDLStunReply {
@ -127,8 +156,31 @@ message SDLData {
bool is_p2p = 4; bool is_p2p = 4;
uint32 ttl = 5; uint32 ttl = 5;
bytes data = 6; 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 { message SDLRegister {
uint32 network_id = 1; uint32 network_id = 1;
bytes src_mac = 2; bytes src_mac = 2;
@ -139,17 +191,4 @@ message SDLRegisterAck {
uint32 network_id = 1; uint32 network_id = 1;
bytes src_mac = 2; bytes src_mac = 2;
bytes dst_mac = 3; bytes dst_mac = 3;
}
//
message SDLStunProbe {
uint32 cookie = 1;
uint32 attr = 2;
}
message SDLStunProbeReply {
uint32 cookie = 1;
uint32 port = 2;
uint32 ip = 3;
} }

View File

@ -1,6 +1,7 @@
fn main() { fn main() {
prost_build::Config::new() prost_build::Config::new()
.out_dir("src/pb") .out_dir("src/pb")
.bytes(&[".message.SDLData.data"])
// .out_dir("../tcp_mock/pb") // .out_dir("../tcp_mock/pb")
.protoc_arg("--experimental_allow_proto3_optional") .protoc_arg("--experimental_allow_proto3_optional")
.compile_protos(&["message.proto"], &["."]) .compile_protos(&["message.proto"], &["."])

243
src/bin/punchnet/api/mod.rs Normal file
View 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
}

View File

@ -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_base_dir;
use punchnet::get_edge; use punchnet::get_edge;
use punchnet::ip_string_to_u32;
use punchnet::mod_hostname; use punchnet::mod_hostname;
use punchnet::restore_dns; use punchnet::restore_dns;
use punchnet::run_sdlan; use punchnet::run_sdlan;
use punchnet::set_access_token;
use punchnet::set_base_dir; use punchnet::set_base_dir;
use punchnet::CommandLine; use punchnet::CommandLine;
use punchnet::CommandLineInput; use punchnet::CommandLineInput;
use sdlan_sn_rs::log; 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 tracing::error;
use std::net::ToSocketAddrs; use std::net::ToSocketAddrs;
use structopt::StructOpt; use structopt::StructOpt;
#[tokio::main] use crate::api::ConnectData;
async fn main() { use crate::api::ConnectResponse;
set_base_dir("/usr/local/punchnet"); use crate::api::LoginData;
let _guard = log::init_log(&format!("{}/.output", get_base_dir())); use crate::api::LoginResponse;
use crate::api::TEST_PREFIX;
let cmd = CommandLineInput::from_args(); 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 (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 host = format!("{}:80", hostname);
let mut server = String::new(); let mut server = String::new();
if let Ok(addrs) = host.to_socket_addrs() { if let Ok(addrs) = host.to_socket_addrs() {
@ -41,7 +129,7 @@ async fn main() {
println!("server is {}", server); println!("server is {}", server);
mod_hostname::get_hostname(); // mod_hostname::get_hostname();
/* /*
let hostname = if cmd.hostname.len() == 0 { let hostname = if cmd.hostname.len() == 0 {
mod_hostname::get_hostname() mod_hostname::get_hostname()
@ -49,6 +137,7 @@ async fn main() {
Some(cmd.hostname) Some(cmd.hostname)
}; };
*/ */
/*
let hostname = if cmd.hostname.len() == 0 { let hostname = if cmd.hostname.len() == 0 {
None None
} else { } else {
@ -56,28 +145,32 @@ async fn main() {
}; };
// let hostname = mod_hostname::get_hostname(); // let hostname = mod_hostname::get_hostname();
println!("hostname = {:?}", hostname); println!("hostname = {:?}", hostname);
*/
let _ = run_sdlan( let _ = run_sdlan(
client_id,
mac,
CommandLine { CommandLine {
sn: server.clone()+":1265", sn: server.clone()+":1365",
tcp: server.clone()+":18083", tcp: server.clone()+":443",
nat_server1: server.clone() +":1265", nat_server1: server.clone() +":1365",
nat_server2: "47.98.178.3:1265".to_owned(), // nat_server2: "47.98.178.3:1265".to_owned(),
nat_server2: server.clone() +":1366",
_allow_routing: true, _allow_routing: true,
_drop_multicast: true, _drop_multicast: true,
register_ttl: 1, register_ttl: 1,
mtu: 1400, mtu: 1400,
name: "tau".to_owned(), name: "tau".to_owned(),
tos: 0, tos: 0,
local_port: cmd.port, local_port: 0,
token: cmd.token.clone(), // token: cmd.token.clone(),
network_code: cmd.network_code.clone(), // network_code: cmd.network_code.clone(),
allow_p2p: true, allow_p2p: true,
}, },
tx, tx,
&punchnet::get_install_channel(), &punchnet::get_install_channel(),
server, server,
hostname, Some(self_host_name),
None, None,
) )
.await; .await;
@ -109,7 +202,21 @@ async fn main() {
// exit(0); // 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); error!("failed to start: {:?}", e);
} }
@ -148,4 +255,124 @@ async fn main() {
// started = !started; // 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;
}
} }

View File

@ -3,6 +3,7 @@ mod network;
mod pb; mod pb;
mod tcp; mod tcp;
mod utils; mod utils;
mod quic;
use std::sync::Arc; use std::sync::Arc;
use std::{sync::atomic::AtomicU8, time::Duration}; 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_edge;
pub use network::get_install_channel; pub use network::get_install_channel;
pub use network::{async_main, init_arp, init_edge, NodeConfig, restore_dns}; 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 serde::{Deserialize, Serialize};
use tokio::net::UdpSocket; use tokio::net::UdpSocket;
use tokio::sync::mpsc::{channel, Sender}; use tokio::sync::mpsc::{channel, Sender};
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use tracing::{debug, error}; use tracing::{debug, error};
pub use utils::{CommandLine, CommandLineInput, mod_hostname}; pub use utils::*;
pub use config::{get_base_dir, set_base_dir}; pub use config::{get_base_dir, set_base_dir};
@ -43,6 +44,9 @@ pub enum ConnectionState {
} }
pub async fn run_sdlan( pub async fn run_sdlan(
edge_uuid: String,
mac: Mac,
args: CommandLine, args: CommandLine,
sender: std::sync::mpsc::Sender<bool>, sender: std::sync::mpsc::Sender<bool>,
install_channel: &str, install_channel: &str,
@ -54,7 +58,7 @@ pub async fn run_sdlan(
// start_stop_receiver: Receiver<String>, // start_stop_receiver: Receiver<String>,
) -> Result<()> { ) -> Result<()> {
let (start_stop_sender, start_stop_chan) = channel(20); let (start_stop_sender, start_stop_chan) = channel(20);
let edge_uuid = create_or_load_uuid(&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 node_conf = parse_config(edge_uuid, &args).await?;
let hostfile = format!("{}/.host", get_base_dir()); 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?); let sock = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
if let Err(e) = init_edge( if let Err(e) = init_edge(
&args.token, // &args.token,
&args.network_code, // &args.network_code,
mac,
node_conf, node_conf,
args.tos, args.tos,
start_stop_sender, start_stop_sender,

View File

@ -1,4 +1,4 @@
use std::sync::atomic::Ordering; use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
@ -7,7 +7,7 @@ use crate::network::ipv6::run_ipv6;
use crate::network::{ use crate::network::{
get_edge, ping_to_sn, read_and_parse_packet, TunTapPacketHandler, 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::utils::{send_to_sock, CommandLine};
use crate::{ConnectionInfo}; use crate::{ConnectionInfo};
use sdlan_sn_rs::peer::{SdlanSock}; 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 sdlan_sn_rs::utils::{Mac, Result};
use tokio::net::{UdpSocket}; use tokio::net::{UdpSocket};
use tokio::sync::mpsc::{channel, Receiver, Sender}; use tokio::sync::mpsc::{channel, Receiver, Sender};
use tokio::time::sleep;
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use super::{Node, StartStopInfo}; use super::{Node, StartStopInfo};
@ -31,11 +32,14 @@ pub async fn async_main(
// let _ = PidRecorder::new(".pid"); // let _ = PidRecorder::new(".pid");
let edge = get_edge(); let edge = get_edge();
init_identity_cache();
// let token = args.token.clone(); // let token = args.token.clone();
let cancel_tcp = cancel.clone(); let cancel_tcp = cancel.clone();
let (ipv6_network_restarter, rx) = channel(10); let (ipv6_network_restarter, rx) = channel(10);
tokio::spawn(run_ipv6(edge, rx)); tokio::spawn(run_ipv6(edge, rx));
init_tcp_conn(
init_quic_conn(
cancel_tcp, cancel_tcp,
&args.tcp, &args.tcp,
// |msg| handle_tcp_message(msg), // |msg| handle_tcp_message(msg),
@ -46,11 +50,6 @@ pub async fn async_main(
Some(ipv6_network_restarter), 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..."); debug!("waiting for authorization...");
/* /*
@ -119,6 +118,17 @@ pub async fn async_main(
Ok(()) 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) { async fn run_edge_loop(eee: &'static Node, cancel: CancellationToken) {
ping_to_sn().await; ping_to_sn().await;
{ {

View File

@ -8,21 +8,21 @@ use crate::utils::generate_mac_address;
pub struct DeviceConfig { pub struct DeviceConfig {
pub mtu: u32, pub mtu: u32,
pub mac: RwLock<Mac>, pub mac: Mac,
pub ip: IpSubnet, pub ip: IpSubnet,
pub dns_mac: Mac, pub dns_mac: Mac,
} }
impl DeviceConfig { impl DeviceConfig {
pub fn new(mtu: u32) -> Self { pub fn new(mac: Mac, mtu: u32) -> Self {
let mac = generate_mac_address(); // let mac = generate_mac_address();
let dns_mac = generate_mac_address(); let dns_mac = generate_mac_address();
println!("self mac: {}", mac_to_string(&mac)); println!("self mac: {}", mac_to_string(&mac));
debug!("self mac: {}", mac_to_string(&mac)); debug!("self mac: {}", mac_to_string(&mac));
DeviceConfig { DeviceConfig {
mtu, mtu,
mac: RwLock::new(mac), mac: mac,
ip: IpSubnet::new(0, 0), ip: IpSubnet::new(0, 0),
dns_mac, dns_mac,
} }
@ -47,7 +47,7 @@ impl DeviceConfig {
} }
pub fn get_mac(&self) -> Mac { pub fn get_mac(&self) -> Mac {
let mac = *self.mac.read().unwrap(); let mac = self.mac;
mac mac
} }
} }

View File

@ -1,4 +1,5 @@
use dashmap::DashMap; use dashmap::DashMap;
use quinn::Endpoint;
use rsa::RsaPrivateKey; use rsa::RsaPrivateKey;
use sdlan_sn_rs::config::{AF_INET, AF_INET6}; use sdlan_sn_rs::config::{AF_INET, AF_INET6};
use tokio::net::UdpSocket; use tokio::net::UdpSocket;
@ -11,12 +12,13 @@ use tokio::sync::mpsc::Sender;
use tokio::sync::oneshot; use tokio::sync::oneshot;
use tracing::{debug, error}; use tracing::{debug, error};
use crate::quic::quic_init;
use crate::{ConnectionInfo, get_base_dir}; use crate::{ConnectionInfo, get_base_dir};
use crate::pb::{ use crate::pb::{
encode_to_tcp_message, encode_to_udp_message, SdlEmpty, SdlStunProbe, SdlStunProbeReply, encode_to_tcp_message, encode_to_udp_message, SdlEmpty, SdlStunProbe, SdlStunProbeReply,
}; };
use crate::tcp::{get_tcp_conn, NatType, PacketType, StunProbeAttr}; use crate::tcp::{NatType, PacketType, StunProbeAttr, get_quic_write_conn};
use crate::utils::{Socket}; use crate::utils::{Socket, create_or_load_mac};
use sdlan_sn_rs::peer::{IpSubnet, V6Info}; use sdlan_sn_rs::peer::{IpSubnet, V6Info};
@ -32,8 +34,9 @@ use sdlan_sn_rs::utils::{Result, SDLanError};
static EDGE: OnceCell<Node> = OnceCell::new(); static EDGE: OnceCell<Node> = OnceCell::new();
pub async fn init_edge( pub async fn init_edge(
token: &str, // token: &str,
network_code: &str, // network_code: &str,
mac: Mac,
node_conf: NodeConfig, node_conf: NodeConfig,
tos: u32, tos: u32,
start_stop: Sender<StartStopInfo>, start_stop: Sender<StartStopInfo>,
@ -75,12 +78,13 @@ pub async fn init_edge(
// let tcpsock = TCPSocket::build("121.4.79.234:1234").await?; // let tcpsock = TCPSocket::build("121.4.79.234:1234").await?;
let tcp_pong = Arc::new(AtomicU64::new(0)); let tcp_pong = Arc::new(AtomicU64::new(0));
let edge = Node::new( let edge = Node::new(
mac,
pubkey, pubkey,
node_conf, node_conf,
sock_v4, sock_v4,
sock_multicast, sock_multicast,
token, // token,
network_code, // network_code,
privatekey, privatekey,
tcp_pong.clone(), tcp_pong.clone(),
start_stop, start_stop,
@ -123,13 +127,53 @@ pub struct StartStopInfo {
pub pkt_id: Option<u32>, 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 { pub struct Node {
packet_id: AtomicU32, packet_id: AtomicU32,
pub network_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 hostname: RwLock<String>,
pub quic_endpoint: Endpoint,
pub udp_sock_for_dns: Arc<UdpSocket>, pub udp_sock_for_dns: Arc<UdpSocket>,
pub server_ip: String, pub server_ip: String,
@ -139,8 +183,8 @@ pub struct Node {
pub connection_chan: Option<Sender<ConnectionInfo>>, pub connection_chan: Option<Sender<ConnectionInfo>>,
// user token info // user token info
pub _token: Mutex<String>, // pub _token: Mutex<String>,
pub network_code: Mutex<String>, // pub network_code: Mutex<String>,
pub device_config: DeviceConfig, pub device_config: DeviceConfig,
pub device: Iface, pub device: Iface,
@ -205,14 +249,33 @@ impl Node {
self.nat_type.lock().unwrap().clone() 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 { if let Some(host) = hostname {
let idfile = format!("{}/.host", get_base_dir()); let idfile = format!("{}/.host", get_base_dir());
let _ = save_to_file(&idfile, &host); let _ = save_to_file(&idfile, &host);
*self.hostname.write().unwrap() = 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 let _ = self
.start_stop_sender .start_stop_sender
.send(StartStopInfo { .send(StartStopInfo {
@ -225,8 +288,17 @@ impl Node {
pub async fn start_with_feedback( pub async fn start_with_feedback(
&self, &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>, hostname: Option<String>,
timeout: Duration, timeout: Duration,
) -> Result<RegisterSuperFeedback> { ) -> Result<RegisterSuperFeedback> {
@ -235,8 +307,17 @@ impl Node {
let _ = save_to_file(&idfile, &host); let _ = save_to_file(&idfile, &host);
*self.hostname.write().unwrap() = 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 (tx, rx) = oneshot::channel();
let id = self.get_next_packet_id(); let id = self.get_next_packet_id();
self.packet_id_match.insert(id, tx); self.packet_id_match.insert(id, tx);
@ -265,7 +346,8 @@ impl Node {
} }
pub async fn stop(&self) { pub async fn stop(&self) {
*self._token.lock().unwrap() = "".to_owned(); // *self._token.lock().unwrap() = "".to_owned();
self.session_token.set(vec![]);
let _ = self let _ = self
.start_stop_sender .start_stop_sender
.send(StartStopInfo { .send(StartStopInfo {
@ -276,13 +358,14 @@ impl Node {
} }
pub fn new( pub fn new(
mac: Mac,
pubkey: String, pubkey: String,
config: NodeConfig, config: NodeConfig,
sock: Socket, sock: Socket,
multicast_sock: Option<Socket>, multicast_sock: Option<Socket>,
// tcpsock: TCPSocket, // tcpsock: TCPSocket,
token: &str, // token: &str,
network_code: &str, // network_code: &str,
private: RsaPrivateKey, private: RsaPrivateKey,
tcp_pong: Arc<AtomicU64>, tcp_pong: Arc<AtomicU64>,
start_stop: Sender<StartStopInfo>, start_stop: Sender<StartStopInfo>,
@ -304,10 +387,18 @@ impl Node {
network_id: AtomicU32::new(0), network_id: AtomicU32::new(0),
hostname: RwLock::new(hostname), hostname: RwLock::new(hostname),
network_domain: RwLock::new(String::new()),
udp_sock_for_dns: udpsock_for_dns, udp_sock_for_dns: udpsock_for_dns,
_token: Mutex::new(token.to_owned()), quic_endpoint: quic_init(),
network_code: Mutex::new(network_code.to_owned()),
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, start_stop_sender: start_stop,
connection_chan: connecting_chan, connection_chan: connecting_chan,
@ -316,7 +407,7 @@ impl Node {
nat_type: Mutex::new(NatType::Blocked), nat_type: Mutex::new(NatType::Blocked),
device_config: DeviceConfig::new(mtu), device_config: DeviceConfig::new(mac, mtu),
device: new_iface("dev", mode), device: new_iface("dev", mode),
authorized: AtomicBool::new(false), authorized: AtomicBool::new(false),
@ -498,9 +589,9 @@ impl Node {
pub async fn send_unregister_super(&self) -> Result<()> { pub async fn send_unregister_super(&self) -> Result<()> {
let content = 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; let _ = conn.send(content).await;
Ok(()) Ok(())
@ -515,6 +606,7 @@ impl Node {
let probe = SdlStunProbe { let probe = SdlStunProbe {
attr: msgattr as u32, attr: msgattr as u32,
cookie, cookie,
step: 0,
}; };
// println!("==> sending probe request: {:?}", probe); // println!("==> sending probe request: {:?}", probe);

View File

@ -1,6 +1,8 @@
use std::{net::SocketAddr, sync::atomic::Ordering, time::Duration}; 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::{network::TunTapPacketHandler, utils::mac_to_string};
use crate::{ use crate::{
@ -9,10 +11,10 @@ use crate::{
encode_to_tcp_message, encode_to_udp_message, SdlData, SdlEmpty, SdlPeerInfo, SdlQueryInfo, encode_to_tcp_message, encode_to_udp_message, SdlData, SdlEmpty, SdlPeerInfo, SdlQueryInfo,
SdlRegister, SdlRegisterAck, SdlStunProbeReply, SdlRegister, SdlRegisterAck, SdlStunProbeReply,
}, },
tcp::{get_tcp_conn, PacketType}, tcp::{PacketType},
utils::{send_to_sock, Socket}, utils::{send_to_sock, Socket},
}; };
use etherparse::Ethernet2Header; use etherparse::{Ethernet2Header, PacketHeaders, ip_number};
use prost::Message; use prost::Message;
use sdlan_sn_rs::utils::{BROADCAST_MAC}; use sdlan_sn_rs::utils::{BROADCAST_MAC};
use sdlan_sn_rs::{ 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}; 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"); error!("failed to convert src mac");
return Err(SDLanError::NormalError("failed to convert vec to Mac")); return Err(SDLanError::NormalError("failed to convert vec to Mac"));
}; };
// let from_sock = get_sdlan_sock_from_socketaddr(addr).unwrap(); // let from_sock = get_sdlan_sock_from_socketaddr(addr).unwrap();
if data.is_p2p { if data.is_p2p {
debug!("[P2P] Rx data from {}", from_sock.to_string()); debug!("[P2P] Rx data from {}", from_sock.to_string());
@ -818,6 +821,61 @@ pub fn print_hex(key: &[u8]) {
println!("[{}]", value.join(" ")) 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( async fn handle_tun_packet(
eee: &Node, eee: &Node,
_from_sock: &SdlanSock, _from_sock: &SdlanSock,
@ -838,7 +896,50 @@ async fn handle_tun_packet(
error!("failed to decrypt original data"); error!("failed to decrypt original data");
return; return;
} }
let data = origin.unwrap(); 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 if let Err(e) = eee
.device .device
.handle_packet_from_net(&data, key.as_slice()) .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 { let query = SdlQueryInfo {
dst_mac: Vec::from(dst_mac), dst_mac: Vec::from(dst_mac),
pkt_id: 0,
}; };
let Ok(content) = encode_to_tcp_message( let Ok(content) = encode_to_tcp_message(
Some(query), Some(query),
eee.get_next_packet_id(), // eee.get_next_packet_id(),
PacketType::QueryInfo as u8, PacketType::QueryInfo as u8,
) else { ) else {
error!("failed to encode query"); error!("failed to encode query");
return Err(SDLanError::NormalError("encode query error")); 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 tcp_conn.send(content).await
} }
pub async fn ping_to_sn() { 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"); error!("failed to encode ping");
return; return;
}; };
debug!("ping to sn"); 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 { if let Err(e) = tcp_conn.send(msg).await {
error!("failed to ping to sn: {:?}", e); error!("failed to ping to sn: {:?}", e);
} }

View File

@ -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)) { if let Err(e) = set_dns(self, &self.name, network_domain, &ip_to_string(&default_gw)) {
error!("failed to set dns: {}", e.as_str()); error!("failed to set dns: {}", e.as_str());
} }
*/
} else { } else {
info!("set tun device"); info!("set tun device");
let res = Command::new("ifconfig") let res = Command::new("ifconfig")
@ -220,10 +223,48 @@ impl TunTapPacketHandler for Iface {
}; };
if let Some(eth) = headers.link { if let Some(eth) = headers.link {
use etherparse::EtherType;
if let Some(hdr) = eth.ethernet2() { 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 { if let Some(ip) = headers.net {
match ip { match ip {
etherparse::NetHeaders::Ipv4(ipv4, _) => { etherparse::NetHeaders::Ipv4(ipv4, _) => {
use etherparse::ip_number::{self, ICMP};
if let Some(transport) = headers.transport {
if let Some(tcp) = transport.tcp() {
// is tcp
}
}
if u32::from_be_bytes(ipv4.destination) == DNS_IP { if u32::from_be_bytes(ipv4.destination) == DNS_IP {
// should send to dns // should send to dns
@ -251,13 +292,16 @@ impl TunTapPacketHandler for Iface {
error!("failed to encrypt packet request"); error!("failed to encrypt packet request");
return Ok(()); return Ok(());
}; };
let data_bytes = Bytes::from(encrypted);
let data = SdlData { let data = SdlData {
is_p2p: true, is_p2p: true,
network_id: edge.network_id.load(Ordering::Relaxed), network_id: edge.network_id.load(Ordering::Relaxed),
ttl: SDLAN_DEFAULT_TTL as u32, ttl: SDLAN_DEFAULT_TTL as u32,
src_mac: Vec::from(edge.device_config.get_mac()), src_mac: Vec::from(edge.device_config.get_mac()),
dst_mac: Vec::from(target), 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(); let msg = encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap();
@ -331,6 +375,7 @@ impl TunTapPacketHandler for Iface {
return Ok(()); return Ok(());
} }
if dest_ip == self_ip { if dest_ip == self_ip {
use bytes::Bytes;
use sdlan_sn_rs::utils::mac_to_string; use sdlan_sn_rs::utils::mac_to_string;
use crate::network::{ARP_REPLY, ArpRequestInfo, send_arp_request}; use crate::network::{ARP_REPLY, ArpRequestInfo, send_arp_request};
@ -359,13 +404,17 @@ impl TunTapPacketHandler for Iface {
return Ok(()); return Ok(());
}; };
let data_bytes = Bytes::from(encrypted);
let data = SdlData { let data = SdlData {
is_p2p: true, is_p2p: true,
ttl: 2, ttl: 2,
network_id: edge.network_id.load(Ordering::Relaxed), network_id: edge.network_id.load(Ordering::Relaxed),
src_mac: Vec::from(self_mac), src_mac: Vec::from(self_mac),
dst_mac: Vec::from(arp.dhwaddr), 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) let v = encode_to_udp_message(Some(data), PacketType::Data as u8)
@ -492,6 +541,8 @@ impl TunTapPacketHandler for Iface {
ip, ip,
do_arp_request, do_arp_request,
} => { } => {
use bytes::Bytes;
use crate::utils::caculate_crc; use crate::utils::caculate_crc;
if do_arp_request { if do_arp_request {
@ -518,7 +569,9 @@ impl TunTapPacketHandler for Iface {
dst_mac: Vec::from([0xff; 6]), dst_mac: Vec::from([0xff; 6]),
is_p2p: true, is_p2p: true,
ttl: SDLAN_DEFAULT_TTL as u32, 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 = let data =
encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap(); 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, ttl: SDLAN_DEFAULT_TTL as u32,
src_mac: Vec::from(src_mac), src_mac: Vec::from(src_mac),
dst_mac: Vec::from(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 = let msg =
encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap(); encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap();

View File

@ -1,3 +1,4 @@
use bytes::Bytes;
use etherparse::ether_type::ARP; use etherparse::ether_type::ARP;
use etherparse::{Ethernet2Header, IpHeaders}; use etherparse::{Ethernet2Header, IpHeaders};
use sdlan_sn_rs::config::SDLAN_DEFAULT_TTL; use sdlan_sn_rs::config::SDLAN_DEFAULT_TTL;
@ -209,7 +210,9 @@ impl TunTapPacketHandler for Iface {
network_id: edge.network_id.load(Ordering::Relaxed), network_id: edge.network_id.load(Ordering::Relaxed),
src_mac: Vec::from(self_mac), src_mac: Vec::from(self_mac),
dst_mac: Vec::from(arp.dhwaddr), 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) 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]), dst_mac: Vec::from([0xff; 6]),
is_p2p: true, is_p2p: true,
ttl: SDLAN_DEFAULT_TTL as u32, 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 = let data =
encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap(); 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, ttl: SDLAN_DEFAULT_TTL as u32,
src_mac: Vec::from(src_mac), src_mac: Vec::from(src_mac),
dst_mac: Vec::from(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 = let msg =
encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap(); encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap();

View File

@ -1,5 +1,6 @@
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use bytes::Bytes;
use dashmap::DashMap; use dashmap::DashMap;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use sdlan_sn_rs::{ use sdlan_sn_rs::{
@ -91,13 +92,16 @@ impl ArpWaitList {
error!("failed to encrypt packet request"); error!("failed to encrypt packet request");
return; return;
}; };
let data_bytes = Bytes::from(encrypted);
let data = SdlData { let data = SdlData {
is_p2p: true, is_p2p: true,
network_id, network_id,
ttl: SDLAN_DEFAULT_TTL as u32, ttl: SDLAN_DEFAULT_TTL as u32,
src_mac: Vec::from(src_mac), src_mac: Vec::from(src_mac),
dst_mac: Vec::from(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(); 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; send_packet_to_net(edge, mac, &msg, pkt_size as u64).await;

View File

@ -17,83 +17,148 @@ pub struct Sdlv6Info {
#[prost(bytes = "vec", tag = "2")] #[prost(bytes = "vec", tag = "2")]
pub v6: ::prost::alloc::vec::Vec<u8>, pub v6: ::prost::alloc::vec::Vec<u8>,
} }
/// 设备网络地址信息
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct SdlDevAddr { pub struct SdlWelcome {
#[prost(uint32, tag = "1")] #[prost(uint32, tag = "1")]
pub network_id: u32, pub version: u32,
#[prost(bytes = "vec", tag = "2")] /// 服务器允许的最大双向流
pub mac: ::prost::alloc::vec::Vec<u8>, #[prost(uint32, tag = "2")]
pub max_bidi_streams: u32,
/// 服务器允许的最大包
#[prost(uint32, tag = "3")] #[prost(uint32, tag = "3")]
pub net_addr: u32, pub max_packet_size: u32,
/// 心跳包的间隔
#[prost(uint32, tag = "4")] #[prost(uint32, tag = "4")]
pub net_bit_len: u32, pub heartbeat_sec: u32,
#[prost(string, tag = "5")]
pub network_domain: ::prost::alloc::string::String,
} }
/// tcp通讯消息 /// quic 通讯消息
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct SdlEmpty {} pub struct SdlEmpty {
#[prost(uint32, tag = "1")]
pub pkt_id: u32,
}
/// 这里修改成了扁平的结构, 否则有些字段不好找放的位置
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct SdlRegisterSuper { pub struct SdlRegisterSuper {
#[prost(uint32, tag = "1")] #[prost(uint32, tag = "1")]
pub version: u32, pub pkt_id: u32,
#[prost(string, tag = "2")] #[prost(string, tag = "2")]
pub installed_channel: ::prost::alloc::string::String,
#[prost(string, tag = "3")]
pub client_id: ::prost::alloc::string::String, pub client_id: ::prost::alloc::string::String,
#[prost(message, optional, tag = "4")] /// 网络地址信息已经有https请求分配了
pub dev_addr: ::core::option::Option<SdlDevAddr>, /// 注册的时候需要带上(network_id, mac, ip, mask_len, hostname)
#[prost(string, tag = "5")] #[prost(uint32, tag = "3")]
pub pub_key: ::prost::alloc::string::String, pub network_id: u32,
#[prost(string, tag = "6")] #[prost(bytes = "vec", tag = "4")]
pub token: ::prost::alloc::string::String, 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")] #[prost(string, tag = "7")]
pub network_code: ::prost::alloc::string::String,
#[prost(string, tag = "8")]
pub hostname: ::prost::alloc::string::String, 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)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct SdlRegisterSuperAck { pub struct SdlRegisterSuperAck {
#[prost(message, optional, tag = "1")] #[prost(uint32, tag = "1")]
pub dev_addr: ::core::option::Option<SdlDevAddr>, pub pkt_id: u32,
#[prost(bytes = "vec", tag = "2")] #[prost(bytes = "vec", tag = "2")]
pub aes_key: ::prost::alloc::vec::Vec<u8>, pub aes_key: ::prost::alloc::vec::Vec<u8>,
#[prost(uint32, tag = "3")] #[prost(bytes = "vec", tag = "3")]
pub upgrade_type: u32, pub session_token: ::prost::alloc::vec::Vec<u8>,
#[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>,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct SdlRegisterSuperNak { pub struct SdlRegisterSuperNak {
#[prost(uint32, tag = "1")] #[prost(uint32, tag = "1")]
pub pkt_id: u32,
#[prost(uint32, tag = "2")]
pub error_code: u32, pub error_code: u32,
#[prost(string, tag = "2")] #[prost(string, tag = "3")]
pub error_message: ::prost::alloc::string::String, pub error_message: ::prost::alloc::string::String,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct SdlQueryInfo { 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>, pub dst_mac: ::prost::alloc::vec::Vec<u8>,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct SdlPeerInfo { pub struct SdlPeerInfo {
#[prost(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>, 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")] #[prost(message, optional, tag = "3")]
pub v4_info: ::core::option::Option<Sdlv4Info>,
#[prost(message, optional, tag = "4")]
pub v6_info: ::core::option::Option<Sdlv6Info>, 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)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct SdlNatChangedEvent { pub struct SdlNatChangedEvent {
@ -122,36 +187,7 @@ pub struct SdlNetworkShutdownEvent {
#[prost(string, tag = "1")] #[prost(string, tag = "1")]
pub message: ::prost::alloc::string::String, pub message: ::prost::alloc::string::String,
} }
#[allow(clippy::derive_partial_eq_without_eq)] /// client和stun之间的心跳包客户端需要和super的udp之间的存活逻辑
#[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,
}
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct SdlStunRequest { pub struct SdlStunRequest {
@ -169,6 +205,8 @@ pub struct SdlStunRequest {
pub nat_type: u32, pub nat_type: u32,
#[prost(message, optional, tag = "7")] #[prost(message, optional, tag = "7")]
pub v6_info: ::core::option::Option<Sdlv6Info>, 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)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
@ -189,8 +227,38 @@ pub struct SdlData {
pub is_p2p: bool, pub is_p2p: bool,
#[prost(uint32, tag = "5")] #[prost(uint32, tag = "5")]
pub ttl: u32, pub ttl: u32,
#[prost(bytes = "vec", tag = "6")] #[prost(bytes = "bytes", tag = "6")]
pub data: ::prost::alloc::vec::Vec<u8>, 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)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
@ -212,21 +280,3 @@ pub struct SdlRegisterAck {
#[prost(bytes = "vec", tag = "3")] #[prost(bytes = "vec", tag = "3")]
pub dst_mac: ::prost::alloc::vec::Vec<u8>, 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,
}

View File

@ -7,7 +7,7 @@ use sdlan_sn_rs::utils::Result;
// tcp message has two-byte of size at header // tcp message has two-byte of size at header
pub fn encode_to_tcp_message<T: Message>( pub fn encode_to_tcp_message<T: Message>(
msg: Option<T>, msg: Option<T>,
packet_id: u32, // _packet_id: u32,
packet_type: u8, packet_type: u8,
) -> Result<Vec<u8>> { ) -> Result<Vec<u8>> {
let mut raw_data = Vec::new(); let mut raw_data = Vec::new();
@ -16,10 +16,10 @@ pub fn encode_to_tcp_message<T: Message>(
msg.encode(&mut raw_data)?; msg.encode(&mut raw_data)?;
} }
let mut result = Vec::with_capacity(raw_data.len() + 7); let mut result = Vec::with_capacity(raw_data.len() + 3);
let size = u16::to_be_bytes(raw_data.len() as u16 + 5); let size = u16::to_be_bytes(raw_data.len() as u16 + 1);
result.extend_from_slice(&size); 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.push(packet_type);
result.extend_from_slice(&raw_data); result.extend_from_slice(&raw_data);
Ok(result) Ok(result)

76
src/quic/mod.rs Normal file
View 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
View 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);
}

View File

@ -1,5 +1,12 @@
mod tcp_codec; mod tcp_codec;
mod tcp_conn; // mod tcp_conn;
mod quic;
mod identity_cache;
pub use tcp_codec::*; 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
View 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());
}
}

View File

@ -1,14 +1,18 @@
use std::sync::atomic::Ordering;
use quinn::RecvStream;
use tokio::{ use tokio::{
io::{AsyncReadExt, BufReader}, io::{AsyncReadExt},
net::tcp::OwnedReadHalf,
}; };
use num_enum::TryFromPrimitive; 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)] #[derive(Debug)]
pub struct SdlanTcp { pub struct SdlanTcp {
pub _packet_id: u32, // pub _packet_id: u32,
pub packet_type: PacketType, pub packet_type: PacketType,
pub current_packet: Vec<u8>, pub current_packet: Vec<u8>,
} }
@ -89,28 +93,65 @@ pub enum PacketType {
StunProbe = 0x32, StunProbe = 0x32,
StunProbeReply = 0x33, StunProbeReply = 0x33,
Welcome = 0x4f,
ArpRequest = 0x50,
ArpResponse = 0x51,
PolicyRequest = 0xb0,
PolicyReply = 0xb1,
Data = 0xff, 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( pub async fn read_a_packet(
reader: &mut BufReader<OwnedReadHalf>, reader: &mut RecvStream,
) -> Result<SdlanTcp, std::io::Error> { ) -> Result<SdlanTcp, std::io::Error> {
debug!("read a packet"); debug!("read a packet");
let size = reader.read_u16().await?; let payload_size = reader.read_u16().await?;
debug!("1"); debug!("1");
let packet_id = reader.read_u32().await?;
debug!("2");
let packet_type = reader.read_u8().await?; let packet_type = reader.read_u8().await?;
debug!("3"); debug!("3");
if size < 5 { if payload_size < 1 {
return Err(std::io::Error::new( return Err(std::io::Error::new(
std::io::ErrorKind::Other, std::io::ErrorKind::Other,
"size less than five", "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 binary = vec![0; bufsize];
let mut to_read = bufsize; let mut to_read = bufsize;
@ -119,6 +160,10 @@ pub async fn read_a_packet(
break; break;
} }
let size_got = reader.read(&mut binary[(bufsize - to_read)..]).await?; 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 { if size_got == 0 {
return Err(std::io::Error::new( 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 { let Ok(packet_type) = packet_type.try_into() else {
return Err(std::io::Error::new( return Err(std::io::Error::new(
std::io::ErrorKind::Other, std::io::ErrorKind::Other,
"packet type error", format!("packet type error: 0x{:02x}", packet_type),
)); ));
}; };
let result = SdlanTcp { let result = SdlanTcp {
_packet_id: packet_id, // _packet_id: packet_id,
packet_type, packet_type,
current_packet: binary, current_packet: binary,
}; };

View File

@ -25,7 +25,7 @@ use tracing::error;
use crate::config::{NULL_MAC, TCP_PING_TIME}; use crate::config::{NULL_MAC, TCP_PING_TIME};
use crate::network::{Node, RegisterSuperFeedback, StartStopInfo, check_peer_registration_needed, handle_packet_peer_info}; 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::tcp::{EventType, NakMsgCode, NatType, PacketType, read_a_packet};
use crate::utils::send_to_sock; use crate::utils::send_to_sock;
use crate::{ConnectionInfo, ConnectionState, get_edge}; use crate::{ConnectionInfo, ConnectionState, get_edge};
@ -35,254 +35,8 @@ use super::tcp_codec::SdlanTcp;
static GLOBAL_TCP_HANDLE: OnceCell<ReadWriterHandle> = OnceCell::new(); static GLOBAL_TCP_HANDLE: OnceCell<ReadWriterHandle> = OnceCell::new();
async fn handle_tcp_message(msg: SdlanTcp) {
let edge = get_edge();
// let now = get_current_timestamp();
// edge.tcp_pong.store(now, Ordering::Relaxed);
debug!("got tcp message: {:?}", msg.packet_type);
match msg.packet_type {
PacketType::RegisterSuperACK => {
edge.send_register_super_feedback(
msg._packet_id,
RegisterSuperFeedback {
result: 0,
message: "".to_owned(),
should_exit: false,
},
);
let Ok(ack) = SdlRegisterSuperAck::decode(&msg.current_packet[..]) else {
error!("failed to decode REGISTER_SUPER_ACK");
return;
};
debug!("got register super ack: {:?}", ack);
let Ok(aes) = rsa_decrypt(&edge.rsa_private, &ack.aes_key) else {
error!("failed to rsa decrypt aes key");
return;
};
let Some(dev) = ack.dev_addr else {
error!("no dev_addr is specified");
return;
};
let ip = ip_to_string(&dev.net_addr);
// debug!("aes key is {:?}, ip is {}/{}", aes, ip, dev.net_bit_len,);
println!("assigned ip: {}", ip);
let hostname = edge.hostname.read().unwrap().clone();
println!("network is: {}.{}", hostname, dev.network_domain);
edge.device_config
.ip
.net_addr
.store(dev.net_addr, Ordering::Relaxed);
if let Some(ref chan) = edge.connection_chan {
let _ = chan.send(ConnectionInfo::IPInfo(ip)).await;
}
/*
let mac = match dev.mac.try_into() {
Err(_) => NULL_MAC,
Ok(m) => m,
};
*/
// *edge.device_config.mac.write().unwrap() = mac;
edge.device_config
.ip
.net_bit_len
.store(dev.net_bit_len as u8, Ordering::Relaxed);
edge.device.reload_config(&edge.device_config, &dev.network_domain);
edge.network_id.store(dev.network_id, Ordering::Relaxed);
edge.set_authorized(true, aes);
send_stun_request(edge).await;
tokio::spawn(async {
let nattype = edge.probe_nat_type().await;
debug!("nat type is {:?}", nattype);
// println!("nat type is: {:?}", nattype);
});
}
PacketType::RegisterSuperNAK => {
let Ok(_nak) = SdlRegisterSuperNak::decode(&msg.current_packet[..]) else {
error!("failed to decode REGISTER_SUPER_NAK");
edge.send_register_super_feedback(
msg._packet_id,
RegisterSuperFeedback {
result: 1,
message: "failed to decode REGISTER SUPER NAK".to_owned(),
should_exit: false,
},
);
return;
};
let Ok(error_code) = NakMsgCode::try_from(_nak.error_code as u8) else {
edge.send_register_super_feedback(
msg._packet_id,
RegisterSuperFeedback {
result: 2,
message: "error_code not recognized".to_owned(),
should_exit: false,
},
);
return;
};
match error_code {
NakMsgCode::InvalidToken => {
edge.send_register_super_feedback(
msg._packet_id,
RegisterSuperFeedback {
result: 3,
message: "invalid token".to_owned(),
should_exit: true,
},
);
edge.stop().await;
}
NakMsgCode::NodeDisabled => {
edge.send_register_super_feedback(
msg._packet_id,
RegisterSuperFeedback {
result: 4,
message: "Node is disabled".to_owned(),
should_exit: true,
},
);
edge.stop().await;
}
_other => {
edge.send_register_super_feedback(
msg._packet_id,
RegisterSuperFeedback {
result: 0,
message: "".to_owned(),
should_exit: false,
},
);
}
}
/*
edge.send_register_super_feedback(msg._packet_id, RegisterSuperFeedback {
result: 1,
message: "failed to decode REGISTER SUPER NAK".to_owned(),
});
*/
edge.set_authorized(false, Vec::new());
// std::process::exit(0);
}
PacketType::Command => {
if msg.current_packet.len() < 1 {
error!("malformed COMMAND received");
return;
}
handle_tcp_command(edge, msg.current_packet[0], &msg.current_packet[1..]).await;
}
PacketType::Event => {
if msg.current_packet.len() < 1 {
error!("malformed EVENT received");
return;
}
let Ok(event) = msg.current_packet[0].try_into() else {
error!("failed to parse event type");
return;
};
handle_tcp_event(edge, event, &msg.current_packet[1..]).await;
}
PacketType::PeerInfo => {
let _ = handle_packet_peer_info(edge, &msg.current_packet[..]).await;
}
PacketType::Pong => {
debug!("tcp pong received");
let now = get_current_timestamp();
edge.tcp_pong.store(now, Ordering::Relaxed);
}
other => {
debug!("tcp not handling {:?}", other);
}
}
}
async fn handle_tcp_command(_edge: &Node, _cmdtype: u8, _cmdprotobuf: &[u8]) {}
async fn handle_tcp_event(edge: &'static Node, eventtype: EventType, eventprotobuf: &[u8]) {
match eventtype {
EventType::SendRegister => {
let Ok(reg) = SdlSendRegisterEvent::decode(eventprotobuf) else {
error!("failed to decode SendRegister Event");
return;
};
let v4 = reg.nat_ip.to_be_bytes();
let mut v6_sock = None;
if let Some(v6_info) = reg.v6_info {
if let Ok(v6_bytes) = v6_info.v6.try_into() {
v6_sock = Some(V6Info {
port: v6_info.port as u16,
v6: v6_bytes,
});
}
}
let dst_mac = match reg.dst_mac.try_into() {
Ok(m) => m,
Err(_e) => NULL_MAC,
};
let remote_nat_byte = reg.nat_type as u8;
let remote_nat = match remote_nat_byte.try_into() {
Ok(t) => t,
Err(_) => NatType::NoNat,
};
check_peer_registration_needed(
edge,
false,
dst_mac,
// &v6_sock,
remote_nat,
&v6_sock,
&SdlanSock {
family: AF_INET,
port: reg.nat_port as u16,
v4,
v6: [0; 16],
},
)
.await;
}
other => {
debug!("unhandled event {:?}", other);
}
}
}
pub async fn send_stun_request(eee: &Node) {
let sdl_v6_info = match *eee.ipv6.read().unwrap() {
Some(ref l) => Some(Sdlv6Info {
port: l.port as u32,
v6: Vec::from(l.v6),
}),
None => None,
};
let req = SdlStunRequest {
cookie: 0,
client_id: eee.config.node_uuid.clone(),
network_id: eee.network_id.load(Ordering::Relaxed),
ip: eee.device_config.get_ip(),
mac: Vec::from(eee.device_config.get_mac()),
nat_type: eee.get_nat_type() as u32,
v6_info: sdl_v6_info,
};
debug!("stun request: {:?}", req);
let msg = encode_to_udp_message(Some(req), PacketType::StunRequest as u8).unwrap();
if let Err(e) = send_to_sock(
eee,
&msg,
&eee.config.super_nodes[eee.config.super_node_index.load(Ordering::Relaxed) as usize],
)
.await
{
error!("failed to send to sock: {:?}", e);
}
}
async fn on_disconnected_callback() { async fn on_disconnected_callback() {
let edge = get_edge(); 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 edge = get_edge();
// let installed_channel = install_channel.to_owned(); // let installed_channel = install_channel.to_owned();
let token = edge._token.lock().unwrap().clone(); // let token = edge._token.lock().unwrap().clone();
let code = edge.network_code.lock().unwrap().clone(); // let code = edge.network_code.lock().unwrap().clone();
// let edge = get_edge(); // let edge = get_edge();
// let edge = get_edge(); // let edge = get_edge();
// let token = args.token.clone(); // let token = args.token.clone();
@ -309,20 +64,16 @@ async fn on_connected_callback<'a>(stream: &'a mut tokio::net::TcpStream, pkt_id
} }
} }
let register_super = SdlRegisterSuper { let register_super = SdlRegisterSuper {
version: 1, mac: Vec::from(edge.device_config.get_mac()),
installed_channel: edge.install_channel.clone(), 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, // installed_channel,
client_id: edge.config.node_uuid.clone(), 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(), pub_key: edge.rsa_pubkey.clone(),
token,
network_code: code,
hostname: edge.hostname.read().unwrap().clone(), hostname: edge.hostname.read().unwrap().clone(),
}; };
// debug!("send register super: {:?}", register_super); // 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)] #[derive(Debug)]
pub struct ReadWriterHandle { 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 { pub fn get_tcp_conn() -> &'static ReadWriterHandle {
match GLOBAL_TCP_HANDLE.get() { match GLOBAL_TCP_HANDLE.get() {

View File

@ -1,16 +1,64 @@
use structopt::StructOpt; 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)] #[derive(StructOpt, Debug)]
pub struct CommandLineInput { 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, pub token: String,
#[structopt(short = "p", long = "port", default_value = "0", help="which port to use")] #[structopt(short = "p", long = "port", default_value = "0", help="which port to use")]
pub port: u16, 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")] #[structopt(short= "h", long = "hostname", default_value="", help="specify the hostname")]
pub hostname: String, pub hostname: String,
} }
@ -53,11 +101,11 @@ pub struct CommandLine {
#[structopt(long = "tos", default_value = "0")] #[structopt(long = "tos", default_value = "0")]
pub tos: u32, pub tos: u32,
#[structopt(long = "token", default_value = "")] // #[structopt(long = "token", default_value = "")]
pub token: String, // pub token: String,
#[structopt(long = "code", default_value = "")] // #[structopt(long = "code", default_value = "")]
pub network_code: String, // pub network_code: String,
#[structopt(short = "p")] #[structopt(short = "p")]
pub allow_p2p: bool, pub allow_p2p: bool,
@ -78,8 +126,8 @@ impl Clone for CommandLine {
local_port: self.local_port, local_port: self.local_port,
name: self.name.clone(), name: self.name.clone(),
tos: self.tos, tos: self.tos,
token: self.token.clone(), // token: self.token.clone(),
network_code: self.network_code.clone(), // network_code: self.network_code.clone(),
allow_p2p: self.allow_p2p, allow_p2p: self.allow_p2p,
nat_server1: self.nat_server1.clone(), nat_server1: self.nat_server1.clone(),
nat_server2: self.nat_server2.clone(), nat_server2: self.nat_server2.clone(),

View File

@ -1,14 +1,29 @@
mod command; mod command;
use std::{fs::OpenOptions, io::Write, net::Ipv4Addr, path::Path};
pub use command::*; pub use command::*;
mod socks; mod socks;
use rand::Rng; use rand::Rng;
use sdlan_sn_rs::utils::Mac; use sdlan_sn_rs::utils::{Mac, Result, SDLanError};
use serde::{Deserialize, Serialize};
pub use socks::*; pub use socks::*;
use crate::get_base_dir;
mod pid_recorder; 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); // pub const CRC_HASH: crc::Crc<u32> = crc::Crc::<u32>::new(&crc::CRC_32_XFER);
#[allow(unused)] #[allow(unused)]
@ -17,6 +32,57 @@ pub fn caculate_crc(data: &[u8]) -> u32 {
res 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 { pub fn mac_to_string(mac: &Mac) -> String {
format!( format!(
"[{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}]", "[{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}]",