add stuff

This commit is contained in:
Adam 2024-01-12 07:57:39 -05:00
parent 3405c0b85d
commit 1636c4c60e
6 changed files with 1037 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

628
Cargo.lock generated Normal file
View file

@ -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",
]

10
Cargo.toml Normal file
View file

@ -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"

6
run Executable file
View file

@ -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

70
src/main.rs Normal file
View file

@ -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<Quad, tcp::State> = 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(())
}

322
src/tcp.rs Normal file
View file

@ -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<usize> {
// 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<Option<Self>> {
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(),
);
}
}