diff --git a/.gitignore b/.gitignore index ea8c4bf..5bc7634 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/joh_git \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index dbd24fb..6207ca6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,633 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[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.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9" +dependencies = [ + "shlex", +] + +[[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.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b14e4ac78394e3ea04edbbc412099cf54f2f52ded51efb79c466a282729399d2" +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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[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.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[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.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" + +[[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 = "rs-tcp" version = "0.1.0" +dependencies = [ + "etherparse", + "tun-tap", +] + +[[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 = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[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 = "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 index 4eb1d49..9283a50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] +etherparse = "0.17.0" +tun-tap = "0.1.4" diff --git a/examples/bin.rs b/examples/bin.rs new file mode 100644 index 0000000..6d78261 --- /dev/null +++ b/examples/bin.rs @@ -0,0 +1,69 @@ +use rs_tcp::*; +use std::{ + collections::{hash_map::Entry, HashMap}, + io, +}; + +fn main() -> io::Result<()> { + let mut nic = tun_tap::Iface::without_packet_info("mytun0", tun_tap::Mode::Tun)?; + let mut buffer = vec![0; 1500]; + // 保存所有连接对应的状态 + let mut connections: HashMap = HashMap::new(); + + loop { + let nbytes = nic.recv(&mut buffer).unwrap(); + // 忽略非TCP数据包 + match etherparse::Ipv4HeaderSlice::from_slice(&buffer) { + Ok(iph) => { + let src = iph.source_addr(); + let dst = iph.destination_addr(); + let proto = iph.protocol(); + if proto != etherparse::IpNumber(0x06) { + continue; + } + match etherparse::TcpHeaderSlice::from_slice(&buffer[iph.slice().len()..nbytes]) { + Ok(tcph) => { + let payload_offset = iph.slice().len() + tcph.slice().len(); + let mut payload = &buffer[payload_offset..nbytes]; + + let recv_quad = Quad { + src: (src, tcph.source_port()), + dst: (dst, tcph.destination_port()), + }; + // 这里我们需要处理接收到的Tcp数据包 + match connections.entry(recv_quad) { + Entry::Occupied(mut occupied_entry) => { + // 已经存在的连接 + occupied_entry.get_mut().on_packet(iph, tcph, &payload); + }, + Entry::Vacant(vacant_entry) => { + eprintln!( + "{}:{} -> {}:{} first handpacket syn: {}, seq: {}", + src, + tcph.source_port(), + dst, + tcph.destination_port(), + tcph.syn(), + tcph.sequence_number() + ); + // 第一次接受的包 + if let Some(c) = Connection::accept(&mut nic, iph, tcph)?{ + vacant_entry.insert(c); + } + }, + } + } + Err(e) => { + // 这不是一个TCP包 但是协议是TCP + eprintln!("ignoring weird packet: {:?}", e) + } + } + } + Err(_) => { + // 非IP标准包 忽略 + continue; + } + }; + } + Ok(()) +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..30242ef --- /dev/null +++ b/readme.md @@ -0,0 +1,7 @@ +# rs-tcp + +使用`rust`从底层网络链路实现`TCP`协议。 + +```bash +git remote add origin ssh://git@81.70.52.148:17022/asahi/rs-tcp.git +``` \ No newline at end of file diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..d1056b8 --- /dev/null +++ b/run.sh @@ -0,0 +1,13 @@ +#!/bin/bash +cargo build --example bin -r +ext=$? +if [[ $ext -ne 0 ]]; then + exit $ext +fi +sudo setcap cap_net_admin=eip ./target/release/examples/bin +./target/release/examples/bin & +pid=$! +sudo ip addr add 192.168.0.1/24 dev mytun0 +sudo ip link set up dev mytun0 +trap "kill $pid" INT TERM +wait $pid \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index b93cf3f..064a0c1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,161 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right +use std::{io, net::Ipv4Addr}; + +#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +pub struct Quad { + pub src: (Ipv4Addr, u16), + pub dst: (Ipv4Addr, u16), } -#[cfg(test)] -mod tests { - use super::*; +#[derive(Debug)] +pub enum State { + //Listen, + SynRcvd, + Estab, + FinWait1, + FinWait2, + TimeWait, +} +/// 对于一个连接,我们需要保存其中的状态上下文 +/// 主要是滑动窗口部分的状态 +pub struct RecvStateContext { + /// 下一个接受的seq值 + pub nxt: u32, + /// 窗口大小 + pub wnd: u16, + /// 由对方设置的初始接受序列号 + pub irs: u32, +} +/// 一个连接既可以是接受方,也可以是发送方 +/// 所以还需要一个结构保存发送时的状态信息 +pub struct SendStateContext { + /// 滑动窗口的左边界指针 + pub una: u32, + /// 存放下一个发送的seq值 + pub nxt: u32, + /// 发送方窗口大小 + pub wnd: u16, + /// 由自己设置的初始发送序列号 + pub iss: u32, +} - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); +pub struct Connection { + state: State, + send: SendStateContext, + recv: RecvStateContext, + iph: etherparse::Ipv4Header +} +impl Connection { + pub fn on_packet<'a>( + &mut self, + iph: etherparse::Ipv4HeaderSlice<'a>, + tcph: etherparse::TcpHeaderSlice<'a>, + data: &'a [u8], + ) { + // 需要检查是否接受 + // SND.UNA < SEG.ACK <= SND.NXT + let ack = tcph.acknowledgment_number(); + if !is_cyclic_order(self.send.una, ack, self.send.nxt.wrapping_add(1)){ + eprintln!("不在可接受的范围!"); + return; + } + match self.state { + State::SynRcvd => { + eprintln!("接收到第三次握手包!"); + + self.state = State::Estab; + }, + State::Estab => { + // 握手结束 + // TODO: 3:31:04 开始编写结束连接 + }, + State::FinWait1 => todo!(), + State::FinWait2 => todo!(), + State::TimeWait => todo!(), + } + } + + pub fn accept<'a>( + nic: &'a mut tun_tap::Iface, + iph: etherparse::Ipv4HeaderSlice<'a>, + tcph: etherparse::TcpHeaderSlice<'a>, + ) -> io::Result> { + let mut buf = [0u8; 1500]; + // 回应握手包 + if !tcph.syn() { + // 只响应syn数据包 + return Ok(None); + } + let iss = 0; + let wnd = 1024; + let mut c = Connection { + state: State::SynRcvd, + send: SendStateContext{ + iss, + una: iss, + nxt: iss, + wnd, + }, + recv: RecvStateContext{ + irs: tcph.sequence_number(), + nxt: tcph.sequence_number() + 1, + wnd: tcph.window_size(), + }, + iph: etherparse::Ipv4Header::new( + 0, + 64, + etherparse::IpNumber::TCP, + iph.destination(), + iph.source(), + ).expect("create ip header fail!") + }; + + // 准备回复SYN+ACK 握手包 + let mut syn_ack = etherparse::TcpHeader::new( + tcph.destination_port(), + tcph.source_port(), + c.send.iss, + 10, + ); + // acknowledgment_number 期望接收的下一个字节的序号 + syn_ack.acknowledgment_number = tcph.sequence_number() + 1; + syn_ack.ack = true; + syn_ack.syn = true; + c.iph.set_payload_len(syn_ack.header_len()); + let unwritten = { + let mut unwritten = &mut buf[..]; + c.iph.write(&mut unwritten); + syn_ack.write(&mut unwritten); + unwritten.len() + }; + nic.send(&buf[..unwritten])?; + Ok(Some(c)) } } + + +/// 判断三个无符号整数是否按顺时针方向形成环形递增顺序 +/// +/// # 参数 +/// - `start`:起始点 +/// - `middle`:中间点(预期在 `start` 顺时针方向) +/// - `end`:终点(预期在 `middle` 顺时针方向) +/// +/// # 返回值 +/// 如果满足 `start → middle → end` 的顺时针递增顺序(允许溢出环绕),返回 `true` +fn is_cyclic_order(start: u32, middle: u32, end: u32) -> bool { + // 计算环形空间的最大半值(超过此值代表逆时针方向更短) + let half_max_value = u32::MAX / 2 + 1; + + // 计算各点间的顺时针距离(考虑溢出) + let start_to_middle_distance = middle.wrapping_sub(start); + let middle_to_end_distance = end.wrapping_sub(middle); + let start_to_end_distance = end.wrapping_sub(start); + + // 验证条件: + // 1. start到middle的顺时针距离不超过半环 + // 2. middle到end的顺时针距离不超过半环 + // 3. start到end的总距离等于前两段距离之和(确保连续性) + start_to_middle_distance <= half_max_value && + middle_to_end_distance <= half_max_value && + start_to_end_distance == start_to_middle_distance + middle_to_end_distance +} \ No newline at end of file diff --git a/tests/test.rs b/tests/test.rs new file mode 100644 index 0000000..0f4718b --- /dev/null +++ b/tests/test.rs @@ -0,0 +1,3 @@ +#[cfg(test)] +mod tests { +} diff --git a/work.dio b/work.dio new file mode 100644 index 0000000..e69de29 diff --git a/work.md b/work.md new file mode 100644 index 0000000..3e436c9 --- /dev/null +++ b/work.md @@ -0,0 +1,84 @@ +# 开始 + +## 架构相关 + +### 依赖 + +- `tun_tap`: 创建低级网络设备的`crate`。 +- `tshark`: `wireshark`的终端版本,安装`wireshark`自己会带。 +- `etherparse`:用来解析`Tcp`和`IP`部分,并且提供了简便访问成员的封装。 + +### 传输链路 + +```mermaid +graph LR + A[TUN 接口] --> B(接收 IP 数据包); + B --> C{解析 IP 数据包}; + C --> D[解析 TCP 头部]; + D --> E[解析 TCP 数据体]; + E --> F{你的逻辑处理}; + F --> G[构造 IP 数据包]; + G --> H[包装 TCP 结构]; + H --> I(通过 TUN 发送); + I --> A; + + style A fill:#f9f,stroke:#333,stroke-width:2px + style I fill:#3e89,stroke:#333,stroke-width:2px + style F fill:#05aa20,stroke:#333,stroke-width:2px + + classDef process fill:#fffff,stroke:#ffff,stroke-width:1px + class C,D,E,G,H process +``` + +使用`TUN`模式进行低级网络传输。我们从`NIC`中获取到的是一个`IP`数据包。 + +具体流程,我们需要先解析这个`IP`数据包,然后解析其中的数据,将它作为`TCP`进行解析,最终我们将我们的数据包装为`IP`数据包,然后传输到`TUN`中,实现通信。 + +### 项目测试 + +我们在`example/bin.rs`中编写我们的启动测试主程序。`tests`目录主要是用来编写单元测试。 + +```bash +#!/bin/bash +cargo build --example bin -r +ext=$? +if [[ $ext -ne 0 ]]; then + exit $ext +fi +sudo setcap cap_net_admin=eip ./target/release/examples/bin # 赋予程序网络控制权限,因为要创建tun接口 +./target/release/examples/bin & +pid=$! +echo $pid +sudo ip addr add 192.168.0.1/24 dev mytun0 # 为我们的虚拟网卡绑定IP和掩码 +sudo ip link set up dev mytun0 # 激活设备 +trap "kill $pid" INT TERM +wait $pid +``` + +#### 抓包 + +```bash +sudo tshark -i mytun0 # 使用tshark监听mytun0设备 +``` + +![image-20250216153930334](http://qiniu.asahichyan33.top/images/202502161539384.png) + +## 开始编写 + +### 滑动窗口 + +**接受方滑动窗口** + +![image-20250216204749732](http://qiniu.asahichyan33.top/images/202502162047809.png) + +**发送方滑动窗口** + +![image-20250216205251736](http://qiniu.asahichyan33.top/images/202502162052832.png) + +--- + +当发送方接收到`ACK`后,会将`SND.UNA`向右移动。 + +而接收方接收到数据包后,会连续的将`RCV.NXT`向右移动,当遇到丢包,就会触发重传。 + +需要注意,发送方和接收方都存在窗口大小,当发送方发送消息时,同时收到`接收方滑动窗口大小`和`自身窗口大小`的限制。 \ No newline at end of file