Compare commits

29 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
PoliEcho 4ca652cea5 fix unecryted network 2025-08-01 19:38:59 +02:00
PoliEcho 4a70fb61f9 another off by one error 2025-08-01 19:35:09 +02:00
PoliEcho 6aa9fb27e6 add debuging of packets 2025-08-01 19:20:58 +02:00
PoliEcho 20a4907ea0 remove off by one error 2025-08-01 18:44:44 +02:00
PoliEcho 582d458f70 maybe works now 2025-08-01 18:41:17 +02:00
PoliEcho 0a32061960 add some debug messages 2025-08-01 18:33:56 +02:00
PoliEcho b1cc5ddd32 minimal changes 2025-08-01 17:57:23 +02:00
PoliEcho c5a4059a84 this has to work 2025-08-01 16:58:42 +02:00
PoliEcho be37082b87 a 2025-08-01 16:16:00 +02:00
PoliEcho 07df839b6d WHY DOESNT IT WORK :((((((( 2025-08-01 16:07:38 +02:00
12 changed files with 752 additions and 258 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

-137
View File
@@ -1,137 +0,0 @@
--- a/src/server/net.rs
+++ b/src/server/net.rs
@@ -59,19 +59,22 @@ pub async fn handle_request(
};
}
- let registration = match registration_vector
+ let registration_opt = registration_vector
.iter()
- .find(|elem| elem.map(|s| &s.net_id == &net_id)) // find if id exists
- {
- Some(registration) => registration,
- None => {match socket.send_to(&[ServerResponse::ID_DOESNT_EXIST as u8], src).await{
+ .find(|elem| elem.map(|s| &s.net_id == &net_id))
+ .cloned();
+
+ let registration = match registration_opt {
+ Some(registration) => registration,
+ None => {
+ match socket.send_to(&[ServerResponse::ID_DOESNT_EXIST as u8], src).await {
Ok(s) => {
#[cfg(debug_assertions)]
eprintln!("send {} bytes", s);
}
Err(e) => {
eprintln!("Error sending data: {}", e);
}
- };
+ }
return;
},
};
@@ -162,19 +165,22 @@ pub async fn handle_request(
return;
};
- match registration_vector
+ let registration_exists = registration_vector
.iter()
- .find(|elem| elem.map(|s| &s.net_id == &net_id)) // find if id exists
- {
- Some(_) => {
- match socket.send_to(&[ServerResponse::ID_EXISTS as u8], src).await {
+ .find(|elem| elem.map(|s| &s.net_id == &net_id))
+ .is_some();
+
+ if registration_exists {
+ match socket.send_to(&[ServerResponse::ID_EXISTS as u8], src).await {
+ Ok(s) => {
+ #[cfg(debug_assertions)]
+ eprintln!("send {} bytes", s);
+ }
+ Err(e) => {
+ eprintln!("Error sending data: {}", e);
+ }
+ }
+ return;
- Ok(s) => {
- #[cfg(debug_assertions)]
- eprintln!("send {} bytes", s);
- }
- Err(e) => {
- eprintln!("Error sending data: {}", e);
- }
- };
- return;
- }
- None => {}
}
let salt: Option<[u8; BLOCK_SIZE as usize]>;
@@ -321,19 +327,22 @@ pub async fn handle_request(
);
- match registration_vector
+ let registration_opt = registration_vector
.iter()
- .find(|elem| elem.map(|s| &s.net_id == &net_id)) // find if id exists
- {
- Some(reg) => {
+ .find(|elem| elem.map(|s| &s.net_id == &net_id))
+ .cloned();
+
+ match registration_opt {
+ Some(reg) => {
let current_time = chrono::Utc::now().timestamp();
- reg.update(|r| {r.last_heart_beat = current_time;
+ reg.update(|r| {
+ r.last_heart_beat = current_time;
match r.clients.par_iter_mut().find_any(|c| *c.client_sock_addr == *sock_addr && c.iv == iv) {
Some(c) => c.last_heart_beat = current_time,
- None => {// add new client if it isn't found
+ None => {
r.clients.par_iter().for_each(|c| {let mut send_buf: Box<[u8]> = vec![0; P2PStandardDataPositions::DATA as usize + sock_addr_len as usize].into();
send_buf[0] = P2PMethods::NEW_CLIENT_NOTIFY as u8;
send_buf[P2PStandardDataPositions::IV as usize..P2PStandardDataPositions::IV as usize+ BLOCK_SIZE].copy_from_slice(&iv);
send_buf[P2PStandardDataPositions::DATA as usize..P2PStandardDataPositions::DATA as usize + sock_addr_len as usize].copy_from_slice(&sock_addr);
let sock_clone = socket.clone();
async move {
match sock_clone.send_to(&send_buf, c.src).await {
Ok(data_lenght) => {
#[cfg(debug_assertions)]
eprintln!("send {} bytes", data_lenght);
},
Err(e) => eprintln!("{} failed to send data to client Error: {}", "[ERROR]".red(), e),
}
};
});
r.clients.push(types::Client::new(sock_addr.clone(), current_time, iv, src));
}
};
});
}
- None => {match socket.send_to(&[ServerResponse::ID_DOESNT_EXIST as u8], src).await {
- Ok(s) => {
- #[cfg(debug_assertions)]
- eprintln!("send {} bytes", s);
- }
- Err(e) => {
- eprintln!("Error sending data: {}", e);
- }
- }; return;}
+ None => {
+ match socket.send_to(&[ServerResponse::ID_DOESNT_EXIST as u8], src).await {
+ Ok(s) => {
+ #[cfg(debug_assertions)]
+ eprintln!("send {} bytes", s);
+ }
+ Err(e) => {
+ eprintln!("Error sending data: {}", e);
+ }
+ }
+ return;
+ }
}
match socket.send_to(&[ServerMethods::HEARTBEAT as u8], src).await {
+78 -20
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(
@@ -46,16 +48,30 @@ struct Cli {
#[arg(short = 'V', long = "version")]
version: bool,
#[arg(short = 'S', long = "symmetric_NAT_bypass_mode")]
#[arg(help = "NOT IMPLEMENTED")]
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
@@ -77,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
@@ -90,6 +106,11 @@ fn main() -> std::io::Result<()> {
Ok(s) => s,
Err(e) => return Err(ServerErrorResponses::into_io_error(e)),
};
println!(
"{} my bublic sockaddr: {}",
"[LOG]".blue(),
public_sock_addr_raw
);
let mut salt: [u8; BLOCK_SIZE] = [0u8; BLOCK_SIZE];
let mut iv: [u8; BLOCK_SIZE] = [0u8; BLOCK_SIZE];
@@ -125,7 +146,7 @@ fn main() -> std::io::Result<()> {
&mut buf,
&server_SocketAddr,
&socket,
&cli.network_id,
&network_id,
&cli.password,
) {
Ok(n) => {
@@ -137,7 +158,7 @@ fn main() -> std::io::Result<()> {
let _ = net::send_heartbeat(
&mut buf,
&server_SocketAddr,
&socket,
socket.clone(),
&n,
&public_sock_addr,
&iv,
@@ -152,7 +173,7 @@ fn main() -> std::io::Result<()> {
None => false,
},
encryption_key,
cli.network_id,
network_id,
salt,
Vec::with_capacity(1),
);
@@ -165,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) => {
@@ -195,18 +227,43 @@ fn main() -> std::io::Result<()> {
let encrypted = network_write_lock.encrypted;
let key = network_write_lock.key;
network_write_lock.peers.iter_mut().for_each(|peer| {
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;
println!(
"{} firing salvo of PUNCHING packets to {}",
"[LOG]".blue(),
peer.sock_addr
);
for _ in 0..MAPPING_SHOT_COUNT {
match socket.send_to(&[P2PMethods::DO_NOTHING as u8], peer.sock_addr) {
Ok(s) => {
#[cfg(debug_assertions)]
eprintln!("send {} bytes", s);
}
Err(e) => eprintln!("{} failed to send puching packet: {}", "[ERROR]".red(), e),
}
Err(e) => eprintln!(
"{} while getting ip from peer: {}, Error: {}",
"[ERROR]".red(),
peer.sock_addr,
e
),
};
}
println!(
"{} packets away!, awiting a bit for NAT mappings to estabilish",
"[LOG]".blue()
);
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));
}
}
}
});
network_write_lock.private_ip = std::net::Ipv4Addr::new(
@@ -273,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) {
+69 -14
View File
@@ -8,6 +8,7 @@ use super::types;
use colored::Colorize;
use pea_2_pea::{shared::net::send_and_recv_with_retry, *};
use rand::{RngCore, rng};
use sha2::Digest;
pub fn query_request(
buf: &mut [u8; UDP_BUFFER_SIZE],
@@ -254,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],
@@ -299,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),
}
@@ -432,16 +442,30 @@ pub async fn handle_incoming_connection(
&network.read().unwrap().key,
&buf[P2PStandardDataPositions::IV as usize
..P2PStandardDataPositions::IV as usize + BLOCK_SIZE],
&buf[P2PStandardDataPositions::DATA as usize..data_lenght as usize-1 /*compensate for size and index diference*/],
&buf[P2PStandardDataPositions::DATA as usize..data_lenght as usize],
) {
Ok(data) => match tun_iface.send(&data) {
Ok(_) => {}
Err(e) => eprintln!(
"{} failed to write packet to tun interface, Error: {}",
"[WARNING]".yellow(),
e
),
},
Ok(data) => {
#[cfg(debug_assertions)]
eprintln!(
"packet contets: {}\nhash: {:x}",
data.iter()
.map(|x| format!("{:02X} ", x))
.collect::<String>(),
{
let mut hasher = sha2::Sha256::new();
hasher.update(&data);
hasher.finalize()
}
);
match tun_iface.send(&data) {
Ok(_) => {}
Err(e) => eprintln!(
"{} failed to write packet to tun interface, Error: {}",
"[WARNING]".yellow(),
e
),
}
}
Err(e) => eprintln!(
"{} failed to decrypt packet, Error: {}",
"[WARNING]".yellow(),
@@ -449,9 +473,15 @@ pub async fn handle_incoming_connection(
),
}
} else {
match tun_iface.send(&buf[P2PStandardDataPositions::DATA as usize..data_lenght as usize-1 /*compensate for size and index diference*/]) {
Ok(_) => {},
Err(e) => eprintln!("{} failed to write packet to tun interface, Error: {}", "[WARNING]".yellow(), e),
match tun_iface
.send(&buf[P2PStandardDataPositions::DATA as usize..data_lenght as usize])
{
Ok(_) => {}
Err(e) => eprintln!(
"{} failed to write packet to tun interface, Error: {}",
"[WARNING]".yellow(),
e
),
};
}
}
@@ -697,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!",
@@ -706,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
);
}
}
}
}
+62 -18
View File
@@ -1,8 +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;
@@ -10,20 +11,41 @@ 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);
}
pub async fn read_tun_iface(
pub fn read_tun_iface(
tun_iface: Arc<tappers::Tun>,
socket: Arc<std::net::UdpSocket>,
network: Arc<RwLock<Network>>,
@@ -31,10 +53,12 @@ pub async fn read_tun_iface(
let mut buf: [u8; IP_BUFFER_SIZE] = [0u8; IP_BUFFER_SIZE];
smol::block_on(async {
#[cfg(debug_assertions)]
eprintln!("Started listening for ip packets");
loop {
let data_lenght = tun_iface.recv(&mut buf).unwrap(); // build in auto termination, isn't it great
smol::spawn(handle_ip_packet(
buf[..data_lenght - 1].to_vec().into(),
buf[..data_lenght].to_vec().into(),
network.clone(),
socket.clone(),
))
@@ -48,6 +72,23 @@ pub async fn handle_ip_packet(
network: Arc<RwLock<Network>>,
socket: Arc<std::net::UdpSocket>,
) {
#[cfg(debug_assertions)]
eprintln!("Processing IP packet");
#[cfg(debug_assertions)]
eprintln!(
"packet contets: {}\nhash: {:x}",
packet_data
.iter()
.map(|x| format!("{:02X} ", x))
.collect::<String>(),
{
let mut hasher = sha2::Sha256::new();
hasher.update(&packet_data);
hasher.finalize()
}
);
let dst_ip = std::net::Ipv4Addr::from(
match <[u8; 4]>::try_from(
&packet_data[DEST_IN_IPV4_OFFSET..DEST_IN_IPV4_OFFSET + IPV4_SIZE],
@@ -64,22 +105,25 @@ pub async fn handle_ip_packet(
let mut iv: [u8; BLOCK_SIZE] = [0u8; BLOCK_SIZE];
rng.fill_bytes(&mut iv);
let mut encrypted_data =
let mut procesed_data: Vec<u8> = if network.read().unwrap().encrypted {
match shared::crypto::encrypt(&network.read().unwrap().key, &iv, &packet_data) {
Ok(cr) => cr,
Err(e) => {
eprintln!("Failed to encrypt packet droping it: {}", e);
return;
}
};
}
} else {
packet_data.to_vec()
};
encrypted_data.insert(0, P2PMethods::PACKET as u8);
encrypted_data.splice(1..1, iv);
procesed_data.insert(0, P2PMethods::PACKET as u8);
procesed_data.splice(1..1, iv);
if dst_ip.octets()[3] == 255 {
network.read().unwrap().peers.par_iter().for_each(|peer| {
// broadcast
match socket.send_to(&encrypted_data, peer.sock_addr) {
match socket.send_to(&procesed_data, peer.sock_addr) {
Ok(_) => {}
Err(e) => eprintln!("failed to send packet: {}", e),
};
@@ -97,7 +141,7 @@ pub async fn handle_ip_packet(
None => return,
};
match socket.send_to(&encrypted_data, dst) {
match socket.send_to(&procesed_data, dst) {
Ok(_) => {}
Err(e) => eprintln!("failed to send packet: {}", e),
};
+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;
}
})
}
}
}