From 1636c4c60e48ba87f2179701302cb0aae953c179 Mon Sep 17 00:00:00 2001 From: Adam <24621027+WhiteDopeOnPunk@users.noreply.github.com> Date: Fri, 12 Jan 2024 07:57:39 -0500 Subject: [PATCH] add stuff --- .gitignore | 1 + Cargo.lock | 628 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 10 + run | 6 + src/main.rs | 70 ++++++ src/tcp.rs | 322 +++++++++++++++++++++++++++ 6 files changed, 1037 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100755 run create mode 100644 src/main.rs create mode 100644 src/tcp.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..1ad60ad --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,628 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" +dependencies = [ + "byteorder", + "iovec", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "maybe-uninit", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if", + "lazy_static", +] + +[[package]] +name = "etherparse" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "827292ea592108849932ad8e30218f8b1f21c0dfd0696698a18b5d0aed62d990" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + +[[package]] +name = "futures" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "lock_api" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "memoffset" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mio" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +dependencies = [ + "cfg-if", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + +[[package]] +name = "mio-uds" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" +dependencies = [ + "iovec", + "libc", + "mio", +] + +[[package]] +name = "miow" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + +[[package]] +name = "net2" +version = "0.2.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" +dependencies = [ + "cfg-if", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "parking_lot" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" +dependencies = [ + "lock_api", + "parking_lot_core", + "rustc_version", +] + +[[package]] +name = "parking_lot_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66b810a62be75176a80873726630147a5ca780cd33921e0b5709033e66b0a" +dependencies = [ + "cfg-if", + "cloudabi", + "libc", + "redox_syscall", + "rustc_version", + "smallvec", + "winapi 0.3.9", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "scoped-tls" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" +dependencies = [ + "maybe-uninit", +] + +[[package]] +name = "tcp" +version = "0.1.0" +dependencies = [ + "etherparse", + "tun-tap", +] + +[[package]] +name = "tokio" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" +dependencies = [ + "bytes", + "futures", + "mio", + "num_cpus", + "tokio-codec", + "tokio-current-thread", + "tokio-executor", + "tokio-fs", + "tokio-io", + "tokio-reactor", + "tokio-sync", + "tokio-tcp", + "tokio-threadpool", + "tokio-timer", + "tokio-udp", + "tokio-uds", +] + +[[package]] +name = "tokio-codec" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" +dependencies = [ + "bytes", + "futures", + "tokio-io", +] + +[[package]] +name = "tokio-core" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87b1395334443abca552f63d4f61d0486f12377c2ba8b368e523f89e828cffd4" +dependencies = [ + "bytes", + "futures", + "iovec", + "log", + "mio", + "scoped-tls", + "tokio", + "tokio-executor", + "tokio-io", + "tokio-reactor", + "tokio-timer", +] + +[[package]] +name = "tokio-current-thread" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" +dependencies = [ + "futures", + "tokio-executor", +] + +[[package]] +name = "tokio-executor" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" +dependencies = [ + "crossbeam-utils", + "futures", +] + +[[package]] +name = "tokio-fs" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" +dependencies = [ + "futures", + "tokio-io", + "tokio-threadpool", +] + +[[package]] +name = "tokio-io" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" +dependencies = [ + "bytes", + "futures", + "log", +] + +[[package]] +name = "tokio-reactor" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" +dependencies = [ + "crossbeam-utils", + "futures", + "lazy_static", + "log", + "mio", + "num_cpus", + "parking_lot", + "slab", + "tokio-executor", + "tokio-io", + "tokio-sync", +] + +[[package]] +name = "tokio-sync" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" +dependencies = [ + "fnv", + "futures", +] + +[[package]] +name = "tokio-tcp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" +dependencies = [ + "bytes", + "futures", + "iovec", + "mio", + "tokio-io", + "tokio-reactor", +] + +[[package]] +name = "tokio-threadpool" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" +dependencies = [ + "crossbeam-deque", + "crossbeam-queue", + "crossbeam-utils", + "futures", + "lazy_static", + "log", + "num_cpus", + "slab", + "tokio-executor", +] + +[[package]] +name = "tokio-timer" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" +dependencies = [ + "crossbeam-utils", + "futures", + "slab", + "tokio-executor", +] + +[[package]] +name = "tokio-udp" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" +dependencies = [ + "bytes", + "futures", + "log", + "mio", + "tokio-codec", + "tokio-io", + "tokio-reactor", +] + +[[package]] +name = "tokio-uds" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab57a4ac4111c8c9dbcf70779f6fc8bc35ae4b2454809febac840ad19bd7e4e0" +dependencies = [ + "bytes", + "futures", + "iovec", + "libc", + "log", + "mio", + "mio-uds", + "tokio-codec", + "tokio-io", + "tokio-reactor", +] + +[[package]] +name = "tun-tap" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a477a4e9367c72ac875d23cd07ac99ffa932497d8428767fed0cfa27bbabe50" +dependencies = [ + "cc", + "futures", + "libc", + "mio", + "tokio-core", +] + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..3a5205d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "tcp" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +etherparse = "0.13.0" +tun-tap = "0.1.4" diff --git a/run b/run new file mode 100755 index 0000000..baf3f06 --- /dev/null +++ b/run @@ -0,0 +1,6 @@ +#!/bin/bash +cargo b --release && +sudo setcap cap_net_admin=eip ./target/release/tcp && +./target/release/tcp && +sudo ip addr add 192.168.69.1/24 dev tun0 && +trap "killall tcp" INT TERM diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..68258f8 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,70 @@ +use std::io; +mod tcp; +use std::collections::HashMap; +use std::collections::hash_map::Entry; +use std::net::Ipv4Addr; + +#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +struct Quad { + src: (Ipv4Addr, u16), + dst: (Ipv4Addr, u16), +} + +fn main() -> io::Result<()> { + let mut connections: HashMap = Default::default(); + + let mut nic = tun_tap::Iface::without_packet_info("tun0", tun_tap::Mode::Tun)?; + + // buffer size 1504 bytes (maximum Ethernet frame size without CRC) + let mut buf = [0u8; 1504]; + + let stfu_unused = true; + while stfu_unused { + let nbytes = nic.recv(&mut buf[..])?; + + match etherparse::Ipv4HeaderSlice::from_slice(&buf[..nbytes]) { + Ok(iph) => { + let src = iph.source_addr(); + let dst = iph.destination_addr(); + + if iph.protocol() != 0x06 { + eprintln!("Not TCP, skipping..."); + continue; + } + + match etherparse::TcpHeaderSlice::from_slice(&buf[iph.slice().len()..nbytes]) { + Ok(tcph) => { + let datai = iph.slice().len() + tcph.slice().len(); + + match connections.entry(Quad { + src: (src, tcph.source_port()), + dst: (dst, tcph.destination_port()), + }) { + Entry::Occupied(mut c) => { + c.get_mut() + .on_packet(&mut nic, iph, tcph, &buf[datai..nbytes])?; + } + Entry::Vacant(mut e) => { + if let Some(c) = tcp::Connection::accept( + &mut nic, + iph, + tcph, + &buf[datai..nbytes], + )? { + e.insert(c); + } + } + } + } + Err(e) => { + eprintln!("An error occurred while parsing TCP packet: {:?}", e); + } + } + } + Err(e) => { + eprintln!("An error occurred while parsing IP packet: {:?}", e); + } + } + } + Ok(()) +} diff --git a/src/tcp.rs b/src/tcp.rs new file mode 100644 index 0000000..b7fd5eb --- /dev/null +++ b/src/tcp.rs @@ -0,0 +1,322 @@ +use std::io; +use std::io::prelude::*; + +pub enum State { + Closed, + Listen, + SynRcvd, + Estab, +} + +pub struct Connection { + state: State, + send: SendSequenceSpace, + recv: RecvSequenceSpace, + ip: etherparse::Ipv4Header, + tcp: etherparse::TcpHeader, +} + +struct SendSequenceSpace { + una: u32, + nxt: u32, + wnd: u16, + up: bool, + wl1: usize, + wl2: usize, + iss: u32, +} + +struct RecvSequenceSpace { + nxt: u32, + wnd: u16, + up: bool, + irs: u32, +} + +impl Default for State { + fn default() -> Self { + State::Listen + } +} + +impl Connection { + fn write(&mut self, nic: &mut tun_tap::Iface, seq: u32, mut limit: usize) -> io::Result { + // 1500 bytes ethernet max transmission unit (MTU) + let mut buf = [0u8; 1500]; + + self.tcp.sequence_number = seq; + self.tcp.acknowledgment_number = self.recv.nxt; + println!( + "write(ack: {}, seq: {}, limit: {}) syn {:?} fin {:?}", + self.recv.nxt - self.recv.irs, + seq, + limit, + self.tcp.syn, + self.tcp.fin, + ); + + let mut offset = seq.wrapping_sub(self.send.una) as usize; + + if let Some(closed_at) = self.closed_at { + if seq == closed_at.wrapping_add(1) { + offset = 0; + limit = 0; + } + } + + println!( + "using offset {} base {} in {:?}", + offset, + self.send.una, + self.unacked.as_slices() + ); + + let (mut h, mut t) = self.unacked.as_slices(); + if h.len() > offset { + h = &h[offset..]; + } else { + let skipped = h.len(); + h = &[]; + t = &t[(offset - skipped)..]; + } + + let max_data = std::cmp::min(limit, h.len() + t.len()); + let size = std::cmp::min( + buf.len(), + self.tcp.header_len() as usize + self.ip.header_len() as usize + max_data, + ); + + self.ip + .set_payload_len(size - self.ip.header_len() as usize); + + let buf_len = buf.len(); + let mut unwritten = &mut buf[..]; + + self.ip.write(&mut unwritten); + + let ip_header_ends_at = buf_len - unwritten.len(); + + unwritten = &mut unwritten[self.tcp.header_len() as usize..]; + let tcp_header_ends_at = buf_len - unwritten.len(); + + let payload_bytes = { + let mut written = 0; + let mut limit = max_data; + + let p1l = std::cmp::min(limit, h.len()); + written += unwritten.write(&h[..p1l])?; + limit -= written; + + let p2l = std::cmp::min(limit, t.len()); + written += unwritten.write(&t[..p2l])?; + written + }; + + let payload_ends_at = buf_len - unwritten.len(); + + self.tcp.checksum = self + .tcp + .calc_checksum_ipv4(&self.ip, &buf[tcp_header_ends_at..payload_ends_at]) + .expect("failed to compute checksum"); + + let mut unwritten = &mut buf[ip_header_ends_at..]; + self.tcp.write(&mut unwritten); + + let write_len = nic.send(&buf[..payload_ends_at])?; + + Ok(payload_bytes) + } +} +pub fn accept<'a>( + nic: &mut tun_tap::Iface, + iph: etherparse::Ipv4HeaderSlice<'a>, + tcph: etherparse::TcpHeaderSlice<'a>, + data: &'a [u8], +) -> io::Result> { + let mut buf = [0u8; 1500]; + if !tcph.syn() { + return Ok(None); + } + let iss = 0; + let wnd = 10; + let mut c = Connection { + state: State::SynRcvd, + send: SendSequenceSpace { + iss, + una: iss, + nxt: 1, + wnd: wnd, + up: false, + wl1: 0, + wl2: 0, + }, + recv: RecvSequenceSpace { + irs: tcph.sequence_number(), + nxt: tcph.sequence_number() + 1, + wnd: tcph.window_size(), + up: false, + }, + + // TODO: Consider keeping track of sender info for future use. + + // Prepare a SYN-ACK packet in response to the SYN packet. + tcp: etherparse::TcpHeader::new(tcph.destination_port(), tcph.source_port(), iss, wnd), + ip: etherparse::Ipv4Header::new( + syn_ack.header_len(), + 64, + etherparse::IpNumber::Tcp as u8, + [ + iph.destination()[0], + iph.destination()[1], + iph.destination()[2], + iph.destination()[3], + ], + [ + iph.source()[0], + iph.source()[1], + iph.source()[2], + iph.source()[3], + ], + ), + }; + + c.tcp.acknowledgment_number = c.recv.nxt; + c.tcp.syn = true; + c.tcp.ack = true; + + c.ip.set_payload_len(c.tcp.header_len() as usize + 0); + + // Calculate and set the checksum for the SYN-ACK packet. + c.tcp.checksum = c + .tcp + .calc_checksum_ipv4(&c.ip, &[]) + .expect("Failed to compute checksum"); + + // Write out the TCP and IP headers to a buffer to be sent. + let unwritten = { + let mut unwritten = &mut buf[..]; + ip.write(&mut unwritten); + syn_ack.write(&mut unwritten); + unwritten.len() + }; + + // Send the SYN-ACK packet. + nic.send(&buf[..unwritten])?; + Ok(Some(c)) +} + +// TODO: Implement a function to handle incoming packets for an established connection. + +// Function to handle incoming packets once a connection is established. +pub fn on_packet<'a>( + &mut self, + nic: &mut tun_tap::Iface, + iph: etherparse::Ipv4HeaderSlice<'a>, + tcph: etherparse::TcpHeaderSlice<'a>, + data: &'a [u8], +) -> io::Result<()> { + let seqn = tcph.sequence_number(); + let mut slen = data.len() as u32; + if tcph.fin() { + slen += 1; + }; + if tcph.syn() { + slen += 1; + }; + let wend = self.recv.nxt.wrapping_add(self.recv.wnd as u32); + + let okay = if slen == 0 { + if self.recv.wnd == 0 { + seqn == self.recv.nxt + } else { + is_between_wrapped(self.recv.nxt.wrapping_sub(1), seqn, wend) + } + } else { + if self.recv.wnd == 0 { + false + } else { + is_between_wrapped(self.recv.nxt.wrapping_sub(1), seqn, wend) || + is_between_wrapped(self.recv.nxt.wrapping_sub(1), seqn.wrapping_add(slen - 1), wend) + } + }; + + if !okay { + self.write(nic, self.send.nxt, 0)?; + return Ok(()); + } + + self.recv.nxt = seqn.wrapping_add(slen); + + if !tcph.ack() { + return Ok(()); + } + + let ackn = tcph.acknowledgment_number(); + + if let State::SynRcvd = self.state { + if is_between_wrapped(self.send.una.wrapping_sub(1), ackn, self.send.nxt.wrapping_add(1)) { + self.state = State::Estab; + } else { + } + } + + if let State::Estab | State::FinWait1 | State::FinWait2 = self.state { + if !is_between_wrapped(self.send.una, ackn, self.send.nxt.wrapping_add(1)) { + return Ok(()); + } + + self.send.una = ackn; + + assert!(data.is_empty()); + + if let State::Estab = self.state { + self.tcp.fin = true; + self.write(nic, self.send.nxt, 0)?; + self.state = State::FinWait1; + } + } + + if let State::FinWait1 = self.state { + if self.send.una == self.send.iss + 2 { + self.state = State::FinWait2; + } + } + + if tcph.fin() { + match self.state { + State::FinWait2 => { + self.write(nic, self.send.nxt, 0)?; + self.state = State::TimeWait; + } + _ => { } + } + } + + Ok(()) +} + +fn wrapping_it(lhs: u32, rhs: u32) -> bool { + lhs.wrapping_sub(rhs) > (1 << 31) +} + +fn is_between_wrapped(start: u32, x: u32, end: u32) -> bool { + wrapping_it(start, x) && wrapping_it(e, end) +} + +impl State { + pub fn on_packet<'a>( + &mut self, + iph: etherparse::Ipv4HeaderSlice<'a>, + tcph: etherparse::TcpHeaderSlice<'a>, + data: &'a [u8], + ) { + eprintln!( + "{}:{} -> {}:{} {}b of TCP", + iph.source_addr(), + tcph.source_port(), + iph.destination_addr(), + tcph.destination_port(), + data.len(), + ); + } +}