Compare commits

19 Commits

Author SHA1 Message Date
PoliEcho 1d9bfb8896 Update README.md 2025-08-10 10:47:01 +00:00
PoliEcho 2b31e112f9 Update README.md 2025-08-10 10:44:33 +00:00
PoliEcho f60ea7fd14 Update README.md 2025-08-10 10:41:02 +00:00
PoliEcho 2bfd0b686b Update README.md 2025-08-10 10:37:19 +00:00
PoliEcho b0dfffff63 Update README.md 2025-08-03 18:55:04 +00:00
PoliEcho 64e6bb1343 resize logo 2025-08-03 20:54:17 +02:00
PoliEcho dea308d73d add logo 2025-08-03 20:50:00 +02:00
PoliEcho 934a053713 bug fixes 2025-08-03 20:23:23 +02:00
PoliEcho a955710350 some more heartbeat modifications 2025-08-03 18:34:31 +02:00
PoliEcho 23dea395d3 Merge branch 'master' of https://git.pupes.org/PoliEcho/pea_2_pea 2025-08-03 15:51:16 +02:00
PoliEcho 6ede42a096 v1.1 2025-08-03 15:49:43 +02:00
PoliEcho 8f2c66c195 Update README.md 2025-08-03 13:41:37 +00:00
PoliEcho 6898f946fa Update README.md 2025-08-03 13:38:18 +00:00
PoliEcho ef83f0216f remove some warnings 2025-08-03 15:12:10 +02:00
PoliEcho 206012e72d add periodic heart beat 2025-08-03 15:05:35 +02:00
PoliEcho b9e36d9f8c maybe it works now? 2025-08-02 10:34:58 +02:00
PoliEcho b8d02b2077 add more debuging 2025-08-02 10:11:33 +02:00
PoliEcho 8e9d179d49 add windows crosscompilation 2025-08-01 23:32:49 +02:00
PoliEcho bc17ffac68 bump version to 1.0 2025-08-01 19:48:35 +02:00
11 changed files with 660 additions and 104 deletions
+13 -1
View File
@@ -28,14 +28,26 @@ rayon = "1.10.0"
readonly = "0.2.13"
sha2 = "0.10.9"
smol = "2.0.2"
tappers = "0.4.2"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winsock2", "mswsock", "minwindef"] }
tappers = { version = "0.4.2", features = ["wintun"] }
[target.'cfg(unix)'.dependencies]
libc = "0.2"
tappers = "0.4.2"
[target.x86_64-pc-windows-gnu]
linker = "/usr/bin/x86_64-w64-mingw32-gcc"
ar = "/usr/bin/x86_64-w64-mingw32-ar"
[target.i686-pc-windows-gnu]
linker = "/usr/bin/i686-w64-mingw32-gcc"
ar = "/usr/bin/i686-w64-mingw32-ar"
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
[features]
no-timeout = []
+26
View File
@@ -0,0 +1,26 @@
<img src="https://git.pupes.org/PoliEcho/pea_2_pea/raw/branch/master/logo.svg" alt="Pea 2 Pea logo" width="196"></img>
# Pea 2 Pea
very simple P2P VPN(Virtual Network yes, Private maybe),
this program is intended to help you play LAN games over internet and as proof of concept
when all clients are behind Full-cone NAT, does not work with clients behind Symmetric NAT
at least for now
> [!WARNING]
> Piercing NAT may fail based on network configuration minor bug fixes
> [!WARNING]
> windows client does not work thanks to some tappers library issues
## how to run
> install rustc and cargo or rustup, you will need 2024 edition
> <b><span style='color: red;'>if using windows you need to get</span></b> [wintun](https://www.wintun.net/) <b><span style='color: red;'>driver</span></b>
> build using
> ```bash
> # to build
> cargo build --release
> # to run server(registrar)
> ./target/release/server
> # to run client
> sudo ./target/release/client -r SERVER_IP -n NETWORK_ID -P PASSWORD # password is optional
> ```
+445
View File
@@ -0,0 +1,445 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="484.58453"
height="248.42142"
viewBox="0 0 128.21298 65.728168"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="logo.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#999999"
borderopacity="1"
inkscape:showpageshadow="2"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="1.1099334"
inkscape:cx="196.40818"
inkscape:cy="60.814458"
inkscape:window-width="1918"
inkscape:window-height="1038"
inkscape:window-x="0"
inkscape:window-y="20"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(3.9106348,-31.359329)">
<circle
style="fill:#008000;stroke:none;stroke-width:2.91042"
id="path1"
cx="46.719666"
cy="57.45282"
r="5" />
<circle
style="fill:#008000;stroke:none;stroke-width:2.91042"
id="path2"
cx="83.68927"
cy="58.152664"
r="5" />
<rect
style="fill:#aa4400;stroke:#000000;stroke-width:0.264583;stroke-dasharray:none"
id="rect2"
width="16.013054"
height="7.4165721"
x="31.945221"
y="27.088457"
transform="rotate(19.028307)" />
<rect
style="fill:#aa4400;stroke:#000000;stroke-width:0.264583;stroke-dasharray:none"
id="rect2-3"
width="16.013054"
height="7.4165721"
x="29.191198"
y="-95.819298"
transform="rotate(130.89504)" />
<rect
style="fill:#aa4400;stroke:#000000;stroke-width:0.264583;stroke-dasharray:none"
id="rect2-3-6"
width="16.013054"
height="7.4165721"
x="-26.219568"
y="-85.876183"
transform="rotate(130.89504)" />
<rect
style="fill:#aa4400;stroke:#000000;stroke-width:0.264583;stroke-dasharray:none"
id="rect2-3-6-2"
width="16.013054"
height="7.4165721"
x="118.05431"
y="23.204641"
transform="rotate(22.124773)" />
<rect
style="fill:#aa4400;stroke:#000000;stroke-width:0.264583;stroke-dasharray:none"
id="rect2-3-6-5"
width="16.013054"
height="7.4165721"
x="88.477242"
y="56.328484"
transform="rotate(-9.8371144)" />
<rect
style="fill:#aa4400;stroke:#000000;stroke-width:0.264583;stroke-dasharray:none"
id="rect2-3-6-5-9"
width="16.013054"
height="7.4165721"
x="92.291519"
y="-31.192705"
transform="rotate(63.042937)" />
<rect
style="fill:#aa4400;stroke:#000000;stroke-width:0.264583;stroke-dasharray:none"
id="rect2-3-1"
width="16.013054"
height="7.4165721"
x="-35.023296"
y="-86.497765"
transform="rotate(-171.92112)" />
<rect
style="fill:#aa4400;stroke:#000000;stroke-width:0.264583;stroke-dasharray:none"
id="rect2-3-1-3"
width="16.013054"
height="7.4165721"
x="17.492208"
y="-55.955021"
transform="rotate(142.51624)" />
<g
id="g4">
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4"
width="7.0014291"
height="0.67321438"
x="39.931004"
y="105.02441"
transform="rotate(-23.434102)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2"
width="7.0014291"
height="0.67321438"
x="41.63229"
y="100.16535"
transform="rotate(-23.434102)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4"
width="7.0014291"
height="0.67321438"
x="41.926292"
y="95.885963"
transform="rotate(-23.434102)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-0"
width="7.0014291"
height="0.67321438"
x="38.900993"
y="91.293457"
transform="rotate(-23.434102)" />
</g>
<g
id="g4-6"
transform="rotate(65.73685,101.19056,61.333303)">
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-3"
width="7.0014291"
height="0.67321438"
x="39.931004"
y="105.02441"
transform="rotate(-23.434102)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-2"
width="7.0014291"
height="0.67321438"
x="41.63229"
y="100.16535"
transform="rotate(-23.434102)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-06"
width="7.0014291"
height="0.67321438"
x="41.926292"
y="95.885963"
transform="rotate(-23.434102)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-0-1"
width="7.0014291"
height="0.67321438"
x="38.900993"
y="91.293457"
transform="rotate(-23.434102)" />
</g>
<g
id="g4-6-6"
transform="rotate(-113.69404,61.903716,91.125325)">
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-3-5"
width="7.0014291"
height="0.67321438"
x="39.931004"
y="105.02441"
transform="rotate(-23.434102)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-2-6"
width="7.0014291"
height="0.67321438"
x="41.63229"
y="100.16535"
transform="rotate(-23.434102)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-06-9"
width="7.0014291"
height="0.67321438"
x="41.926292"
y="95.885963"
transform="rotate(-23.434102)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-0-1-3"
width="7.0014291"
height="0.67321438"
x="38.900993"
y="91.293457"
transform="rotate(-23.434102)" />
</g>
<g
id="g5">
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-3-5-5-3-8"
width="7.0014291"
height="0.67321438"
x="-8.7603998"
y="127.93809"
transform="rotate(176.53385,-1.1221414,92.265355)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-3-5-5-3-8-4"
width="7.0014291"
height="0.67321438"
x="-7.19274"
y="122.34638"
transform="rotate(176.53385,-1.1221414,92.265355)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-3-5-5-3-8-8"
width="7.0014291"
height="0.67321438"
x="-9.5258064"
y="118.47264"
transform="rotate(176.53385,-1.1221414,92.265355)" />
</g>
<g
id="g5-4"
transform="translate(1.5735268,24.969803)">
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-3-5-5-3-8-9"
width="7.0014291"
height="0.67321438"
x="-8.7603998"
y="127.93809"
transform="rotate(176.53385,-1.1221414,92.265355)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-3-5-5-3-8-4-5"
width="7.0014291"
height="0.67321438"
x="-7.19274"
y="122.34638"
transform="rotate(176.53385,-1.1221414,92.265355)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-3-5-5-3-8-8-0"
width="7.0014291"
height="0.67321438"
x="-9.5258064"
y="118.47264"
transform="rotate(176.53385,-1.1221414,92.265355)" />
</g>
<g
id="g6">
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-06-6"
width="7.0014291"
height="0.67321438"
x="120.58088"
y="1.4029152"
transform="rotate(17.66615)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-06-6-9"
width="7.0014291"
height="0.67321438"
x="121.73305"
y="4.3680196"
transform="rotate(17.66615)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-06-6-7"
width="7.0014291"
height="0.67321438"
x="120.06847"
y="10.63729"
transform="rotate(17.66615)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-06-6-77"
width="7.0014291"
height="0.67321438"
x="123.14556"
y="7.7831545"
transform="rotate(17.66615)" />
</g>
<g
id="g1">
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-06-6-7-5"
width="7.0014291"
height="0.67321438"
x="104.35145"
y="90.858383"
transform="rotate(-6.8426428)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-06-6-7-5-8"
width="7.0014291"
height="0.67321438"
x="106.21098"
y="87.927322"
transform="rotate(-6.8426428)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-06-6-7-5-9"
width="7.0014291"
height="0.67321438"
x="102.55393"
y="81.353195"
transform="rotate(-6.8426428)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-06-6-7-5-0"
width="7.0014291"
height="0.67321438"
x="107.95219"
y="84.665787"
transform="rotate(-6.8426428)" />
</g>
<g
id="g2">
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-06-6-7-5-3"
width="7.0014291"
height="0.67321438"
x="7.5878925"
y="56.102978"
transform="rotate(-18.642383)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-06-6-7-5-3-1"
width="7.0014291"
height="0.67321438"
x="4.4349847"
y="53.472279"
transform="rotate(-18.642383)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-06-6-7-5-3-1-3"
width="7.0014291"
height="0.67321438"
x="1.2183968"
y="50.885269"
transform="rotate(-18.642383)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-06-6-7-5-3-1-6"
width="7.0014291"
height="0.67321438"
x="-0.33573198"
y="41.308918"
transform="rotate(-18.642383)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112354;stroke-dasharray:none"
id="rect4-2-4-06-6-7-5-3-1-2"
width="7.0014291"
height="0.67321438"
x="-3.9510856"
y="46.704735"
transform="rotate(-18.642383)" />
</g>
<g
id="g3">
<rect
style="fill:#000000;stroke:none;stroke-width:0.112299;stroke-dasharray:none"
id="rect4-2-4-06-6-7-5-3-1-6-5"
width="6.997993"
height="0.67288405"
x="22.438622"
y="68.204086"
transform="rotate(-11.251809)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112299;stroke-dasharray:none"
id="rect4-2-4-06-6-7-5-3-1-6-5-9"
width="6.997993"
height="0.67288405"
x="21.747293"
y="64.102196"
transform="rotate(-11.251809)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112299;stroke-dasharray:none"
id="rect4-2-4-06-6-7-5-3-1-6-5-2"
width="6.997993"
height="0.67288405"
x="23.246773"
y="60.863266"
transform="rotate(-11.251809)" />
</g>
<rect
style="fill:#000000;stroke:none;stroke-width:0.112299;stroke-dasharray:none"
id="rect4-2-4-06-6-7-5-3-1-6-5-2-4"
width="6.997993"
height="0.67288405"
x="97.801979"
y="36.583424"
transform="rotate(11.279343)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112299;stroke-dasharray:none"
id="rect4-2-4-06-6-7-5-3-1-6-5-2-4-6"
width="6.997993"
height="0.67288405"
x="100.02957"
y="39.268402"
transform="rotate(13.217335)" />
<rect
style="fill:#000000;stroke:none;stroke-width:0.112299;stroke-dasharray:none"
id="rect4-2-4-06-6-7-5-3-1-6-5-2-4-0"
width="6.997993"
height="0.67288405"
x="99.277161"
y="39.332554"
transform="rotate(11.279343)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

+50 -23
View File
@@ -21,7 +21,8 @@ use crate::types::Network;
struct Cli {
#[arg(short = 'r', long = "registrar")]
#[arg(help = "registrar ip address or hostname")]
registrar: String,
#[arg(required_unless_present = "version")]
registrar: Option<String>,
#[arg(short = 'p', long = "registrar-port")]
#[arg(help = format!("optional Port number for the registrar service (1-65535) Default: {}", SERVER_PORT))]
@@ -29,7 +30,8 @@ struct Cli {
#[arg(short = 'n', long = "network-id")]
#[arg(help = "your virtual network id that allows other people to connect to you")]
network_id: String,
#[arg(required_unless_present = "version")]
network_id: Option<String>,
#[arg(short = 'P', long = "password")]
#[arg(
@@ -52,14 +54,24 @@ struct Cli {
symmetric_nat_bypass_mode: bool,
}
fn print_version() {
println!("Pea 2 Pea {}", VERSION);
}
fn main() -> std::io::Result<()> {
let cli = <Cli as clap::Parser>::parse();
if cli.network_id.len() > 0xff {
if cli.version {
print_version();
exit(0);
}
let network_id = cli.network_id.unwrap();
let registrar = cli.registrar.unwrap();
if network_id.len() > 0xff {
eprintln!("network id cannot have more then 255 charactes");
exit(7); // posix for E2BIG
}
let mut buf: [u8; UDP_BUFFER_SIZE] = [0; UDP_BUFFER_SIZE];
let (socket, virtual_network, my_public_sock_addr) = {
let (socket, virtual_network, _my_public_sock_addr) = {
let socket: Arc<UdpSocket> = Arc::new(|| -> std::io::Result<UdpSocket> {
match UdpSocket::bind("0.0.0.0:0") {
// bind to OS assigned random port
@@ -81,11 +93,11 @@ fn main() -> std::io::Result<()> {
})();
#[allow(non_snake_case)] // i think this is valid snake case but rustc doesnt think so
let server_SocketAddr: core::net::SocketAddr = format!("{}:{}", cli.registrar, server_port)
let server_SocketAddr: core::net::SocketAddr = format!("{}:{}", registrar, server_port)
.parse()
.expect(&format!(
"{}:{} is invalid sock addr",
cli.registrar, server_port
registrar, server_port
));
// query here
@@ -134,7 +146,7 @@ fn main() -> std::io::Result<()> {
&mut buf,
&server_SocketAddr,
&socket,
&cli.network_id,
&network_id,
&cli.password,
) {
Ok(n) => {
@@ -146,7 +158,7 @@ fn main() -> std::io::Result<()> {
let _ = net::send_heartbeat(
&mut buf,
&server_SocketAddr,
&socket,
socket.clone(),
&n,
&public_sock_addr,
&iv,
@@ -161,7 +173,7 @@ fn main() -> std::io::Result<()> {
None => false,
},
encryption_key,
cli.network_id,
network_id,
salt,
Vec::with_capacity(1),
);
@@ -174,6 +186,17 @@ fn main() -> std::io::Result<()> {
&iv,
)
.unwrap();
let _ = net::send_heartbeat(
// send heart beat to start periodic heart beat
&mut buf,
&server_SocketAddr,
socket.clone(),
&tmp_v_net,
&public_sock_addr,
&iv,
);
tmp_v_net
}
Err(e) => {
@@ -222,20 +245,23 @@ fn main() -> std::io::Result<()> {
"{} packets away!, awiting a bit for NAT mappings to estabilish",
"[LOG]".blue()
);
std::thread::sleep(Duration::from_millis(200));
match net::P2P_query(&mut buf, &peer.sock_addr, &socket, encrypted, key) {
Ok(ip) => {
ips_used[ip.octets()[3] as usize] = true;
peer.private_ip = ip;
}
Err(e) => {
eprintln!(
"{} while getting ip from peer: {}, Error: {}",
"[ERROR]".red(),
peer.sock_addr,
e
);
std::thread::sleep(Duration::from_millis(2000));
for _ in 0..STANDARD_RETRY_MAX {
match net::P2P_query(&mut buf, &peer.sock_addr, &socket, encrypted, key) {
Ok(ip) => {
ips_used[ip.octets()[3] as usize] = true;
peer.private_ip = ip;
break;
}
Err(e) => {
eprintln!(
"{} while getting ip from peer: {}, Error: {}",
"[ERROR]".red(),
peer.sock_addr,
e
);
std::thread::sleep(Duration::from_millis(2000));
}
}
}
});
@@ -304,6 +330,7 @@ fn main() -> std::io::Result<()> {
} // just let me have my thread
smol::block_on(async {
println!("{} listener started!", "[LOG]".blue());
loop {
buf.fill(0);
match socket.recv_from(&mut buf) {
+36 -2
View File
@@ -255,7 +255,7 @@ pub fn get_request(
pub fn send_heartbeat(
buf: &mut [u8; UDP_BUFFER_SIZE],
dst: &SocketAddr,
socket: &UdpSocket,
socket: Arc<std::net::UdpSocket>,
network: &types::Network,
my_public_sock_addr: &Box<[u8]>,
iv: &[u8; BLOCK_SIZE as usize],
@@ -300,7 +300,16 @@ pub fn send_heartbeat(
.collect::<String>(),
);
match send_and_recv_with_retry(buf, &send_buf, dst, socket, STANDARD_RETRY_MAX) {
{
let sock_clone = socket.clone();
let send_buf_clone: Box<[u8]> = send_buf.clone();
let dst_clone: SocketAddr = dst.clone();
std::thread::spawn(move || {
periodic_heart_beat(sock_clone, send_buf_clone, dst_clone);
});
}
match send_and_recv_with_retry(buf, &send_buf, dst, &socket, STANDARD_RETRY_MAX) {
Ok((data_lenght, _)) => return Ok(data_lenght),
Err(e) => return Err(e),
}
@@ -718,6 +727,9 @@ pub async fn handle_incoming_connection(
"[SUCCESS]".green()
);
}
x if x == ServerMethods::HEARTBEAT as u8 => {
println!("{} heart beat recive confirmed", "[OK]".green());
}
_ => {
eprintln!(
"{} unknown method ID: 0x{:02x}, Droping!",
@@ -727,3 +739,25 @@ pub async fn handle_incoming_connection(
}
}
}
pub fn periodic_heart_beat(socket: Arc<UdpSocket>, send_buf: Box<[u8]>, dst: SocketAddr) {
println!("{} periodic heartbeat started", "[LOG]".blue());
loop {
std::thread::sleep(std::time::Duration::from_secs(30));
println!("{} sending heartbeat to server", "[LOG]".blue());
match socket.send_to(&send_buf, dst) {
Ok(size) => {
#[cfg(debug_assertions)]
println!("send {} bytes", size);
}
Err(e) => {
eprintln!(
"{} failed to send heartbeat to server Error: {}",
"[ERROR]".red(),
e
);
}
}
}
}
+31 -10
View File
@@ -1,9 +1,9 @@
use std::sync::{Arc, RwLock};
use pea_2_pea::*;
use rand::RngCore;
use rayon::prelude::*;
use sha2::Digest;
use std::sync::{Arc, RwLock};
use tappers::Interface;
use crate::types::Network;
@@ -11,15 +11,36 @@ pub fn create_tun_interface(
private_ip: std::net::Ipv4Addr,
if_name: Option<String>,
) -> Result<tappers::Tun, std::io::Error> {
let mut tun_iface: tappers::Tun = tappers::Tun::new_named(tappers::Interface::new(
if_name.unwrap_or("pea0".to_owned()),
#[cfg(not(target_os = "windows"))]
let mut tun_iface: tappers::Tun = tappers::Tun::new_named(Interface::new(
&if_name.unwrap_or(DEFAULT_INTERFACE_NAME.to_owned()),
)?)?;
let mut addr_req = tappers::AddAddressV4::new(private_ip);
addr_req.set_netmask(24);
let mut broadcast_addr_oct = private_ip.octets();
broadcast_addr_oct[3] = 255;
addr_req.set_broadcast(std::net::Ipv4Addr::from(broadcast_addr_oct));
tun_iface.add_addr(addr_req)?;
#[cfg(target_os = "windows")]
let mut tun_iface: tappers::Tun = tappers::Tun::new()?;
#[cfg(not(target_os = "windows"))]
{
let mut addr_req = tappers::AddAddressV4::new(private_ip);
addr_req.set_netmask(24);
let mut broadcast_addr_oct = private_ip.octets();
broadcast_addr_oct[3] = 255;
addr_req.set_broadcast(std::net::Ipv4Addr::from(broadcast_addr_oct));
tun_iface.add_addr(addr_req)?;
}
#[cfg(target_os = "windows")]
std::process::Command::new("netsh").args([
"interface",
"ipv4",
"set",
"address",
&format!(
"name=\"{}\"",
tun_iface.name()?.name().into_string().unwrap()
),
"static",
&private_ip.to_string(),
"255.255.255.0",
]);
tun_iface.set_up()?;
return Ok(tun_iface);
}
+3 -1
View File
@@ -4,7 +4,7 @@ pub const SERVER_PORT: u16 = 3543;
pub const UDP_BUFFER_SIZE: usize = 65527;
pub const IP_BUFFER_SIZE: usize = 65535;
pub const DEFAULT_TIMEOUT: u64 = 30;
pub const VERSION: &str = "v0.1";
pub const VERSION: &str = "v1.1.1";
pub const BLOCK_SIZE: usize = 16;
pub const STANDARD_RETRY_MAX: usize = 10;
@@ -15,6 +15,8 @@ pub const MAPPING_SHOT_COUNT: u8 = 5;
pub const DEFAULT_NETWORK_PREFIX: [u8; 3] = [172, 22, 44];
pub const DEFAULT_INTERFACE_NAME: &str = "pea0";
#[repr(u8)]
#[allow(non_camel_case_types)]
pub enum ServerMethods {
+8 -4
View File
@@ -2,10 +2,7 @@ mod net;
mod types;
mod utils;
use smol::net::UdpSocket;
use std::{
process::exit,
sync::{Arc, RwLock},
};
use std::{process::exit, sync::Arc};
use orx_concurrent_vec::ConcurrentVec;
fn main() -> std::io::Result<()> {
@@ -21,6 +18,13 @@ fn main() -> std::io::Result<()> {
let registration_vector: Arc<ConcurrentVec<types::Registration>> =
Arc::new(orx_concurrent_vec::ConcurrentVec::new());
{
let reg_clone = registration_vector.clone();
std::thread::spawn(move || {
utils::disconnected_cleaner(reg_clone);
});
}
let mut buf: [u8; pea_2_pea::UDP_BUFFER_SIZE] = [0u8; pea_2_pea::UDP_BUFFER_SIZE];
smol::block_on(async {
loop {
+24 -4
View File
@@ -64,7 +64,7 @@ pub async fn handle_request(
let registration = match registration_vector
.iter()
.find(|elem| elem.map(|s| &s.net_id == &net_id)) // find if id exists
.find(|elem| elem.map(|s| &s.net_id == &net_id && !s.invalid)) // find if id exists
{
Some(registration) => registration,
None => {futures::executor::block_on(send_with_count(socket, &src ,&[ServerResponse::ID_DOESNT_EXIST as u8]));
@@ -163,7 +163,7 @@ pub async fn handle_request(
match registration_vector
.iter()
.find(|elem| elem.map(|s| &s.net_id == &net_id)) // find if id exists
.find(|elem| elem.map(|s| &s.net_id == &net_id && !s.invalid)) // find if id exists
{
Some(_) => {
futures::executor::block_on(send_with_count(socket, &src, &[ServerResponse::ID_EXISTS as u8]));
@@ -216,7 +216,25 @@ pub async fn handle_request(
.collect::<String>(),
);
registration_vector.push(types::Registration::new(
let mut first_invalid_registration: Option<usize> = None;
for (i, reg) in registration_vector.iter().enumerate() {
if reg.map(|r| r.invalid) {
first_invalid_registration = Some(i);
break;
}
}
match first_invalid_registration {
Some(i) => registration_vector[i].update(|r|{*r = types::Registration::new(
net_id.clone(),
client_sock_addr.clone(),
encrypted,
chrono::Utc::now().timestamp(),
salt,
iv,
src
);}),
None => {registration_vector.push(types::Registration::new(
net_id,
client_sock_addr,
encrypted,
@@ -224,7 +242,9 @@ pub async fn handle_request(
salt,
iv,
src
));
));},
};
send_with_count(socket, &src, &[ServerMethods::REGISTER as u8]).await;
#[cfg(debug_assertions)]
println!("network registered");
+2 -59
View File
@@ -1,5 +1,4 @@
use pea_2_pea::*;
use std::sync::{Arc, atomic::Ordering};
#[derive(Clone)]
#[readonly::make]
@@ -41,6 +40,7 @@ pub struct Registration {
pub encrypted: bool,
#[readonly]
pub salt: [u8; BLOCK_SIZE as usize],
pub invalid: bool,
}
impl Registration {
@@ -64,64 +64,7 @@ impl Registration {
encrypted,
last_heart_beat: heart_beat,
salt: salt.unwrap_or([0; BLOCK_SIZE as usize]),
invalid: false,
}
}
}
pub struct BatchLock {
inner: std::sync::Mutex<bool>, // true = blocking new locks
condvar: std::sync::Condvar,
active_count: std::sync::atomic::AtomicUsize,
}
pub struct LockGuard {
lock: Arc<BatchLock>,
}
impl BatchLock {
pub fn new() -> Arc<Self> {
Arc::new(BatchLock {
inner: std::sync::Mutex::new(false),
condvar: std::sync::Condvar::new(),
active_count: std::sync::atomic::AtomicUsize::new(0),
})
}
// Acquire a lock (blocks if waiting for all to unlock)
pub fn lock(self: &Arc<Self>) -> LockGuard {
let mut blocking = self.inner.lock().unwrap();
// Wait while new locks are blocked
while *blocking {
blocking = self.condvar.wait(blocking).unwrap();
}
self.active_count.fetch_add(1, Ordering::SeqCst);
LockGuard {
lock: Arc::clone(self),
}
}
// Block new locks and wait for all current locks to finish
pub fn wait_all_unlock(self: &Arc<Self>) {
// Block new locks
*self.inner.lock().unwrap() = true;
// Wait for all active locks to finish
while self.active_count.load(Ordering::SeqCst) > 0 {
std::thread::sleep(std::time::Duration::from_millis(1));
}
// Allow new locks again
*self.inner.lock().unwrap() = false;
self.condvar.notify_all();
}
}
impl Drop for LockGuard {
fn drop(&mut self) {
// Automatically release lock when guard is dropped
self.lock.active_count.fetch_sub(1, Ordering::SeqCst);
}
}
+22
View File
@@ -1,4 +1,6 @@
use colored::Colorize;
use pea_2_pea::*;
pub fn send_general_error_to_client<T: std::error::Error>(
dst: core::net::SocketAddr,
e: T,
@@ -11,3 +13,23 @@ pub fn send_general_error_to_client<T: std::error::Error>(
let _ = socket.send_to(&[ServerResponse::GENERAL_ERROR as u8], dst);
}
pub fn disconnected_cleaner(
registration_vector: std::sync::Arc<
orx_concurrent_vec::ConcurrentVec<crate::types::Registration>,
>,
) {
loop {
std::thread::sleep(std::time::Duration::from_secs(120));
println!("{} starting cleanup", "[LOG]".blue());
let time_now = chrono::Utc::now().timestamp();
unsafe {
registration_vector.iter_mut().for_each(|reg| {
reg.clients.retain(|c| time_now - c.last_heart_beat < 120);
if time_now - reg.last_heart_beat > 120 {
reg.invalid = true;
}
})
}
}
}