Initial commit: Project structure, Coordinator Server v1.0.0, and Documentation
This commit is contained in:
commit
0ead98d0c4
18 files changed
+2073
No files matched your search
@@ -0,0 +1,9 @@
|
||||
target/
|
||||
.git/
|
||||
.env
|
||||
*.exe
|
||||
*.msi
|
||||
udp-hole-punch/
|
||||
wintun-rust/
|
||||
meshvpn-dashboard/
|
||||
node_modules/
|
||||
Generated
+723
@@ -0,0 +1,723 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aead"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher",
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes-gcm"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
|
||||
dependencies = [
|
||||
"aead",
|
||||
"aes",
|
||||
"cipher",
|
||||
"ctr",
|
||||
"ghash",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blake2"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f360145194ee8e21db5ee7f3fcd4fe52210864c75c985dae33218202c8bbe040"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
|
||||
|
||||
[[package]]
|
||||
name = "chacha20"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher",
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chacha20poly1305"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
|
||||
dependencies = [
|
||||
"aead",
|
||||
"chacha20",
|
||||
"cipher",
|
||||
"poly1305",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"inout",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03e8bd762f7479489c70ed6c768ddca99d7296857de437a68dcb2a94365b3fae"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctr"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
|
||||
dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek"
|
||||
version = "4.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"curve25519-dalek-derive",
|
||||
"fiat-crypto",
|
||||
"rustc_version",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek-derive"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
|
||||
dependencies = [
|
||||
"humantime",
|
||||
"is-terminal",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fiat-crypto"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasip2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ghash"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1"
|
||||
dependencies = [
|
||||
"opaque-debug",
|
||||
"polyval",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15cdd26707701c53297e2fa6afb323d55fbc1d0810c3aec078ae3ef0424c3c15"
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.189"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||
|
||||
[[package]]
|
||||
name = "poly1305"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
|
||||
dependencies = [
|
||||
"cpufeatures",
|
||||
"opaque-debug",
|
||||
"universal-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polyval"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"opaque-debug",
|
||||
"universal-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom 0.2.17",
|
||||
"libc",
|
||||
"untrusted",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-data-plane"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"crossbeam-queue",
|
||||
"env_logger",
|
||||
"log",
|
||||
"snow",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
|
||||
|
||||
[[package]]
|
||||
name = "snow"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "599b506ccc4aff8cf7844bc42cf783009a434c1e26c964432560fb6d6ad02d82"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"blake2",
|
||||
"chacha20poly1305",
|
||||
"curve25519-dalek",
|
||||
"getrandom 0.3.4",
|
||||
"ring",
|
||||
"rustc_version",
|
||||
"sha2",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.119"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
|
||||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.1+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "wasip2"
|
||||
version = "1.0.4+wasi-0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.57.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "rust-data-plane"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1", features = ["rt", "net", "macros"] }
|
||||
bytes = "1.5"
|
||||
crossbeam-queue = "0.3"
|
||||
log = "0.4"
|
||||
env_logger = "0.10"
|
||||
snow = "0.10.0"
|
||||
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "udp-hole-punch"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
byteorder = "1.5"
|
||||
rand = "0.8"
|
||||
@@ -0,0 +1,105 @@
|
||||
use std::net::SocketAddr;
|
||||
use tokio::net::UdpSocket;
|
||||
use byteorder::{BigEndian, WriteBytesExt};
|
||||
use rand::RngCore;
|
||||
use std::sync::Arc;
|
||||
use tokio::time::{sleep, Duration};
|
||||
|
||||
async fn get_public_addr(socket: &UdpSocket, stun_server: &str) -> Result<SocketAddr, Box<dyn std::error::Error>> {
|
||||
let mut request = Vec::with_capacity(20);
|
||||
request.write_u16::<BigEndian>(0x0001)?;
|
||||
request.write_u16::<BigEndian>(0)?;
|
||||
request.write_u32::<BigEndian>(0x2112A442)?;
|
||||
let mut transaction_id = [0u8; 12];
|
||||
rand::thread_rng().fill_bytes(&mut transaction_id);
|
||||
request.extend_from_slice(&transaction_id);
|
||||
|
||||
socket.send_to(&request, stun_server).await?;
|
||||
let mut buf = [0u8; 1024];
|
||||
let (len, _) = socket.recv_from(&mut buf).await?;
|
||||
|
||||
if len < 20 { return Err("Response too short".into()); }
|
||||
if u16::from_be_bytes([buf[0], buf[1]]) != 0x0101 { return Err("Not a binding response".into()); }
|
||||
|
||||
let mut pos = 20;
|
||||
while pos + 4 <= len {
|
||||
let attr_type = u16::from_be_bytes([buf[pos], buf[pos+1]]);
|
||||
let attr_len = u16::from_be_bytes([buf[pos+2], buf[pos+3]]) as usize;
|
||||
pos += 4;
|
||||
if attr_type == 0x0020 {
|
||||
let xored_port = u16::from_be_bytes([buf[pos], buf[pos+1]]);
|
||||
let xored_ip = [buf[pos+2], buf[pos+3], buf[pos+4], buf[pos+5]];
|
||||
let port = xored_port ^ 0x2112;
|
||||
let ip = [xored_ip[0] ^ 0x21, xored_ip[1] ^ 0x12, xored_ip[2] ^ 0xA4, xored_ip[3] ^ 0x42];
|
||||
return Ok(SocketAddr::new(std::net::Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]), port));
|
||||
}
|
||||
pos += attr_len;
|
||||
}
|
||||
Err("XOR-MAPPED-ADDRESS not found".into())
|
||||
}
|
||||
|
||||
async fn detect_nat_type(socket: &UdpSocket) -> Result<String, Box<dyn std::error::Error>> {
|
||||
// To detect Symmetric NAT, we query two different STUN servers.
|
||||
// If they report different public ports for the same internal socket, it's Symmetric.
|
||||
let server1 = "stun.l.google.com:19302";
|
||||
let server2 = "stun1.l.google.com:19302"; // Using another Google STUN server if available, or similar
|
||||
|
||||
let addr1 = get_public_addr(socket, server1).await?;
|
||||
let addr2 = get_public_addr(socket, server2).await?;
|
||||
|
||||
if addr1.port() == addr2.port() {
|
||||
Ok("Cone NAT".to_string())
|
||||
} else {
|
||||
Ok("Symmetric NAT".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
async fn punch_hole(socket: Arc<UdpSocket>, peer_addr: SocketAddr) {
|
||||
println!("Starting hole punching to {}", peer_addr);
|
||||
for i in 0..15 {
|
||||
let msg = format!("Punch {} from {}", i, socket.local_addr().unwrap());
|
||||
let _ = socket.send_to(msg.as_bytes(), peer_addr).await;
|
||||
sleep(Duration::from_millis(300)).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn listen_for_peer(socket: Arc<UdpSocket>) {
|
||||
let mut buf = [0u8; 1024];
|
||||
loop {
|
||||
if let Ok((len, addr)) = socket.recv_from(&mut buf).await {
|
||||
let msg = String::from_utf8_lossy(&buf[..len]);
|
||||
println!("Received from {}: {}", addr, msg);
|
||||
if msg.contains("Punch") {
|
||||
println!("Hole punched successfully from {}!", addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let socket = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
|
||||
println!("Local address: {}", socket.local_addr()?);
|
||||
|
||||
let nat_type = detect_nat_type(&socket).await.unwrap_or_else(|_| "Unknown".to_string());
|
||||
println!("Detected NAT Type: {}", nat_type);
|
||||
|
||||
let public_addr = get_public_addr(&socket, "stun.l.google.com:19302").await?;
|
||||
println!("Public address: {}", public_addr);
|
||||
|
||||
println!("Enter peer's public address (IP:PORT) or 'skip':");
|
||||
let mut input = String::new();
|
||||
std::io::stdin().read_line(&mut input)?;
|
||||
let input = input.trim();
|
||||
|
||||
if input != "skip" {
|
||||
let peer_addr: SocketAddr = input.parse().expect("Invalid address");
|
||||
let s_clone = Arc::clone(&socket);
|
||||
tokio::spawn(async move {
|
||||
punch_hole(s_clone, peer_addr).await;
|
||||
});
|
||||
}
|
||||
|
||||
listen_for_peer(socket).await;
|
||||
Ok(())
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
# MeshVPN - High Performance Overlay Network
|
||||
|
||||
A production-grade, lightweight mesh VPN solution designed for zero-config connectivity.
|
||||
|
||||
## 🚀 Overview
|
||||
MeshVPN allows you to create a secure, peer-to-peer encrypted network across Windows, macOS, and Linux without requiring manual port forwarding.
|
||||
|
||||
### Key Features
|
||||
- **All-in-One Coordinator**: Integrated STUN, Coordination, and WebUI.
|
||||
- **Zero-Config Onboarding**: Join a network using a single shared "Network Key".
|
||||
- **Extreme Performance**: Rust-based data plane with memory footprint < 256MB.
|
||||
- **NAT Traversal**: Advanced UDP hole punching and blind relay (DERP) support.
|
||||
- **Professional UI**: Enterprise-grade glassmorphism dashboard for server monitoring.
|
||||
|
||||
## 📂 Project Structure
|
||||
- `/server`: Go-based Coordinator, STUN, and Web Dashboard.
|
||||
- `/client`: Rust-based cross-platform client agent.
|
||||
- `install_meshvpn.sh`: Automated one-click VPS deployment script.
|
||||
- `/docs`: Technical specifications and deployment guides.
|
||||
|
||||
## 🛠 Installation
|
||||
|
||||
### Server (VPS)
|
||||
Run the automated installer on your Ubuntu VPS:
|
||||
```bash
|
||||
chmod +x install_meshvpn.sh
|
||||
sudo ./install_meshvpn.sh
|
||||
```
|
||||
Then start the server:
|
||||
```bash
|
||||
cd ~/meshvpn/server && go run main.go
|
||||
```
|
||||
|
||||
### Client (Windows/Linux/macOS)
|
||||
1. Install the [Rust toolchain](https://rustup.rs/).
|
||||
2. Build the release binary:
|
||||
```bash
|
||||
cargo build --release
|
||||
```
|
||||
3. Run as Administrator/Root.
|
||||
|
||||
## 🛡 Security
|
||||
- **E2EE**: All traffic is encrypted via the Noise Protocol (WireGuard).
|
||||
- **Zero-Trust Coordination**: The server facilitates introductions but cannot decrypt user traffic.
|
||||
- **Identity**: Nodes are identified by a combination of a shared network key and unique public keys.
|
||||
|
||||
## 📄 License
|
||||
MIT License
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="MeshVPN.Client" type="win32" />
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
</assembly>
|
||||
@@ -0,0 +1,42 @@
|
||||
# MeshVPN Client
|
||||
|
||||
The MeshVPN Client creates a secure, peer-to-peer overlay network on your machine. It uses WireGuard encryption and UDP hole punching to connect you to other peers without needing manual port forwarding.
|
||||
|
||||
## Features
|
||||
- **Zero-Config Connection**: Connect using a simple Network Key.
|
||||
- **Cross-Platform**: Supports Windows, macOS, and Linux.
|
||||
- **Secure E2EE**: End-to-end encryption powered by the Noise Protocol.
|
||||
- **Automatic NAT Traversal**: Bypasses firewalls using STUN and UDP hole punching.
|
||||
|
||||
## Installation
|
||||
|
||||
### Prerequisites
|
||||
- [Rust](https://rustup.rs/) (Stable channel)
|
||||
- **Administrator/Root Privileges**: Required to create the virtual TUN interface.
|
||||
|
||||
### Setup
|
||||
1. **Clone the repository**
|
||||
2. **Build the client**:
|
||||
```bash
|
||||
cargo build --release
|
||||
```
|
||||
3. **Install TUN Driver**:
|
||||
- **Windows**: Install `Wintun` (bundled with the installer).
|
||||
- **macOS**: Grant permissions for the Network Extension.
|
||||
- **Linux**: Ensure the `tun` module is loaded (`modprobe tun`).
|
||||
|
||||
## Usage
|
||||
|
||||
1. **Start the Client**:
|
||||
```bash
|
||||
./target/release/meshvpn-client
|
||||
```
|
||||
2. **Configure Your Node**:
|
||||
- **Network Key**: Enter the shared key provided by your network administrator.
|
||||
- **User Name**: Enter your preferred display name (e.g., "My-Laptop").
|
||||
3. **Connect**:
|
||||
The client will automatically discover the coordinator, register your node, and start discovering peers.
|
||||
|
||||
## Troubleshooting
|
||||
- **Permission Denied**: Ensure you are running the client as Administrator (Windows) or using `sudo` (Linux/macOS).
|
||||
- **Cannot Connect**: Check if UDP port 3478 (STUN) and 50051 (Coordinator) are reachable from your network.
|
||||
@@ -0,0 +1,38 @@
|
||||
# Windows Deployment Guide (.exe)
|
||||
|
||||
To ensure the client is a lightweight `.exe` that consumes less than 256MB of RAM, follow these build instructions.
|
||||
|
||||
## 🛠 Build Process
|
||||
|
||||
1. **Environment Setup**:
|
||||
- Install [Rust](https://rustup.rs/).
|
||||
- Install [LLVM](https://llvm.org/build/) (required for some networking crates).
|
||||
|
||||
2. **Optimization Flags**:
|
||||
To keep the binary small and memory usage low, use the following `Cargo.toml` profile:
|
||||
```toml
|
||||
[profile.release]
|
||||
opt-level = 'z' # Optimize for size
|
||||
lto = true # Link Time Optimization
|
||||
codegen-units = 1 # Maximize optimization
|
||||
panic = 'abort' # Remove stack unwinding (saves space/RAM)
|
||||
strip = true # Remove symbols from the binary
|
||||
```
|
||||
|
||||
3. **Building the .exe**:
|
||||
```bash
|
||||
cargo build --release
|
||||
```
|
||||
The resulting executable will be in `target/release/meshvpn-client.exe`.
|
||||
|
||||
## 📦 Resource Constraints (< 256MB RAM)
|
||||
To guarantee low memory usage:
|
||||
- **Asynchronous Runtime**: Using `tokio` with the `current_thread` scheduler instead of `multi_thread` to reduce thread overhead.
|
||||
- **Zero-Copy**: Using `bytes` crate for packet handling to avoid unnecessary memory allocations.
|
||||
- **No GUI**: By keeping it a CLI tool, we avoid the massive overhead of Electron or similar frameworks.
|
||||
|
||||
## 🚦 Administrator Requirements
|
||||
The `.exe` must be run as **Administrator** to:
|
||||
1. Load the `wintun.dll`.
|
||||
2. Create the virtual network adapter.
|
||||
3. Set routing table entries.
|
||||
+404
@@ -0,0 +1,404 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Enterprise MeshVPN Dashboard</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=JetBrains+Mono&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
/* Surfaces */
|
||||
--chart-surface: #0F172A;
|
||||
--component-surface: rgba(30, 41, 59, 0.7);
|
||||
--border-color: rgba(51, 65, 85, 0.5);
|
||||
|
||||
/* Text */
|
||||
--text-primary: #F8FAFC;
|
||||
--text-muted: #94A3B8;
|
||||
|
||||
/* Status Palette */
|
||||
--status-good: #10B981;
|
||||
--status-warning: #F59E0B;
|
||||
--status-serious: #EF4444;
|
||||
--status-critical: #7F1D1D;
|
||||
|
||||
/* Categorical Theme */
|
||||
--color-1: #06B6D4; /* Electric Cyan */
|
||||
--color-2: #6366F1; /* Royal Indigo */
|
||||
--color-3: #8B5CF6; /* Vivid Violet */
|
||||
--color-4: #D946EF; /* Deep Magenta */
|
||||
--color-5: #FACC15; /* Goldenrod */
|
||||
--color-6: #4ADE80; /* Spring Green */
|
||||
|
||||
/* Glassmorphism */
|
||||
--glass-bg: rgba(30, 41, 59, 0.6);
|
||||
--glass-border: rgba(255, 255, 255, 0.1);
|
||||
--glass-blur: blur(12px);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--chart-surface);
|
||||
color: var(--text-primary);
|
||||
font-family: 'Inter', "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
min-height: 100vh;
|
||||
padding: 2rem;
|
||||
background-image:
|
||||
radial-gradient(circle at 0% 0%, rgba(6, 182, 212, 0.05) 0%, transparent 25%),
|
||||
radial-gradient(circle at 100% 100%, rgba(99, 102, 241, 0.05) 0%, transparent 25%);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.02em;
|
||||
margin-bottom: 2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
h1::before {
|
||||
content: '';
|
||||
width: 4px;
|
||||
height: 24px;
|
||||
background: var(--color-1);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.dashboard-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(12, 1fr);
|
||||
gap: 1.5rem;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* Glass Card Style */
|
||||
.card {
|
||||
background: var(--glass-bg);
|
||||
backdrop-filter: var(--glass-blur);
|
||||
-webkit-backdrop-filter: var(--glass-blur);
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 12px;
|
||||
padding: 1.5rem;
|
||||
transition: transform 0.2s ease, border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
border-color: rgba(6, 182, 212, 0.3);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
letter-spacing: -0.01em;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 1.25rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card-title span {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: var(--text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
/* Header Stats */
|
||||
.stats-row {
|
||||
grid-column: span 12;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.stat-tile {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
}
|
||||
|
||||
/* Node List */
|
||||
.node-list-card {
|
||||
grid-column: span 8;
|
||||
}
|
||||
|
||||
.table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.table th {
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-muted);
|
||||
padding-bottom: 1rem;
|
||||
font-weight: 500;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.table td {
|
||||
padding: 1rem 0;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.table tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* Status Pill */
|
||||
.status-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.status-online { color: var(--status-good); }
|
||||
.status-online .status-dot {
|
||||
background: var(--status-good);
|
||||
box-shadow: 0 0 8px var(--status-good);
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
.status-degraded { color: var(--status-warning); }
|
||||
.status-degraded .status-dot { background: var(--status-warning); }
|
||||
|
||||
.status-offline { color: var(--status-serious); }
|
||||
.status-offline .status-dot { background: var(--status-serious); }
|
||||
|
||||
@keyframes pulse {
|
||||
0% { opacity: 1; transform: scale(1); }
|
||||
50% { opacity: 0.5; transform: scale(1.2); }
|
||||
100% { opacity: 1; transform: scale(1); }
|
||||
}
|
||||
|
||||
/* Ports Section */
|
||||
.ports-card {
|
||||
grid-column: span 4;
|
||||
}
|
||||
|
||||
.port-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.port-item {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border: 1px solid var(--border-color);
|
||||
padding: 0.75rem;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.port-num {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.port-meta {
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
/* Version Footer */
|
||||
.version-card {
|
||||
grid-column: span 12;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 1rem 1.5rem;
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.version-tag {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
color: var(--color-1);
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 1024px) {
|
||||
.node-list-card, .ports-card {
|
||||
grid-column: span 12;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
body { padding: 1rem; }
|
||||
.stats-row { grid-template-columns: 1fr; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>MeshVPN Enterprise Control</h1>
|
||||
|
||||
<div class="dashboard-grid">
|
||||
<!-- KPI Section -->
|
||||
<div class="stats-row">
|
||||
<div class="card stat-tile">
|
||||
<div class="stat-label">Global Latency</div>
|
||||
<div class="stat-value" style="color: var(--color-1);">24ms</div>
|
||||
<div class="stat-label" style="font-size: 10px;">↓ 2ms from last hour</div>
|
||||
</div>
|
||||
<div class="card stat-tile">
|
||||
<div class="stat-label">Packet Loss</div>
|
||||
<div class="stat-value" style="color: var(--status-good);">0.001%</div>
|
||||
<div class="stat-label" style="font-size: 10px;">Stable baseline</div>
|
||||
</div>
|
||||
<div class="card stat-tile">
|
||||
<div class="stat-label">Uptime (90d)</div>
|
||||
<div class="stat-value" style="color: var(--color-2);">99.998%</div>
|
||||
<div class="stat-label" style="font-size: 10px;">Enterprise SLA Active</div>
|
||||
</div>
|
||||
<div class="card stat-tile">
|
||||
<div class="stat-label">Active Tunnels</div>
|
||||
<div class="stat-value">1,284</div>
|
||||
<div class="stat-label" style="font-size: 10px;">+12 nodes today</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Nodes List -->
|
||||
<div class="card node-list-card">
|
||||
<div class="card-title">
|
||||
Connected Nodes
|
||||
<span>Live Status</span>
|
||||
</div>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Node Identity</th>
|
||||
<th>Address</th>
|
||||
<th>Region</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>core-gateway-01</strong></td>
|
||||
<td style="font-family: 'JetBrains Mono', monospace;">100.64.0.1</td>
|
||||
<td>us-east-1</td>
|
||||
<td><div class="status-pill status-online"><div class="status-dot"></div>Online</div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>edge-london-alpha</strong></td>
|
||||
<td style="font-family: 'JetBrains Mono', monospace;">100.64.12.45</td>
|
||||
<td>eu-west-2</td>
|
||||
<td><div class="status-pill status-online"><div class="status-dot"></div>Online</div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>dev-workstation-x</strong></td>
|
||||
<td style="font-family: 'JetBrains Mono', monospace;">100.64.88.102</td>
|
||||
<td>remote-home</td>
|
||||
<td><div class="status-pill status-degraded"><div class="status-dot"></div>Degraded</div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>backup-vault-s3</strong></td>
|
||||
<td style="font-family: 'JetBrains Mono', monospace;">100.64.201.11</td>
|
||||
<td>us-west-2</td>
|
||||
<td><div class="status-pill status-offline"><div class="status-dot"></div>Offline</div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>tokyo-relayer-01</strong></td>
|
||||
<td style="font-family: 'JetBrains Mono', monospace;">100.64.45.22</td>
|
||||
<td>ap-northeast-1</td>
|
||||
<td><div class="status-pill status-online"><div class="status-dot"></div>Online</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- System Ports -->
|
||||
<div class="card ports-card">
|
||||
<div class="card-title">
|
||||
Active Ports
|
||||
<span>Network Stack</span>
|
||||
</div>
|
||||
<div class="port-grid">
|
||||
<div class="port-item">
|
||||
<div class="port-num">443</div>
|
||||
<div class="port-meta"><span>HTTPS / TCP</span><span style="color: var(--status-good);">Open</span></div>
|
||||
</div>
|
||||
<div class="port-item">
|
||||
<div class="port-num">80</div>
|
||||
<div class="port-meta"><span>HTTP / TCP</span><span style="color: var(--status-serious);">Closed</span></div>
|
||||
</div>
|
||||
<div class="port-item">
|
||||
<div class="port-num">51820</div>
|
||||
<div class="port-meta"><span>WireGuard / UDP</span><span style="color: var(--status-good);">Open</span></div>
|
||||
</div>
|
||||
<div class="port-item">
|
||||
<div class="port-num">22</div>
|
||||
<div class="port-meta"><span>SSH / TCP</span><span style="color: var(--status-warning);">Filtered</span></div>
|
||||
</div>
|
||||
<div class="port-item">
|
||||
<div class="port-num">8080</div>
|
||||
<div class="port-meta"><span>API / TCP</span><span style="color: var(--status-good);">Open</span></div>
|
||||
</div>
|
||||
<div class="port-item">
|
||||
<div class="port-num">9000</div>
|
||||
<div class="port-meta"><span>Metric / TCP</span><span style="color: var(--status-good);">Open</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="card version-card">
|
||||
<div>System Status: <span style="color: var(--status-good);">Operational</span></div>
|
||||
<div>
|
||||
Server Version: <span class="version-tag">v2.4.12-enterprise-stable</span>
|
||||
</div>
|
||||
<div>© 2026 MeshVPN Systems Inc.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,197 @@
|
||||
#!/bin/bash
|
||||
|
||||
# MeshVPN "Idiot-Proof" Full Installer - Version 1.0.0
|
||||
# This script handles EVERYTHING: Cleaning, Deps, Files, Config, and Deployment.
|
||||
|
||||
set -e
|
||||
|
||||
VERSION="1.0.0"
|
||||
INSTALL_DIR="$HOME/meshvpn"
|
||||
|
||||
# Colors for better UX
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${BLUE}=======================================================${NC}"
|
||||
echo -e "${BLUE} 🚀 MeshVPN All-in-One Server Deployment ${NC}"
|
||||
echo -e "${BLUE} Version: $VERSION ${NC}"
|
||||
echo -e "${BLUE}=======================================================${NC}"
|
||||
|
||||
# 1. Clean Old Versions
|
||||
echo -e "\n${YELLOW}[1/7] Cleaning previous deployments...${NC}"
|
||||
if [ -d "$INSTALL_DIR" ]; then
|
||||
echo "Removing old installation at $INSTALL_DIR..."
|
||||
rm -rf "$INSTALL_DIR"
|
||||
fi
|
||||
echo "Stopping existing MeshVPN processes..."
|
||||
pkill -f "go run main.go" || echo "No running server found."
|
||||
pkill -f "main" || echo "No running binary found."
|
||||
|
||||
# 2. System Dependencies
|
||||
echo -e "\n${GREEN}[2/7] Installing System Dependencies...${NC}"
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y golang-go redis-server postgresql postgresql-contrib ufw curl git
|
||||
|
||||
# 3. Database Setup
|
||||
echo -e "\n${GREEN}[3/7] Setting up Databases...${NC}"
|
||||
sudo systemctl start postgresql
|
||||
sudo systemctl enable postgresql
|
||||
sudo -u postgres psql -c "CREATE USER meshvpn WITH PASSWORD 'password';" || echo "User exists"
|
||||
sudo -u postgres psql -c "CREATE DATABASE meshvpn OWNER meshvpn;" || echo "DB exists"
|
||||
sudo systemctl start redis-server
|
||||
sudo systemctl enable redis-server
|
||||
|
||||
# 4. Project Structure & Files
|
||||
echo -e "\n${GREEN}[4/7] Deploying Version $VERSION Files...${NC}"
|
||||
mkdir -p "$INSTALL_DIR/server/api"
|
||||
|
||||
# Create the proto file
|
||||
cat <<EOF > "$INSTALL_DIR/server/api/coordinator.proto"
|
||||
syntax = "proto3";
|
||||
package coordinator;
|
||||
option go_package = "server/api";
|
||||
service Coordinator {
|
||||
rpc RegisterNode(RegisterRequest) returns (RegisterResponse);
|
||||
rpc UpdateNodeName(UpdateNameRequest) returns (UpdateNameResponse);
|
||||
rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse);
|
||||
rpc GetPeerEndpoint(PeerRequest) returns (PeerResponse);
|
||||
rpc SignalConnection(SignalRequest) returns (SignalResponse);
|
||||
}
|
||||
message RegisterRequest {
|
||||
string network_key = 1;
|
||||
string node_id = 2;
|
||||
string public_key = 3;
|
||||
string local_ip = 4;
|
||||
}
|
||||
message RegisterResponse {
|
||||
string virtual_ip = 1;
|
||||
string session_token = 2;
|
||||
string coordinator_address = 3;
|
||||
string assigned_name = 4;
|
||||
}
|
||||
message UpdateNameRequest {
|
||||
string node_id = 1;
|
||||
string new_name = 2;
|
||||
string session_token = 3;
|
||||
}
|
||||
message UpdateNameResponse {
|
||||
bool success = 1;
|
||||
string current_name = 2;
|
||||
}
|
||||
message HeartbeatRequest {
|
||||
string node_id = 1;
|
||||
string session_token = 2;
|
||||
string public_endpoint = 3;
|
||||
}
|
||||
message HeartbeatResponse {
|
||||
bool success = 1;
|
||||
}
|
||||
message PeerRequest {
|
||||
string target_node_id = 1;
|
||||
string session_token = 2;
|
||||
}
|
||||
message PeerResponse {
|
||||
string peer_public_key = 1;
|
||||
string public_endpoint = 2;
|
||||
string nat_type = 3;
|
||||
}
|
||||
message SignalRequest {
|
||||
string source_node_id = 1;
|
||||
string target_node_id = 2;
|
||||
string session_token = 3;
|
||||
}
|
||||
message SignalResponse {
|
||||
bool acknowledged = 1;
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create the main server file
|
||||
cat <<EOF > "$INSTALL_DIR/server/main.go"
|
||||
package main
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/reflection"
|
||||
)
|
||||
type CoordinatorServer struct {}
|
||||
func (s *CoordinatorServer) RegisterNode(ctx interface{}, req interface{}) (interface{}, error) { return nil, nil }
|
||||
func (s *CoordinatorServer) UpdateNodeName(ctx interface{}, req interface{}) (interface{}, error) { return nil, nil }
|
||||
func (s *CoordinatorServer) Heartbeat(ctx interface{}, req interface{}) (interface{}, error) { return nil, nil }
|
||||
func (s *CoordinatorServer) GetPeerEndpoint(ctx interface{}, req interface{}) (interface{}, error) { return nil, nil }
|
||||
func (s *CoordinatorServer) SignalConnection(ctx interface{}, req interface{}) (interface{}, error) { return nil, nil }
|
||||
func startSTUNServer(port int) {
|
||||
addr := fmt.Sprintf(":%d", port)
|
||||
conn, err := net.ListenUDP("udp", &net.UDPAddr{Port: port})
|
||||
if err != nil { log.Fatalf("STUN failed: %v", err) }
|
||||
defer conn.Close()
|
||||
fmt.Printf("STUN listening on %s\n", addr)
|
||||
buf := make([]byte, 1024)
|
||||
for {
|
||||
_, remoteAddr, err := conn.ReadFromUDP(buf)
|
||||
if err != nil { continue }
|
||||
response := []byte(fmt.Sprintf("STUN_RESP:%s", remoteAddr.String()))
|
||||
conn.WriteToUDP(response, remoteAddr)
|
||||
}
|
||||
}
|
||||
func startWebUI(port int) {
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
fmt.Fprintf(w, "<html><body style='background:#1a1a1a;color:#eee;text-align:center;padding:50px;font-family:sans-serif;'><h1>🚀 MeshVPN Coordinator v$VERSION</h1><div style='background:#2a2a2a;padding:20px;border-radius:10px;display:inline-block;border:1px solid #444;'><p>STUN Port: <b style='color:#00ffaa;'>3478 (UDP)</b></p><p>Coord Port: <b style='color:#00ffaa;'>50051 (TCP)</b></p><p>Web Port: <b style='color:#00ffaa;'>8080 (TCP)</b></p></div><p style='margin-top:20px;color:#666;'>Status: <span style='color:#00ffaa;'>ONLINE</span></p></body></html>")
|
||||
})
|
||||
fmt.Printf("WebUI listening on :%d\n", port)
|
||||
http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
|
||||
}
|
||||
func main() {
|
||||
go startSTUNServer(3478)
|
||||
go startWebUI(8080)
|
||||
lis, err := net.Listen("tcp", ":50051")
|
||||
if err != nil { log.Fatalf("failed to listen: %v", err) }
|
||||
s := grpc.NewServer()
|
||||
reflection.Register(s)
|
||||
fmt.Println("Coordinator Server listening on :50051")
|
||||
s.Serve(lis)
|
||||
}
|
||||
EOF
|
||||
|
||||
# Initialize Go module
|
||||
cd "$INSTALL_DIR/server"
|
||||
go mod init meshvpn-server
|
||||
go mod tidy
|
||||
|
||||
# 5. Firewall
|
||||
echo -e "\n${GREEN}[5/7] Opening Ports...${NC}"
|
||||
sudo ufw allow 22/tcp
|
||||
sudo ufw allow 3478/udp
|
||||
sudo ufw allow 50051/tcp
|
||||
sudo ufw allow 8080/tcp
|
||||
sudo ufw --force enable
|
||||
|
||||
# 6. Network Identity
|
||||
echo -e "\n${GREEN}[6/7] Network Identity...${NC}"
|
||||
# Get actual public IP instead of localhost
|
||||
PUBLIC_IP=$(curl -s https://api.ipify.org || echo "Unknown")
|
||||
echo -e "Detected Public IP: ${BLUE}$PUBLIC_IP${NC}"
|
||||
read -p "Keep this IP or enter a custom domain (e.g., vpn.example.com) [Enter for $PUBLIC_IP]: " CUSTOM_DOMAIN
|
||||
|
||||
if [ -z "$CUSTOM_DOMAIN" ]; then
|
||||
DOMAIN=$PUBLIC_IP
|
||||
else
|
||||
DOMAIN=$CUSTOM_DOMAIN
|
||||
fi
|
||||
|
||||
echo "DOMAIN=$DOMAIN" > "$INSTALL_DIR/.env"
|
||||
echo -e "Coordinator will be reachable at: ${BLUE}$DOMAIN${NC}"
|
||||
|
||||
# 7. Final Launch
|
||||
echo -e "\n${GREEN}[7/7] Finalizing...${NC}"
|
||||
echo "-------------------------------------------------------"
|
||||
echo -e "${BLUE}✅ Setup Complete! Version $VERSION deployed.${NC}"
|
||||
echo "Your MeshVPN server is now configured."
|
||||
echo "To start the server: cd $INSTALL_DIR/server && go run main.go"
|
||||
echo "-------------------------------------------------------"
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
|
||||
<Package Name="MeshVPN Client"
|
||||
Manufacturer="MeshVPN"
|
||||
Version="1.0.0.0"
|
||||
UpgradeCode="53a08b3d-b9da-48d5-9454-59dbcbd0c7bc"
|
||||
Language="1033">
|
||||
|
||||
<!-- Request Administrator Privileges -->
|
||||
<Package InstallPrivileges="elevated" />
|
||||
|
||||
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
|
||||
|
||||
<Feature Id="Main">
|
||||
<ComponentGroupRef Id="ProductComponents" />
|
||||
</Feature>
|
||||
|
||||
<ComponentGroup Id="ProductComponents">
|
||||
<!-- The main executable -->
|
||||
<Component Guid="0f8328ee-1e2c-4de6-9e2c-e86799b18f70">
|
||||
<File Source="bin\client.exe" KeyPath="yes" />
|
||||
</Component>
|
||||
|
||||
<!-- Bundling wintun.dll -->
|
||||
<Component Guid="bbfda103-64e2-4add-a2b2-e14faaaec1d9">
|
||||
<File Source="bin\wintun.dll" />
|
||||
</Component>
|
||||
</ComponentGroup>
|
||||
|
||||
<!-- Windows Service Configuration -->
|
||||
<ServiceInstall Id="ServiceInstaller"
|
||||
Name="MeshVPNService"
|
||||
DisplayName="MeshVPN Client Service"
|
||||
Type="ownProcess"
|
||||
Start="auto"
|
||||
ErrorControl="normal"
|
||||
Account="LocalSystem"
|
||||
Password="" />
|
||||
|
||||
<ServiceControl Id="ServiceControl"
|
||||
Name="MeshVPNService"
|
||||
Start="install"
|
||||
Stop="uninstall"
|
||||
Remove="uninstall" />
|
||||
|
||||
</Package>
|
||||
</Wix>
|
||||
@@ -0,0 +1,39 @@
|
||||
# MeshVPN Coordinator Server
|
||||
|
||||
The Coordinator Server is the central brain of the MeshVPN network. It handles node registration, peer signaling, and provides STUN services for NAT traversal.
|
||||
|
||||
## Features
|
||||
- **Integrated STUN Server**: Helps clients discover their public endpoints.
|
||||
- **Node Coordination**: Manages public keys and virtual IP assignments.
|
||||
- **Signaling**: Facilitates UDP hole punching between peers.
|
||||
- **Web Dashboard**: (Coming soon) Visualization of the mesh network.
|
||||
|
||||
## Installation
|
||||
|
||||
### Prerequisites
|
||||
- [Go](https://go.dev/dl/) (1.21+)
|
||||
- [Redis](https://redis.io/download) (For real-time node state)
|
||||
- [PostgreSQL](https://www.postgresql.org/download/) (For identity and ACLs)
|
||||
|
||||
### Setup
|
||||
1. **Clone the repository**
|
||||
2. **Install dependencies**:
|
||||
```bash
|
||||
go mod tidy
|
||||
```
|
||||
3. **Configure Environment**:
|
||||
Create a `.env` file with:
|
||||
```env
|
||||
REDIS_ADDR=localhost:6379
|
||||
POSTGRES_URL=postgres://user:pass@localhost:5432/meshvpn
|
||||
STUN_PORT=3478
|
||||
COORD_PORT=50051
|
||||
```
|
||||
4. **Run the server**:
|
||||
```bash
|
||||
go run main.go
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
- **STUN**: UDP port 3478
|
||||
- **gRPC Coordinator**: TCP port 50051
|
||||
@@ -0,0 +1,78 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package coordinator;
|
||||
|
||||
option go_package = "server/api";
|
||||
|
||||
service Coordinator {
|
||||
// Registers a node. User name is auto-generated by server initially.
|
||||
rpc RegisterNode(RegisterRequest) returns (RegisterResponse);
|
||||
|
||||
// Updates the display name of the node (allows user to change it later).
|
||||
rpc UpdateNodeName(UpdateNameRequest) returns (UpdateNameResponse);
|
||||
|
||||
// Heartbeat to keep the node marked as online in Redis.
|
||||
rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse);
|
||||
|
||||
// Requests the connection details for a target peer.
|
||||
rpc GetPeerEndpoint(PeerRequest) returns (PeerResponse);
|
||||
|
||||
// Notifies the coordinator that a node wants to establish a connection.
|
||||
rpc SignalConnection(SignalRequest) returns (SignalResponse);
|
||||
}
|
||||
|
||||
message RegisterRequest {
|
||||
string network_key = 1; // The shared secret for this overlay network
|
||||
string node_id = 2; // Unique hardware/installation ID
|
||||
string public_key = 3; // WireGuard public key for E2EE
|
||||
string local_ip = 4; // Local network IP
|
||||
}
|
||||
|
||||
message RegisterResponse {
|
||||
string virtual_ip = 1; // Assigned IP in the overlay network
|
||||
string session_token = 2; // JWT for subsequent authenticated requests
|
||||
string coordinator_address = 3;
|
||||
string assigned_name = 4; // The auto-generated name (e.g., "Node-8a2f")
|
||||
}
|
||||
|
||||
message UpdateNameRequest {
|
||||
string node_id = 1;
|
||||
string new_name = 2;
|
||||
string session_token = 3;
|
||||
}
|
||||
|
||||
message UpdateNameResponse {
|
||||
bool success = 1;
|
||||
string current_name = 2;
|
||||
}
|
||||
|
||||
message HeartbeatRequest {
|
||||
string node_id = 1;
|
||||
string session_token = 2;
|
||||
string public_endpoint = 3;
|
||||
}
|
||||
|
||||
message HeartbeatResponse {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message PeerRequest {
|
||||
string target_node_id = 1;
|
||||
string session_token = 2;
|
||||
}
|
||||
|
||||
message PeerResponse {
|
||||
string peer_public_key = 1;
|
||||
string public_endpoint = 2;
|
||||
string nat_type = 3;
|
||||
}
|
||||
|
||||
message SignalRequest {
|
||||
string source_node_id = 1;
|
||||
string target_node_id = 2;
|
||||
string session_token = 3;
|
||||
}
|
||||
|
||||
message SignalResponse {
|
||||
bool acknowledged = 1;
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/reflection"
|
||||
// "server/api" // This would be the generated package
|
||||
)
|
||||
|
||||
const version = "1.0.0"
|
||||
|
||||
// CoordinatorServer implements the Coordinator gRPC service
|
||||
type CoordinatorServer struct {
|
||||
// In a full implementation, we would have a Redis client here
|
||||
// nodes map[string]*NodeInfo
|
||||
}
|
||||
|
||||
func (s *CoordinatorServer) RegisterNode(ctx interface{}, req interface{}) (interface{}, error) {
|
||||
fmt.Println("RegisterNode called")
|
||||
return nil, nil // Placeholder for actual implementation
|
||||
}
|
||||
|
||||
func (s *CoordinatorServer) Heartbeat(ctx interface{}, req interface{}) (interface{}, error) {
|
||||
fmt.Println("Heartbeat called")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *CoordinatorServer) GetPeerEndpoint(ctx interface{}, req interface{}) (interface{}, error) {
|
||||
fmt.Println("GetPeerEndpoint called")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *CoordinatorServer) SignalConnection(ctx interface{}, req interface{}) (interface{}, error) {
|
||||
fmt.Println("SignalConnection called")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// STUN server implementation
|
||||
func startSTUNServer(port int) {
|
||||
addr := fmt.Sprintf(":%d", port)
|
||||
conn, err := net.ListenUDP("udp", &net.UDPAddr{Port: port})
|
||||
if err != nil {
|
||||
log.Fatalf("STUN server failed to start: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
fmt.Printf("STUN server listening on %s\n", addr)
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
for {
|
||||
n, remoteAddr, err := conn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
log.Printf("STUN read error: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("Received STUN request from %s (size: %d)\n", remoteAddr, n)
|
||||
|
||||
// Simplified STUN response: send the remote address back to the client
|
||||
// In a real STUN server, we would follow RFC 5389
|
||||
response := []byte(fmt.Sprintf("STUN_RESP:%s", remoteAddr.String()))
|
||||
_, err = conn.WriteToUDP(response, remoteAddr)
|
||||
if err != nil {
|
||||
log.Printf("STUN write error: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Start STUN server in a goroutine
|
||||
go startSTUNServer(3478)
|
||||
|
||||
// Serve HTML Dashboard
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
// Note: In a production app, we would use a template to inject the version
|
||||
// For this task, we serve the file and suggest using a template for dynamic injection
|
||||
http.ServeFile(w, r, "C:\\Users\\jadon\\Documents\\vscode\\tailscale-test\\meshvpn-dashboard\\index.html")
|
||||
})
|
||||
|
||||
// Start HTTP server in a goroutine
|
||||
go func() {
|
||||
fmt.Printf("HTTP Dashboard listening on :8080 (Version: %s)\n", version)
|
||||
if err := http.ListenAndServe(":8080", nil); err != nil {
|
||||
log.Fatalf("HTTP server failed: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Start gRPC Coordinator server
|
||||
lis, err := net.Listen("tcp", ":50051")
|
||||
if err != nil {
|
||||
log.Fatalf("failed to listen: %v", err)
|
||||
}
|
||||
|
||||
s := grpc.NewServer()
|
||||
// In a real setup, we'd register the generated server:
|
||||
// pb.RegisterCoordinatorServer(s, &CoordinatorServer{})
|
||||
|
||||
reflection.Register(s)
|
||||
|
||||
fmt.Println("Coordinator Server listening on :50051")
|
||||
if err := s.Serve(lis); err != nil {
|
||||
log.Fatalf("failed to serve: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
# MeshVPN Server Setup Script
|
||||
# This script installs Go, Redis, PostgreSQL, and configures the firewall.
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 Starting MeshVPN Coordinator Setup..."
|
||||
|
||||
# 1. Update System
|
||||
sudo apt-get update
|
||||
|
||||
# 2. Install Dependencies
|
||||
echo "📦 Installing system dependencies..."
|
||||
sudo apt-get install -y golang-go redis-server postgresql postgresql-contrib ufw curl git
|
||||
|
||||
# 3. Configure PostgreSQL
|
||||
echo "🐘 Configuring PostgreSQL..."
|
||||
sudo systemctl start postgresql
|
||||
sudo systemctl enable postgresql
|
||||
# Create database and user (Simplified for setup)
|
||||
sudo -u postgres psql -c "CREATE USER meshvpn WITH PASSWORD 'password';" || echo "User already exists"
|
||||
sudo -u postgres psql -c "CREATE DATABASE meshvpn OWNER meshvpn;" || echo "DB already exists"
|
||||
|
||||
# 4. Configure Redis
|
||||
echo "⚡ Configuring Redis..."
|
||||
sudo systemctl start redis-server
|
||||
sudo systemctl enable redis-server
|
||||
|
||||
# 5. Firewall Configuration (UFW)
|
||||
echo "🛡️ Configuring Firewall (UFW)..."
|
||||
sudo ufw allow 22/tcp # SSH
|
||||
sudo ufw allow 3478/udp # STUN
|
||||
sudo ufw allow 50051/tcp # Coordinator gRPC
|
||||
sudo ufw --force enable
|
||||
|
||||
echo "-------------------------------------------------------"
|
||||
echo "✅ Server Setup Complete!"
|
||||
echo "Ports opened: 3478/UDP (STUN), 50051/TCP (Coordinator)"
|
||||
echo "Redis and Postgres are running."
|
||||
echo "Now navigate to /server and run: go run main.go"
|
||||
echo "-------------------------------------------------------"
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use crossbeam_queue::ArrayQueue;
|
||||
use std::sync::Arc;
|
||||
use tokio::net::UdpSocket;
|
||||
use std::io;
|
||||
|
||||
mod noise;
|
||||
|
||||
/// Configuration for the data plane memory limits.
|
||||
const MAX_PACKET_SIZE: usize = 16384; // 16KB
|
||||
const PACKET_POOL_SIZE: usize = 10000; // ~160MB (10k * 16KB)
|
||||
const MAX_RAM_USAGE_MB: usize = 256;
|
||||
|
||||
/// A fixed-size packet pool to prevent excessive allocations and fragmentation.
|
||||
struct PacketPool {
|
||||
pool: Arc<ArrayQueue<BytesMut>>,
|
||||
}
|
||||
|
||||
impl PacketPool {
|
||||
fn new(capacity: usize, packet_size: usize) -> Self {
|
||||
let queue = ArrayQueue::new(capacity);
|
||||
for _ in 0..capacity {
|
||||
let _ = queue.push(BytesMut::with_capacity(packet_size));
|
||||
}
|
||||
Self {
|
||||
pool: Arc::new(queue),
|
||||
}
|
||||
}
|
||||
|
||||
/// Acquires a buffer from the pool or creates a new one if the pool is empty
|
||||
/// (though in a strict memory-constrained environment, we might prefer to drop packets).
|
||||
fn acquire(&self) -> BytesMut {
|
||||
self.pool.pop().unwrap_or_else(|| BytesMut::with_capacity(MAX_PACKET_SIZE))
|
||||
}
|
||||
|
||||
/// Returns a buffer to the pool for reuse.
|
||||
fn release(&self, mut buf: BytesMut) {
|
||||
buf.clear();
|
||||
let _ = self.pool.push(buf);
|
||||
}
|
||||
}
|
||||
|
||||
struct DataPlane {
|
||||
pool: Arc<PacketPool>,
|
||||
}
|
||||
|
||||
impl DataPlane {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
pool: Arc::new(PacketPool::new(PACKET_POOL_SIZE, MAX_PACKET_SIZE)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn run(&self) -> io::Result<()> {
|
||||
// Using current_thread runtime as specified for memory efficiency and avoiding cross-core synchronization overhead
|
||||
let socket = UdpSocket::bind("0.0.0.0:0").await?;
|
||||
println!("Data plane listening on {}", socket.local_addr()?);
|
||||
|
||||
loop {
|
||||
let mut buf = self.pool.acquire();
|
||||
|
||||
// Zero-copy receiving: reading directly into the pooled buffer
|
||||
match socket.recv_from(&mut buf).await {
|
||||
Ok((len, addr)) => {
|
||||
// Use BytesMut::split_to to create a zero-copy 'Bytes' view for processing
|
||||
let packet = buf.split_to(len).freeze();
|
||||
|
||||
// Simulate processing the packet without copying data
|
||||
self.process_packet(packet, addr).await;
|
||||
|
||||
// Return the remaining buffer to the pool
|
||||
self.pool.release(buf);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error receiving packet: {}", e);
|
||||
self.pool.release(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn process_packet(&self, packet: Bytes, addr: std::net::SocketAddr) {
|
||||
// Logic for handling packets would go here.
|
||||
// 'packet' is a reference-counted view into the original buffer.
|
||||
let _ = packet.len();
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() -> io::Result<()> {
|
||||
let dp = DataPlane::new();
|
||||
println!("Starting memory-efficient data plane...");
|
||||
println!("Estimated pool memory: {} MB", (PACKET_POOL_SIZE * MAX_PACKET_SIZE) / 1024 / 1024);
|
||||
dp.run().await
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
use snow::params::NoiseParams;
|
||||
use snow::{HandshakeState, Noise};
|
||||
|
||||
pub struct NoiseSession {
|
||||
pub state: HandshakeState,
|
||||
}
|
||||
|
||||
impl NoiseSession {
|
||||
pub fn new_initiator(static_key: &[u8], remote_static_key: &[u8]) -> Self {
|
||||
let params = NoiseParams::Noise_XX_25519_ChaChaPoly_BLAKE2s;
|
||||
let builder = Noise::new(¶ms).unwrap();
|
||||
let state = builder.initiate_handshake(
|
||||
snow::keys::StaticKey::from_slice(static_key).unwrap(),
|
||||
snow::keys::PublicKey::from_slice(remote_static_key).unwrap(),
|
||||
).unwrap();
|
||||
|
||||
NoiseSession { state }
|
||||
}
|
||||
|
||||
pub fn new_responder(static_key: &[u8]) -> Self {
|
||||
let params = NoiseParams::Noise_XX_25519_ChaChaPoly_BLAKE2s;
|
||||
let builder = Noise::new(¶ms).unwrap();
|
||||
let state = builder.respond_handshake(
|
||||
snow::keys::StaticKey::from_slice(static_key).unwrap(),
|
||||
None,
|
||||
).unwrap();
|
||||
|
||||
NoiseSession { state }
|
||||
}
|
||||
|
||||
pub fn write_message(&mut self, payload: &[u8]) -> Vec<u8> {
|
||||
let mut buf = vec![0u8; 65535];
|
||||
let len = self.state.write_message(payload, &mut buf).unwrap();
|
||||
buf.truncate(len);
|
||||
buf
|
||||
}
|
||||
|
||||
pub fn read_message(&mut self, ciphertext: &[u8]) -> Vec<u8> {
|
||||
let mut buf = vec![0u8; 65535];
|
||||
let len = self.state.read_message(ciphertext, &mut buf).unwrap();
|
||||
buf.truncate(len);
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_handshake() {
|
||||
let alice_static = [0u8; 32];
|
||||
let bob_static = [1u8; 32];
|
||||
|
||||
let mut alice = NoiseSession::new_initiator(&alice_static, &bob_static);
|
||||
let mut bob = NoiseSession::new_responder(&bob_static);
|
||||
|
||||
let msg1 = alice.write_message(b"Hello Bob");
|
||||
let res1 = bob.read_message(&msg1);
|
||||
assert_eq!(res1, b"Hello Bob");
|
||||
|
||||
let msg2 = bob.write_message(b"Hello Alice");
|
||||
let res2 = alice.read_message(&msg2);
|
||||
assert_eq!(res2, b"Hello Alice");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user