├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── docs └── images │ ├── google-example.gif │ └── overview.png ├── set_forward.sh ├── set_tap.sh └── src ├── app.rs ├── devices ├── ethernet.rs ├── loopback.rs └── mod.rs ├── drivers ├── mod.rs ├── pcap.rs └── tap.rs ├── interrupt.rs ├── main.rs ├── net.rs ├── protocols ├── arp.rs ├── ip │ ├── icmp.rs │ ├── mod.rs │ ├── tcp.rs │ └── udp.rs └── mod.rs └── utils ├── byte.rs ├── list.rs └── mod.rs /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.241.1/containers/rust/.devcontainer/base.Dockerfile 2 | 3 | # [Choice] Debian OS version (use bullseye on local arm64/Apple Silicon): buster, bullseye 4 | ARG VARIANT="bullseye" 5 | FROM mcr.microsoft.com/vscode/devcontainers/rust:1-${VARIANT} 6 | 7 | # [Optional] Uncomment this section to install additional packages. 8 | # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 9 | # && apt-get -y install --no-install-recommends 10 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.241.1/containers/rust 3 | { 4 | "name": "Rust", 5 | "build": { 6 | "dockerfile": "Dockerfile", 7 | "args": { 8 | // Use the VARIANT arg to pick a Debian OS version: buster, bullseye 9 | // Use bullseye when on local on arm64/Apple Silicon. 10 | "VARIANT": "bullseye" 11 | } 12 | }, 13 | "runArgs": [ 14 | "--cap-add=SYS_PTRACE", 15 | "--security-opt", 16 | "seccomp=unconfined", 17 | "--privileged", 18 | "--cap-add=NET_ADMIN", 19 | "--device=/dev/net/tun:/dev/net/tun" // tap device 20 | ], 21 | 22 | // Configure tool-specific properties. 23 | "customizations": { 24 | // Configure properties specific to VS Code. 25 | "vscode": { 26 | // Set *default* container specific settings.json values on container create. 27 | "settings": { 28 | "lldb.executable": "/usr/bin/lldb", 29 | // VS Code don't watch files under ./target 30 | "files.watcherExclude": { 31 | "**/target/**": true 32 | }, 33 | "rust-analyzer.checkOnSave.command": "clippy" 34 | }, 35 | 36 | // Add the IDs of extensions you want installed when the container is created. 37 | "extensions": [ 38 | "vadimcn.vscode-lldb", 39 | "mutantdino.resourcemonitor", 40 | "rust-lang.rust-analyzer", 41 | "tamasfe.even-better-toml", 42 | "serayuzgur.crates" 43 | ] 44 | } 45 | }, 46 | 47 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 48 | // "forwardPorts": [], 49 | 50 | // Use 'postCreateCommand' to run commands after the container is created. 51 | // "postCreateCommand": "rustc --version", 52 | 53 | // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. 54 | "remoteUser": "vscode" 55 | } 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .DS_Store -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "atty" 7 | version = "0.2.14" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 10 | dependencies = [ 11 | "hermit-abi", 12 | "libc", 13 | "winapi", 14 | ] 15 | 16 | [[package]] 17 | name = "autocfg" 18 | version = "1.1.0" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 21 | 22 | [[package]] 23 | name = "bitflags" 24 | version = "1.3.2" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 27 | 28 | [[package]] 29 | name = "cc" 30 | version = "1.0.73" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 33 | 34 | [[package]] 35 | name = "cfg-if" 36 | version = "0.1.10" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 39 | 40 | [[package]] 41 | name = "cfg-if" 42 | version = "1.0.0" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 45 | 46 | [[package]] 47 | name = "clap" 48 | version = "4.0.26" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e" 51 | dependencies = [ 52 | "atty", 53 | "bitflags", 54 | "clap_derive", 55 | "clap_lex", 56 | "once_cell", 57 | "strsim", 58 | "termcolor", 59 | ] 60 | 61 | [[package]] 62 | name = "clap_derive" 63 | version = "4.0.21" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" 66 | dependencies = [ 67 | "heck", 68 | "proc-macro-error", 69 | "proc-macro2", 70 | "quote", 71 | "syn", 72 | ] 73 | 74 | [[package]] 75 | name = "clap_lex" 76 | version = "0.3.0" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" 79 | dependencies = [ 80 | "os_str_bytes", 81 | ] 82 | 83 | [[package]] 84 | name = "getrandom" 85 | version = "0.2.8" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" 88 | dependencies = [ 89 | "cfg-if 1.0.0", 90 | "libc", 91 | "wasi", 92 | ] 93 | 94 | [[package]] 95 | name = "heck" 96 | version = "0.4.0" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 99 | 100 | [[package]] 101 | name = "hermit-abi" 102 | version = "0.1.19" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 105 | dependencies = [ 106 | "libc", 107 | ] 108 | 109 | [[package]] 110 | name = "ifstructs" 111 | version = "0.1.1" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "b24d770f92a5ea876a33851b16553f21985bb83e7fe8e7e1f596ad75545e9581" 114 | dependencies = [ 115 | "cfg-if 0.1.10", 116 | "libc", 117 | ] 118 | 119 | [[package]] 120 | name = "ioctl-sys" 121 | version = "0.6.0" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "1c429fffa658f288669529fc26565f728489a2e39bc7b24a428aaaf51355182e" 124 | 125 | [[package]] 126 | name = "itoa" 127 | version = "1.0.4" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" 130 | 131 | [[package]] 132 | name = "libc" 133 | version = "0.2.129" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "64de3cc433455c14174d42e554d4027ee631c4d046d43e3ecc6efc4636cdc7a7" 136 | 137 | [[package]] 138 | name = "log" 139 | version = "0.4.17" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 142 | dependencies = [ 143 | "cfg-if 1.0.0", 144 | ] 145 | 146 | [[package]] 147 | name = "memoffset" 148 | version = "0.6.5" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" 151 | dependencies = [ 152 | "autocfg", 153 | ] 154 | 155 | [[package]] 156 | name = "nix" 157 | version = "0.25.0" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb" 160 | dependencies = [ 161 | "autocfg", 162 | "bitflags", 163 | "cfg-if 1.0.0", 164 | "libc", 165 | "memoffset", 166 | "pin-utils", 167 | ] 168 | 169 | [[package]] 170 | name = "num_threads" 171 | version = "0.1.6" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" 174 | dependencies = [ 175 | "libc", 176 | ] 177 | 178 | [[package]] 179 | name = "once_cell" 180 | version = "1.16.0" 181 | source = "registry+https://github.com/rust-lang/crates.io-index" 182 | checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" 183 | 184 | [[package]] 185 | name = "os_str_bytes" 186 | version = "6.4.0" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "7b5bf27447411e9ee3ff51186bf7a08e16c341efdde93f4d823e8844429bed7e" 189 | 190 | [[package]] 191 | name = "pin-utils" 192 | version = "0.1.0" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 195 | 196 | [[package]] 197 | name = "ppv-lite86" 198 | version = "0.2.16" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" 201 | 202 | [[package]] 203 | name = "proc-macro-error" 204 | version = "1.0.4" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 207 | dependencies = [ 208 | "proc-macro-error-attr", 209 | "proc-macro2", 210 | "quote", 211 | "syn", 212 | "version_check", 213 | ] 214 | 215 | [[package]] 216 | name = "proc-macro-error-attr" 217 | version = "1.0.4" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 220 | dependencies = [ 221 | "proc-macro2", 222 | "quote", 223 | "version_check", 224 | ] 225 | 226 | [[package]] 227 | name = "proc-macro2" 228 | version = "1.0.47" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" 231 | dependencies = [ 232 | "unicode-ident", 233 | ] 234 | 235 | [[package]] 236 | name = "quote" 237 | version = "1.0.21" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" 240 | dependencies = [ 241 | "proc-macro2", 242 | ] 243 | 244 | [[package]] 245 | name = "rand" 246 | version = "0.8.5" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 249 | dependencies = [ 250 | "libc", 251 | "rand_chacha", 252 | "rand_core", 253 | ] 254 | 255 | [[package]] 256 | name = "rand_chacha" 257 | version = "0.3.1" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 260 | dependencies = [ 261 | "ppv-lite86", 262 | "rand_core", 263 | ] 264 | 265 | [[package]] 266 | name = "rand_core" 267 | version = "0.6.4" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 270 | dependencies = [ 271 | "getrandom", 272 | ] 273 | 274 | [[package]] 275 | name = "rust-user-net" 276 | version = "0.1.0" 277 | dependencies = [ 278 | "clap", 279 | "ifstructs", 280 | "ioctl-sys", 281 | "log", 282 | "nix", 283 | "rand", 284 | "signal-hook", 285 | "simplelog", 286 | ] 287 | 288 | [[package]] 289 | name = "serde" 290 | version = "1.0.147" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" 293 | 294 | [[package]] 295 | name = "signal-hook" 296 | version = "0.3.14" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" 299 | dependencies = [ 300 | "cc", 301 | "libc", 302 | "signal-hook-registry", 303 | ] 304 | 305 | [[package]] 306 | name = "signal-hook-registry" 307 | version = "1.4.0" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 310 | dependencies = [ 311 | "libc", 312 | ] 313 | 314 | [[package]] 315 | name = "simplelog" 316 | version = "0.12.0" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "48dfff04aade74dd495b007c831cd6f4e0cee19c344dd9dc0884c0289b70a786" 319 | dependencies = [ 320 | "log", 321 | "termcolor", 322 | "time", 323 | ] 324 | 325 | [[package]] 326 | name = "strsim" 327 | version = "0.10.0" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 330 | 331 | [[package]] 332 | name = "syn" 333 | version = "1.0.103" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" 336 | dependencies = [ 337 | "proc-macro2", 338 | "quote", 339 | "unicode-ident", 340 | ] 341 | 342 | [[package]] 343 | name = "termcolor" 344 | version = "1.1.3" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 347 | dependencies = [ 348 | "winapi-util", 349 | ] 350 | 351 | [[package]] 352 | name = "time" 353 | version = "0.3.17" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" 356 | dependencies = [ 357 | "itoa", 358 | "libc", 359 | "num_threads", 360 | "serde", 361 | "time-core", 362 | "time-macros", 363 | ] 364 | 365 | [[package]] 366 | name = "time-core" 367 | version = "0.1.0" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" 370 | 371 | [[package]] 372 | name = "time-macros" 373 | version = "0.2.6" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" 376 | dependencies = [ 377 | "time-core", 378 | ] 379 | 380 | [[package]] 381 | name = "unicode-ident" 382 | version = "1.0.5" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" 385 | 386 | [[package]] 387 | name = "version_check" 388 | version = "0.9.4" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 391 | 392 | [[package]] 393 | name = "wasi" 394 | version = "0.11.0+wasi-snapshot-preview1" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 397 | 398 | [[package]] 399 | name = "winapi" 400 | version = "0.3.9" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 403 | dependencies = [ 404 | "winapi-i686-pc-windows-gnu", 405 | "winapi-x86_64-pc-windows-gnu", 406 | ] 407 | 408 | [[package]] 409 | name = "winapi-i686-pc-windows-gnu" 410 | version = "0.4.0" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 413 | 414 | [[package]] 415 | name = "winapi-util" 416 | version = "0.1.5" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 419 | dependencies = [ 420 | "winapi", 421 | ] 422 | 423 | [[package]] 424 | name = "winapi-x86_64-pc-windows-gnu" 425 | version = "0.4.0" 426 | source = "registry+https://github.com/rust-lang/crates.io-index" 427 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 428 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust-user-net" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | signal-hook = { version = "0.3.14", features = ["extended-siginfo"] } 10 | nix = "0.25.0" 11 | ifstructs = "0.1.1" 12 | ioctl = { version = "0.6", package = "ioctl-sys" } 13 | rand = "0.8.5" 14 | log = "0.4" 15 | simplelog = "^0.12.0" 16 | clap = { version = "4.0.26", features = ["derive"] } 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-user-net 2 | 3 | User-space network protocol stack written in Rust for study / experiment purpose 4 | 5 | Talks Ethernet / ARP / IP / ICMP / UDP / TCP through TAP device on Linux. 6 | 7 | 8 | 9 | This project is by and large a Rust port of [microps](https://github.com/pandax381/microps) project written in C. Many thanks to [the owner](https://github.com/pandax381) for awesome codes and shared [decks](https://drive.google.com/drive/folders/1k2vymbC3vUk5CTJbay4LLEdZ9HemIpZe?usp=share_link) (Japanese). 10 | 11 | ### High-level View 12 | 13 | 14 | 15 | ### Setup and Usage 16 | 17 | - Built and tested on Ubuntu 22.04 18 | 19 | ```sh 20 | cd rust-user-net 21 | 22 | # Build 23 | cargo build 24 | 25 | # TAP device setup (will be reset on reboot) 26 | ./set_tap.sh 27 | 28 | # If you want rust-user-net to connect to Internet: 29 | # Output interface name is assumed to be `wlp0s20f3`. 30 | # Please update it if it's different in your machine. 31 | ./set_forward.sh 32 | 33 | # Show help 34 | ./rust-user-net -h 35 | ./rust-user-net tcp -h 36 | ./rust-user-net tcp send -h 37 | ``` 38 | 39 | ### Example 40 | 41 | HTTP (TCP: 80) request to `http://www.google.com`: 42 | 43 | ```sh 44 | # Send command sends a request and gets into receive loop 45 | rust-user-net tcp send 142.250.4.138 80 'GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n' 46 | ``` 47 | 48 | ### Local Tests with netcat 49 | 50 | ```sh 51 | # TCP 52 | 53 | # Test send command: 54 | # nc listens for TCP active open (3-way handshake) from rust-user-net 55 | nc -nv -l 10007 56 | rust-user-net tcp send 192.0.2.1 10007 "TCP TEST DATA" 57 | 58 | # Test receive command: 59 | # nc connects and sends data to rust-user-net (192.0.2.2:7) 60 | rust-user-net tcp receive 0.0.0.0 7 61 | nc -nv 192.0.2.2 7 # -n: no name resolution 62 | 63 | # UDP 64 | 65 | # Test send command: 66 | # nc listens for UDP data from rust-user-net 67 | nc -u -l 10007 68 | rust-user-net udp send 192.0.2.1 10007 "UDP TEST DATA" 69 | 70 | # Test receive command: 71 | # nc sends UDP data to rust-user-net (192.0.2.2:7) 72 | rust-user-net udp receive 0.0.0.0 7 73 | nc -u 192.0.2.2 7 # -u: UDP mode 74 | ``` -------------------------------------------------------------------------------- /docs/images/google-example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ykskb/rust-user-net/3a063dff0f254ba950b37c65b19397ce65349c4d/docs/images/google-example.gif -------------------------------------------------------------------------------- /docs/images/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ykskb/rust-user-net/3a063dff0f254ba950b37c65b19397ce65349c4d/docs/images/overview.png -------------------------------------------------------------------------------- /set_forward.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "Enabling IP forwarding..." 4 | sudo bash -c "echo 1 > /proc/sys/net/ipv4/ip_forward" 5 | 6 | echo "Appending FORWARD rule: ACCEPT output to interface: tap0..." 7 | sudo iptables -A FORWARD -o tap0 -j ACCEPT 8 | 9 | echo "Appending FORWARD rule: ACCEPT input via interface: tap0..." 10 | sudo iptables -A FORWARD -i tap0 -j ACCEPT 11 | 12 | # POSTROUTING: alter packets as they leave firewall's external device. 13 | echo "Appending POSTROUTING rule into NAT table: mask source to 192.0.2.0/24 and output to interface: eth0..." 14 | # Replace output interface if your machine has different name below: 15 | sudo iptables -t nat -A POSTROUTING -s 192.0.2.0/24 -o wlp0s20f3 -j MASQUERADE 16 | 17 | # # Revert 18 | # sudo iptables -D FORWARD -o tap0 -j ACCEPT 19 | # sudo iptables -D FORWARD -i tap0 -j ACCEPT 20 | # sudo iptables -t nat -D POSTROUTING -s 192.0.2.0/24 -o wlp0s20f3 -j MASQUERADE 21 | -------------------------------------------------------------------------------- /set_tap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo "Adding TAP virtual interface: tap0..." 3 | sudo ip tuntap add mode tap user $USER name tap0 4 | 5 | echo "Attaching IP: 192.0.2.1/24 to device: tap0..." 6 | sudo ip addr add 192.0.2.1/24 dev tap0 7 | 8 | echo "Activating link: tap0..." 9 | sudo ip link set tap0 up 10 | 11 | # # Revert 12 | # sudo ip addr del 192.0.2.1/24 dev tap0 13 | -------------------------------------------------------------------------------- /src/app.rs: -------------------------------------------------------------------------------- 1 | use crate::devices::ethernet; 2 | use crate::devices::loopback; 3 | use crate::devices::{NetDeviceType, NetDevices}; 4 | use crate::protocols::arp::ArpTable; 5 | use crate::protocols::ip::icmp; 6 | use crate::protocols::ip::ip_addr_to_bytes; 7 | use crate::protocols::ip::ip_addr_to_str; 8 | use crate::protocols::ip::tcp; 9 | use crate::protocols::ip::udp; 10 | use crate::protocols::ip::{ 11 | IPAdress, IPEndpoint, IPHeaderIdManager, IPInterface, IPRoute, IPRoutes, 12 | }; 13 | use crate::protocols::{ControlBlocks, NetProtocol, NetProtocols, ProtocolContexts, ProtocolType}; 14 | use crate::utils::byte::le_to_be_u32; 15 | use clap::{Args, Parser, Subcommand}; 16 | use log::{info, warn}; 17 | use std::process; 18 | use std::str; 19 | use std::sync::Mutex; 20 | use std::{ 21 | sync::{ 22 | mpsc::{self, TryRecvError}, 23 | Arc, 24 | }, 25 | thread::{self, JoinHandle}, 26 | time::Duration, 27 | }; 28 | 29 | const LOOPBACK_IP: &str = "127.0.0.1"; 30 | const LOOPBACK_NETMASK: &str = "255.255.255.0"; 31 | const DEFAULT_GATEWAY: &str = "192.0.2.1"; 32 | const ETH_TAP_IP: &str = "192.0.2.2"; 33 | const ETH_TAP_NETMASK: &str = "255.255.255.0"; 34 | 35 | pub struct NetApp { 36 | pub devices: Arc>, 37 | pub protocols: Arc>, 38 | pub contexts: Arc>, 39 | pub pcbs: Arc>, 40 | } 41 | 42 | impl NetApp { 43 | pub fn new() -> NetApp { 44 | // Args 45 | let args = Cli::parse(); 46 | 47 | // Setups 48 | let mut devices = NetDevices::new(); 49 | let mut ip_routes = IPRoutes::new(); 50 | // Loopback device 51 | let mut loopback_device = loopback::init(0); 52 | loopback_device.open().unwrap(); 53 | 54 | // Loopback interface 55 | let loopback_interface = Arc::new(IPInterface::new(LOOPBACK_IP, LOOPBACK_NETMASK)); 56 | loopback_device.register_interface(loopback_interface.clone()); 57 | 58 | // Loopback route 59 | let loopback_route = IPRoute::interface_route(loopback_interface); 60 | 61 | devices.register(loopback_device); 62 | ip_routes.register(loopback_route); 63 | 64 | // Ethernet device 65 | let mut ethernet_device = ethernet::init(1, crate::drivers::DriverType::Tap); 66 | ethernet_device.open().unwrap(); 67 | 68 | // Ethernet Interface 69 | let ethernet_interface = Arc::new(IPInterface::new(ETH_TAP_IP, ETH_TAP_NETMASK)); 70 | ethernet_device.register_interface(ethernet_interface.clone()); 71 | 72 | devices.register(ethernet_device); 73 | 74 | // Default gateway route 75 | let default_gw_route = IPRoute::gateway_route(DEFAULT_GATEWAY, ethernet_interface); 76 | ip_routes.register(default_gw_route); 77 | 78 | // Protocol setup 79 | let mut protocols = NetProtocols::new(); 80 | 81 | // ARP 82 | let arp_proto = NetProtocol::new(ProtocolType::Arp); 83 | protocols.register(arp_proto); 84 | 85 | // IP 86 | let ip_proto = NetProtocol::new(ProtocolType::IP); 87 | protocols.register(ip_proto); 88 | 89 | // Protocol contexts 90 | let contexts = ProtocolContexts { 91 | arp_table: ArpTable::new(), 92 | ip_routes, 93 | ip_id_manager: IPHeaderIdManager::new(), 94 | }; 95 | 96 | NetApp { 97 | devices: Arc::new(Mutex::new(devices)), 98 | protocols: Arc::new(Mutex::new(protocols)), 99 | contexts: Arc::new(Mutex::new(contexts)), 100 | pcbs: Arc::new(Mutex::new(ControlBlocks::new())), 101 | } 102 | } 103 | 104 | pub fn run(&mut self, receiver: mpsc::Receiver<()>) -> JoinHandle<()> { 105 | let args = Cli::parse(); 106 | match args.command { 107 | Commands::Tcp(tcp) => { 108 | let tcp_command = tcp.command.unwrap(); 109 | match tcp_command { 110 | EndPointCommand::Send { 111 | target_ip, 112 | target_port, 113 | data, 114 | } => { 115 | return self.tcp_send_command(target_ip, target_port, data, receiver); 116 | } 117 | EndPointCommand::Receive { 118 | local_ip, 119 | local_port, 120 | } => { 121 | return self.tcp_receive_command(receiver); 122 | } 123 | }; 124 | } 125 | Commands::Udp(udp) => { 126 | let udp_command = udp.command.unwrap(); 127 | match udp_command { 128 | EndPointCommand::Send { 129 | target_ip, 130 | target_port, 131 | data, 132 | } => { 133 | return self.udp_send_command(target_ip, target_port, data, receiver); 134 | } 135 | EndPointCommand::Receive { 136 | local_ip, 137 | local_port, 138 | } => { 139 | return self.udp_receive_command(receiver); 140 | } 141 | } 142 | } 143 | } 144 | } 145 | 146 | pub fn close_sockets(&mut self) { 147 | let mut pcbs = self.pcbs.lock().unwrap(); 148 | pcbs.udp_pcbs.close_sockets(); 149 | pcbs.tcp_pcbs.close_sockets(); 150 | } 151 | 152 | pub fn handle_protocol(&mut self) { 153 | let devices = &mut self.devices.lock().unwrap(); 154 | let protocols = &mut self.protocols.lock().unwrap(); 155 | let contexts = &mut self.contexts.lock().unwrap(); 156 | let pcbs = &mut self.pcbs.lock().unwrap(); 157 | protocols.handle_data(devices, contexts, pcbs); 158 | } 159 | 160 | pub fn handle_irq(&mut self, irq: i32) { 161 | let devices = &mut self.devices.lock().unwrap(); 162 | let protocols = &mut self.protocols.lock().unwrap(); 163 | devices.handle_irq(irq, protocols); 164 | } 165 | 166 | pub fn tcp_transmit_thread(&mut self, receiver: mpsc::Receiver<()>) -> JoinHandle<()> { 167 | let pcbs_arc = self.pcbs.clone(); 168 | let devices_arc = self.devices.clone(); 169 | let contexts_arc = self.contexts.clone(); 170 | thread::spawn(move || loop { 171 | // transmit check interval: 100ms 172 | thread::sleep(Duration::from_millis(100)); 173 | 174 | // Termination check 175 | match receiver.try_recv() { 176 | Ok(_) | Err(TryRecvError::Disconnected) => { 177 | info!("TCP transmit thread Terminating."); 178 | break; 179 | } 180 | Err(TryRecvError::Empty) => {} 181 | } 182 | 183 | { 184 | let pcbs = &mut pcbs_arc.lock().unwrap(); 185 | let devices = &mut devices_arc.lock().unwrap(); 186 | let contexts = &mut contexts_arc.lock().unwrap(); 187 | let eth_device = devices.get_mut_by_type(NetDeviceType::Ethernet).unwrap(); 188 | tcp::retransmit(&mut pcbs.tcp_pcbs, eth_device, contexts); 189 | } 190 | }) 191 | } 192 | 193 | // CLI command implementations 194 | 195 | fn tcp_send_command( 196 | &mut self, 197 | target_ip: String, 198 | target_port: u16, 199 | data: String, 200 | receiver: mpsc::Receiver<()>, 201 | ) -> JoinHandle<()> { 202 | let pcbs_arc = self.pcbs.clone(); 203 | let devices_arc = self.devices.clone(); 204 | let contexts_arc = self.contexts.clone(); 205 | let mut sock_opt = None; 206 | let mut request_sent = false; 207 | thread::spawn(move || loop { 208 | // Termination check 209 | match receiver.try_recv() { 210 | Ok(_) | Err(TryRecvError::Disconnected) => { 211 | info!("App: thread terminating."); 212 | break; 213 | } 214 | Err(TryRecvError::Empty) => {} 215 | } 216 | if sock_opt.is_none() { 217 | sock_opt = { 218 | let local = IPEndpoint::new_from_str("192.0.2.2", 7); 219 | let remote = IPEndpoint::new_from_str(&target_ip, target_port); 220 | tcp::rfc793_open( 221 | local, 222 | Some(remote), 223 | true, 224 | pcbs_arc.clone(), 225 | devices_arc.clone(), 226 | contexts_arc.clone(), 227 | ) 228 | } 229 | } 230 | if !request_sent { 231 | info!("App: sending request"); 232 | let devices = &mut devices_arc.lock().unwrap(); 233 | let contexts = &mut contexts_arc.lock().unwrap(); 234 | let eth_device = devices.get_mut_by_type(NetDeviceType::Ethernet).unwrap(); 235 | 236 | let req = data 237 | .replace("\\r", "\r") 238 | .replace("\\n", "\n") 239 | .as_bytes() 240 | .to_vec(); // "GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n" 241 | tcp::send( 242 | sock_opt.unwrap(), 243 | req, 244 | eth_device, 245 | contexts, 246 | &mut pcbs_arc.clone(), 247 | ); 248 | request_sent = true; 249 | } 250 | info!("App: starting TCP receive..."); 251 | let receive_res = tcp::receive(sock_opt.unwrap(), 2048, pcbs_arc.clone()); 252 | if let Some(received) = receive_res { 253 | log_data(&received[..]); 254 | } 255 | }) 256 | } 257 | 258 | fn tcp_receive_command(&mut self, receiver: mpsc::Receiver<()>) -> JoinHandle<()> { 259 | let pcbs_arc = self.pcbs.clone(); 260 | let devices_arc = self.devices.clone(); 261 | let contexts_arc = self.contexts.clone(); 262 | let mut sock_opt = None; 263 | thread::spawn(move || loop { 264 | // Termination check 265 | match receiver.try_recv() { 266 | Ok(_) | Err(TryRecvError::Disconnected) => { 267 | info!("App: thread terminating."); 268 | break; 269 | } 270 | Err(TryRecvError::Empty) => {} 271 | } 272 | if sock_opt.is_none() { 273 | sock_opt = { 274 | let local = IPEndpoint::new_from_str("0.0.0.0", 7); 275 | tcp::rfc793_open( 276 | local, 277 | None, 278 | false, 279 | pcbs_arc.clone(), 280 | devices_arc.clone(), 281 | contexts_arc.clone(), 282 | ) 283 | } 284 | } 285 | if sock_opt.is_none() { 286 | info!("App: interrupted before establishing any connection."); 287 | return; 288 | } 289 | info!("App: starting TCP receive..."); 290 | let receive_res = tcp::receive(sock_opt.unwrap(), 2048, pcbs_arc.clone()); 291 | if let Some(received) = receive_res { 292 | log_data(&received[..]); 293 | } 294 | }) 295 | } 296 | 297 | fn udp_send_command( 298 | &mut self, 299 | target_ip: String, 300 | target_port: u16, 301 | data: String, 302 | receiver: mpsc::Receiver<()>, 303 | ) -> JoinHandle<()> { 304 | let pcbs_arc = self.pcbs.clone(); 305 | let devices_arc = self.devices.clone(); 306 | let contexts_arc = self.contexts.clone(); 307 | let mut soc_opt = None; 308 | let mut sent_count = 0; 309 | 310 | thread::spawn(move || loop { 311 | // Termination check 312 | match receiver.try_recv() { 313 | Ok(_) | Err(TryRecvError::Disconnected) => { 314 | info!("App: thread terminating."); 315 | break; 316 | } 317 | Err(TryRecvError::Empty) => {} 318 | } 319 | if soc_opt.is_none() { 320 | soc_opt = { 321 | let pcbs = &mut pcbs_arc.lock().unwrap(); 322 | let soc = udp::open(&mut pcbs.udp_pcbs); 323 | let local = IPEndpoint::new_from_str("0.0.0.0", 7); 324 | udp::bind(&mut pcbs.udp_pcbs, soc, local); 325 | Some(soc) 326 | } 327 | } 328 | // send twice to wait for ARP response once 329 | if sent_count < 2 { 330 | let devices = &mut devices_arc.lock().unwrap(); 331 | let contexts = &mut contexts_arc.lock().unwrap(); 332 | let pcbs = &mut pcbs_arc.lock().unwrap(); 333 | 334 | let remote = IPEndpoint::new_from_str(&target_ip, target_port); // 192.0.2.1 10007 335 | let eth_device = devices.get_mut_by_type(NetDeviceType::Ethernet).unwrap(); 336 | let req = data 337 | .replace("\\r", "\r") 338 | .replace("\\n", "\n") 339 | .as_bytes() 340 | .to_vec(); 341 | 342 | udp::send_to(soc_opt.unwrap(), req, remote, eth_device, contexts, pcbs); 343 | sent_count += 1; 344 | } else { 345 | info!("App: starting UDP receive..."); 346 | let receive_res = udp::receive_from(soc_opt.unwrap(), pcbs_arc.clone()); 347 | if let Some(entry) = receive_res { 348 | log_data(&entry.data[..]); 349 | } 350 | } 351 | // TODO: fix this hack to wait for ARP reply in signal thread 352 | thread::sleep(Duration::from_secs(1)); 353 | }) 354 | } 355 | 356 | fn udp_receive_command(&self, receiver: mpsc::Receiver<()>) -> JoinHandle<()> { 357 | let pcbs_arc = self.pcbs.clone(); 358 | let mut soc_opt = None; 359 | thread::spawn(move || loop { 360 | // Termination check 361 | match receiver.try_recv() { 362 | Ok(_) | Err(TryRecvError::Disconnected) => { 363 | info!("App: thread terminating."); 364 | break; 365 | } 366 | Err(TryRecvError::Empty) => {} 367 | } 368 | if soc_opt.is_none() { 369 | soc_opt = { 370 | let pcbs = &mut pcbs_arc.lock().unwrap(); 371 | let soc = udp::open(&mut pcbs.udp_pcbs); 372 | let local = IPEndpoint::new_from_str("0.0.0.0", 7); 373 | udp::bind(&mut pcbs.udp_pcbs, soc, local); 374 | Some(soc) 375 | } 376 | } 377 | info!("App: starting UDP receive..."); 378 | let receive_res = udp::receive_from(soc_opt.unwrap(), pcbs_arc.clone()); 379 | if let Some(entry) = receive_res { 380 | log_data(&entry.data[..]); 381 | } 382 | }) 383 | } 384 | } 385 | 386 | fn log_data(data: &[u8]) { 387 | let received_utf8 = str::from_utf8(data); 388 | if let Ok(utf8_str) = received_utf8 { 389 | info!("App: data received = {:?}", utf8_str); 390 | } else { 391 | warn!("App: UTF8 error. Data is {:02x?}", data); 392 | } 393 | } 394 | // TEST: ICMP output 395 | 396 | // let pid = process::id() % u16::MAX as u32; 397 | // let values = le_to_be_u32(pid << 16 | 1); 398 | // let icmp_type_echo: u8 = 8; 399 | // let ip_any = 0; 400 | // let dst = ip_addr_to_bytes("8.8.8.8").unwrap(); 401 | // icmp::output( 402 | // icmp_type_echo, 403 | // 0, 404 | // values, 405 | // data, 406 | // data_len, 407 | // ip_any, 408 | // dst, 409 | // eth_device, 410 | // contexts, 411 | // pcbs, 412 | // ); 413 | 414 | // CLI setup 415 | 416 | #[derive(Debug, Parser)] 417 | #[command(name = "rust-user-net")] 418 | #[command(about = "Network protocol stack in user space written in Rust.", long_about = None)] 419 | struct Cli { 420 | #[command(subcommand)] 421 | command: Commands, 422 | } 423 | 424 | #[derive(Debug, Subcommand)] 425 | enum Commands { 426 | Tcp(Tcp), 427 | Udp(Udp), 428 | } 429 | 430 | #[derive(Debug, Args)] 431 | #[command(args_conflicts_with_subcommands = true)] 432 | #[command(about = "Sends and/or receive TCP packets. `rust-user-net tcp -h` for more details.", long_about = None)] 433 | struct Tcp { 434 | #[command(subcommand)] 435 | command: Option, 436 | } 437 | 438 | #[derive(Debug, Args)] 439 | #[command(args_conflicts_with_subcommands = true)] 440 | #[command(about = "Sends and/or receive UDP packets. `rust-user-net udp -h` for more details.", long_about = None)] 441 | struct Udp { 442 | #[command(subcommand)] 443 | command: Option, 444 | } 445 | 446 | #[derive(Debug, Subcommand)] 447 | enum EndPointCommand { 448 | #[command(about = "Sends a request with data and starts a receive loop printing each segment received. Ctrl+C to end.", long_about = None)] 449 | Send { 450 | target_ip: String, 451 | target_port: u16, 452 | data: String, 453 | }, 454 | #[command(about = "Starts a receive loop printing out each segment received. Ctrl+C to end.", long_about = None)] 455 | Receive { 456 | local_ip: String, 457 | local_port: String, 458 | }, 459 | } 460 | -------------------------------------------------------------------------------- /src/devices/ethernet.rs: -------------------------------------------------------------------------------- 1 | use super::{ 2 | NetDevice, NetDeviceType, DEVICE_FLAG_BROADCAST, DEVICE_FLAG_NEED_ARP, NET_DEVICE_ADDR_LEN, 3 | }; 4 | use crate::{ 5 | drivers::{pcap, tap, DriverType}, 6 | interrupt::{self, IRQEntry}, 7 | protocols::ProtocolType, 8 | utils::byte::{be_to_le_u16, le_to_be_u16}, 9 | utils::{bytes_to_struct, to_u8_slice}, 10 | }; 11 | use log::{debug, trace}; 12 | use std::{convert::TryInto, mem::size_of}; 13 | 14 | pub const IRQ_ETHERNET: i32 = interrupt::INTR_IRQ_BASE + 2; 15 | 16 | const ETH_HDR_SIZE: usize = 14; 17 | const ETH_FRAME_MIN: usize = 60; // without FCS 18 | pub const ETH_FRAME_MAX: usize = 1514; // without FCS 19 | const ETH_PAYLOAD_MIN: usize = ETH_FRAME_MIN - ETH_HDR_SIZE; 20 | const ETH_PAYLOAD_MAX: usize = ETH_FRAME_MAX - ETH_HDR_SIZE; 21 | 22 | pub const ETH_ADDR_ANY: [u8; 6] = [0x00; 6]; 23 | pub const ETH_ADDR_BROADCAST: [u8; 6] = [0xff; 6]; 24 | pub const ETH_ADDR_LEN: usize = 6; 25 | 26 | /// Ethernet Header (unit: octet) 27 | /// [ Preamble: 7 | SDF: 1 | Dst MAC: 6 | Src MAC: 6 | EtherType: 2 | Payload: to 1500 | FCS: 4 ] 28 | /// SFD: start frame delimiter / FCS: frame check sequence (32bit-CRC) 29 | /// 30 | /// EtherType in Ethernet II: 31 | /// 0x0800: IPv4 | 0x0806: ARP | 0x86DD: IPv6 32 | /// 33 | /// MAC Address 34 | /// [ OUI: 3 | Product ID: 3 ] 35 | /// b0: 0: unicast | 1: broadcast 36 | /// b1: 0: global address | 1: local address 37 | #[repr(packed)] 38 | pub struct EthernetHeader { 39 | pub dst: [u8; ETH_ADDR_LEN], // destination MAC: 6 octets 40 | pub src: [u8; ETH_ADDR_LEN], // source MAC: 6 octets 41 | pub eth_type: u16, // ethernet type : 2 octets IEEE 802.3 42 | } 43 | 44 | pub fn open(device: &mut NetDevice) -> Result<(), ()> { 45 | match device.driver_type.as_ref().unwrap() { 46 | DriverType::Tap => { 47 | tap::open(device); 48 | } 49 | DriverType::Pcap => {} 50 | } 51 | Ok(()) 52 | } 53 | 54 | pub fn read_data(device: &mut NetDevice) -> Option<(ProtocolType, Vec, usize)> { 55 | let (len, buf) = match device.driver_type.as_ref().unwrap() { 56 | DriverType::Tap => tap::read_data(device), 57 | DriverType::Pcap => pcap::read_data(device), 58 | }; 59 | 60 | let hdr_len = size_of::(); 61 | if len < hdr_len { 62 | panic!("Ethernet: data is smaller than eth header.") 63 | } 64 | 65 | let hdr = unsafe { bytes_to_struct::(&buf) }; 66 | 67 | // Check if address matches with this device. 68 | if device.address[..ETH_ADDR_LEN] != hdr.dst[..ETH_ADDR_LEN] 69 | && ETH_ADDR_BROADCAST != hdr.dst[..ETH_ADDR_LEN] 70 | { 71 | debug!("Ethernet: not my route."); 72 | return None; 73 | } 74 | 75 | trace!( 76 | "Ethernet: input buffer = {:?} bytes data = {:02x?}", 77 | len, 78 | &buf[..len] 79 | ); 80 | 81 | let eth_type = be_to_le_u16(hdr.eth_type); 82 | let data = (&buf[hdr_len..len]).to_vec(); 83 | let data_len = len - hdr_len; 84 | 85 | trace!( 86 | "Ethernet: device addr: {:x?} Eth header destination: {:x?} Eth header source: {:x?} Eth type: {:x?}", 87 | device.address, 88 | hdr.dst, 89 | hdr.src, 90 | eth_type 91 | ); 92 | 93 | Some((ProtocolType::from_u16(eth_type), data, data_len)) 94 | } 95 | 96 | pub fn transmit( 97 | device: &mut NetDevice, 98 | ether_type: ProtocolType, 99 | data: Vec, 100 | len: usize, 101 | dst: [u8; ETH_ADDR_LEN], 102 | ) -> Result<(), ()> { 103 | let src_address: [u8; 6] = device.address[..ETH_ADDR_LEN] 104 | .try_into() 105 | .expect("Ethernet: device address size error."); 106 | 107 | let hdr = EthernetHeader { 108 | dst, 109 | src: src_address, 110 | eth_type: le_to_be_u16(ether_type as u16), 111 | }; 112 | let hdr_bytes = unsafe { to_u8_slice::(&hdr) }; 113 | 114 | let mut frame: [u8; ETH_FRAME_MAX] = [0; ETH_FRAME_MAX]; 115 | let mut pad_len: usize = 0; 116 | let data_len = data.len(); 117 | let hdr_len = hdr_bytes.len(); 118 | 119 | frame[..hdr_len].copy_from_slice(hdr_bytes); 120 | frame[hdr_len..(hdr_len + data_len)].copy_from_slice(&data[..]); 121 | 122 | if data_len < ETH_PAYLOAD_MIN { 123 | pad_len = ETH_PAYLOAD_MIN - data_len; 124 | } 125 | let frame_len = hdr_len + data_len + pad_len; 126 | 127 | trace!( 128 | "Ethernet: transmit frame length: {frame_len} (data: {len} + header: {hdr_len} + pad: {pad_len}) | bytes: {:02x?}", 129 | &frame[..frame_len] 130 | ); 131 | 132 | match device.driver_type.as_ref().unwrap() { 133 | DriverType::Tap => tap::write_data(device, &frame[..frame_len]), 134 | DriverType::Pcap => Ok(()), 135 | } 136 | } 137 | 138 | pub fn init(i: u8, driver_type: DriverType) -> NetDevice { 139 | let irq_entry = IRQEntry::new(IRQ_ETHERNET, 0); 140 | let mut device = NetDevice::new( 141 | i, 142 | NetDeviceType::Ethernet, 143 | String::from("tap0"), 144 | ETH_PAYLOAD_MAX, 145 | DEVICE_FLAG_BROADCAST | DEVICE_FLAG_NEED_ARP, 146 | ETH_HDR_SIZE as u16, 147 | ETH_ADDR_LEN as u16, 148 | [0; NET_DEVICE_ADDR_LEN], 149 | [0xff; NET_DEVICE_ADDR_LEN], 150 | irq_entry, 151 | ); 152 | device.driver_type = Some(driver_type); 153 | device 154 | } 155 | -------------------------------------------------------------------------------- /src/devices/loopback.rs: -------------------------------------------------------------------------------- 1 | use super::{NetDevice, NetDeviceType, IRQ_FLAG_SHARED, NET_DEVICE_ADDR_LEN}; 2 | use crate::{interrupt, protocols::ProtocolType}; 3 | use log::info; 4 | use signal_hook::low_level::raise; 5 | use std::sync::Arc; 6 | 7 | pub const IRQ_LOOPBACK: i32 = interrupt::INTR_IRQ_BASE + 5; 8 | const LOOPBACK_MTU: usize = u16::MAX as usize; 9 | 10 | pub fn open(_device: &mut NetDevice) -> Result<(), ()> { 11 | Ok(()) 12 | } 13 | 14 | pub fn read_data(device: &NetDevice) -> Option<(ProtocolType, Vec, usize)> { 15 | let data = device.irq_entry.custom_data.as_ref().unwrap(); 16 | Some((ProtocolType::IP, data.clone().as_ref().to_vec(), data.len())) 17 | } 18 | 19 | pub fn transmit(device: &mut NetDevice, data: Vec) -> Result<(), ()> { 20 | info!("Loopback: transmitting data through loopback device...\n"); 21 | device.irq_entry.custom_data = Some(Arc::new(data)); 22 | raise(IRQ_LOOPBACK).unwrap(); 23 | Ok(()) 24 | } 25 | 26 | pub fn init(i: u8) -> NetDevice { 27 | let irq_entry = interrupt::IRQEntry::new(IRQ_LOOPBACK, IRQ_FLAG_SHARED); 28 | NetDevice::new( 29 | i, 30 | NetDeviceType::Loopback, 31 | String::from("lo"), 32 | LOOPBACK_MTU, 33 | super::DEVICE_FLAG_LOOPBACK, 34 | 0, 35 | 0, 36 | [0; NET_DEVICE_ADDR_LEN], 37 | [0; NET_DEVICE_ADDR_LEN], 38 | irq_entry, 39 | ) 40 | } 41 | -------------------------------------------------------------------------------- /src/devices/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ethernet; 2 | pub mod loopback; 3 | 4 | use crate::{ 5 | drivers::{DriverData, DriverType}, 6 | interrupt, 7 | net::NetInterfaceFamily, 8 | protocols::{ip::IPInterface, NetProtocols, ProtocolData, ProtocolType}, 9 | utils::list::List, 10 | }; 11 | use log::{debug, info}; 12 | use signal_hook::{consts::SIGUSR1, low_level::raise}; 13 | use std::sync::Arc; 14 | 15 | use self::ethernet::ETH_ADDR_LEN; 16 | 17 | const DEVICE_FLAG_UP: u16 = 0x0001; 18 | pub const DEVICE_FLAG_LOOPBACK: u16 = 0x0010; 19 | pub const DEVICE_FLAG_BROADCAST: u16 = 0x0020; 20 | pub const DEVICE_FLAG_P2P: u16 = 0x0040; 21 | pub const DEVICE_FLAG_NEED_ARP: u16 = 0x0100; 22 | 23 | pub const IRQ_FLAG_SHARED: u8 = 0x0001; 24 | pub const NET_DEVICE_ADDR_LEN: usize = 14; 25 | 26 | #[derive(Debug, PartialEq)] 27 | pub enum NetDeviceType { 28 | Loopback, 29 | Ethernet, 30 | } 31 | 32 | pub struct NetDevice { 33 | index: u8, 34 | pub device_type: NetDeviceType, 35 | pub name: String, 36 | pub mtu: usize, 37 | pub flags: u16, 38 | pub header_len: u16, 39 | pub address_len: u16, 40 | pub address: [u8; NET_DEVICE_ADDR_LEN], 41 | pub broadcast: [u8; NET_DEVICE_ADDR_LEN], 42 | pub irq_entry: interrupt::IRQEntry, 43 | pub interfaces: List>, 44 | pub driver_type: Option, 45 | pub driver_data: Option, 46 | } 47 | 48 | impl NetDevice { 49 | pub fn new( 50 | i: u8, 51 | device_type: NetDeviceType, 52 | name: String, 53 | mtu: usize, 54 | flags: u16, 55 | header_len: u16, 56 | address_len: u16, 57 | address: [u8; NET_DEVICE_ADDR_LEN], 58 | broadcast: [u8; NET_DEVICE_ADDR_LEN], 59 | irq_entry: interrupt::IRQEntry, 60 | ) -> NetDevice { 61 | NetDevice { 62 | index: i, 63 | device_type, 64 | name, 65 | mtu, 66 | flags, 67 | header_len, 68 | address_len, 69 | address, 70 | broadcast, 71 | irq_entry, 72 | interfaces: List::>::new(), 73 | driver_type: None, 74 | driver_data: None, 75 | } 76 | } 77 | 78 | pub fn register_interface(&mut self, interface: Arc) { 79 | info!( 80 | "Device: registering {:?} interface on device: {}\n", 81 | interface.interface.family, self.name 82 | ); 83 | // TODO: check duplicate inteface family type (IP or IPv6) 84 | self.interfaces.push(interface); 85 | } 86 | 87 | pub fn get_interface(&self, family: NetInterfaceFamily) -> Option> { 88 | for ip_iface in self.interfaces.iter() { 89 | if ip_iface.interface.family == family { 90 | return Some(ip_iface.clone()); 91 | } 92 | } 93 | None 94 | } 95 | 96 | fn is_open(&self) -> bool { 97 | self.flags & DEVICE_FLAG_UP > 0 98 | } 99 | 100 | pub fn open(&mut self) -> Result<(), ()> { 101 | self.flags |= DEVICE_FLAG_UP; 102 | match self.device_type { 103 | NetDeviceType::Loopback => loopback::open(self), 104 | NetDeviceType::Ethernet => ethernet::open(self), 105 | } 106 | } 107 | 108 | pub fn close(&self) -> Result<(), &str> { 109 | match self.device_type { 110 | NetDeviceType::Loopback => Ok(()), 111 | NetDeviceType::Ethernet => Ok(()), 112 | } 113 | } 114 | 115 | /// Sends data to a device. 116 | pub fn transmit( 117 | &mut self, 118 | proto_type: ProtocolType, 119 | data: Vec, 120 | len: usize, 121 | dst: [u8; ETH_ADDR_LEN], 122 | ) -> Result<(), ()> { 123 | if !self.is_open() { 124 | panic!("Device: device is not open.") 125 | } 126 | match self.device_type { 127 | NetDeviceType::Loopback => loopback::transmit(self, data), 128 | NetDeviceType::Ethernet => ethernet::transmit(self, proto_type, data, len, dst), 129 | } 130 | } 131 | 132 | /// ISR (interrupt service routine) for registered IRQs. Handles inputs and raises SIGUSR1. 133 | pub fn isr(&mut self, irq: i32, protocols: &mut NetProtocols) { 134 | let incoming_data = match self.device_type { 135 | NetDeviceType::Loopback => loopback::read_data(self), 136 | NetDeviceType::Ethernet => ethernet::read_data(self), 137 | }; 138 | 139 | if incoming_data.is_none() { 140 | debug!("Device: ISR called but no data."); 141 | return; 142 | } 143 | 144 | let (proto_type, data, len) = incoming_data.unwrap(); 145 | for protocol in protocols.entries.iter_mut() { 146 | if protocol.protocol_type == proto_type { 147 | let data_entry: ProtocolData = ProtocolData::new(irq, Some(Arc::new(data)), len); 148 | protocol.input_head.push_back(data_entry); 149 | break; 150 | } 151 | } 152 | 153 | debug!( 154 | "Device: ISR done: received protocol type: {:x?}", 155 | proto_type 156 | ); 157 | raise(SIGUSR1).unwrap(); 158 | } 159 | } 160 | 161 | pub struct NetDevices { 162 | pub entries: List, 163 | } 164 | 165 | impl NetDevices { 166 | pub fn new() -> NetDevices { 167 | NetDevices { 168 | entries: List::::new(), 169 | } 170 | } 171 | 172 | pub fn register(&mut self, device: NetDevice) { 173 | self.entries.push(device); 174 | } 175 | 176 | pub fn handle_irq(&mut self, irq: i32, protocols: &mut NetProtocols) { 177 | for device in self.entries.iter_mut() { 178 | if device.irq_entry.irq == irq { 179 | device.isr(irq, protocols); 180 | } 181 | } 182 | } 183 | 184 | pub fn get_mut_by_type(&mut self, device_type: NetDeviceType) -> Option<&mut NetDevice> { 185 | for device in self.entries.iter_mut() { 186 | if device.device_type == device_type { 187 | return Some(device); 188 | } 189 | } 190 | None 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /src/drivers/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod pcap; 2 | pub mod tap; 3 | 4 | use std::fs::File; 5 | 6 | #[derive(Debug)] 7 | pub enum DriverType { 8 | Tap, 9 | Pcap, 10 | } 11 | 12 | #[derive(Debug)] 13 | pub struct DriverData { 14 | // pub fd: i32, 15 | pub file: File, 16 | irq: i32, 17 | } 18 | 19 | impl DriverData { 20 | pub fn new(file: File, irq: i32) -> DriverData { 21 | DriverData { file, irq } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/drivers/pcap.rs: -------------------------------------------------------------------------------- 1 | use crate::devices::{ethernet::ETH_FRAME_MAX, NetDevice}; 2 | 3 | pub fn read_data(device: &NetDevice) -> (usize, [u8; ETH_FRAME_MAX]) { 4 | (0, [0; ETH_FRAME_MAX]) 5 | } 6 | -------------------------------------------------------------------------------- /src/drivers/tap.rs: -------------------------------------------------------------------------------- 1 | use super::DriverData; 2 | use crate::{ 3 | devices::{ 4 | ethernet::{ETH_ADDR_ANY, ETH_FRAME_MAX}, 5 | NetDevice, NET_DEVICE_ADDR_LEN, 6 | }, 7 | interrupt::INTR_IRQ_BASE, 8 | }; 9 | use core::slice; 10 | use ifstructs::ifreq; 11 | use ioctl::*; 12 | use log::{error, info}; 13 | use nix::{ 14 | libc::{c_int, fcntl, F_SETFL, F_SETOWN, IFF_NO_PI, IFF_TAP, O_ASYNC, SIOCGIFHWADDR}, 15 | sys::socket::{socket, AddressFamily, SockFlag, SockType}, 16 | }; 17 | use std::io::{self, Read, Write}; 18 | use std::{fs::OpenOptions, os::unix::prelude::AsRawFd, process}; 19 | 20 | const TUN_PATH: &str = "/dev/net/tun"; 21 | const TUN_IOC_MAGIC: u8 = b'T'; 22 | const TUN_IOC_SET_IFF: u8 = 202; 23 | 24 | const F_SETSIG: c_int = 10; // not defined in nix crate 25 | const AF_INET_RAW: u16 = 2; 26 | 27 | // const SOCK_IOC_TYPE: u8 = 0x89; // uapi/linux/sockios.h 28 | 29 | const ETH_TAP_IRQ: i32 = INTR_IRQ_BASE + 2; 30 | 31 | // Network device allocation (registers a device on kernel) 32 | ioctl!(write tun_set_iff with TUN_IOC_MAGIC, TUN_IOC_SET_IFF; c_int); 33 | 34 | // Hardware address retrieval 35 | ioctl!(bad read get_hw_addr with SIOCGIFHWADDR; ifreq); 36 | 37 | fn set_tap_address(device: &mut NetDevice) { 38 | let soc = socket( 39 | AddressFamily::Inet, 40 | SockType::Datagram, 41 | SockFlag::empty(), 42 | None, 43 | ) 44 | .unwrap(); 45 | 46 | let mut ifr = ifreq::from_name(&device.name).unwrap(); 47 | ifr.ifr_ifru.ifr_addr.sa_family = AF_INET_RAW; 48 | 49 | unsafe { 50 | if get_hw_addr(soc, &mut ifr) < 0 { 51 | let err = io::Error::last_os_error(); 52 | panic!("TAP: get IF HW Addr failed: {err}"); 53 | } 54 | 55 | let hw_addr_u8 = slice::from_raw_parts( 56 | ifr.ifr_ifru.ifr_hwaddr.sa_data.as_ptr() as *const u8, 57 | NET_DEVICE_ADDR_LEN, 58 | ); 59 | 60 | let name = ifr.get_name().unwrap(); 61 | info!("TAP: retrieved HW Address for {name}: {:x?}", hw_addr_u8); 62 | 63 | device.address.copy_from_slice(hw_addr_u8); 64 | } 65 | } 66 | 67 | pub fn open(device: &mut NetDevice) { 68 | let file = OpenOptions::new() 69 | .read(true) 70 | .write(true) 71 | .open(TUN_PATH) 72 | .unwrap(); 73 | let fd = file.as_raw_fd(); 74 | 75 | let mut ifr = ifreq::from_name(&device.name).unwrap(); 76 | let ifr_flag = IFF_TAP | IFF_NO_PI; // TAP device and do not provide packet info 77 | ifr.set_flags(ifr_flag as i16); 78 | 79 | unsafe { 80 | // TAP device allocation 81 | if tun_set_iff(fd, &mut ifr as *mut _ as *mut _) < 0 { 82 | let err = io::Error::last_os_error(); 83 | panic!("TAP: TUN set IFF failed: {err}"); 84 | } 85 | 86 | // Signal settings for a file descriptor of TAP 87 | // https://man7.org/linux/man-pages/man2/fcntl.2.html 88 | 89 | // SIGIO & SIGURG fd signals to self process id 90 | let mut res = fcntl(fd, F_SETOWN, process::id()); 91 | if res == -1 { 92 | panic!("TAP: F_SETOWN failed."); 93 | } 94 | // Signal enablement 95 | res = fcntl(fd, F_SETFL, O_ASYNC); 96 | if res == -1 { 97 | panic!("TAP: F_SETFL failed."); 98 | } 99 | // Custom signal instead of SIGIO 100 | res = fcntl(fd, F_SETSIG, device.irq_entry.irq); 101 | if res == -1 { 102 | panic!("TAP: F_SETSIG failed."); 103 | } 104 | if device.address[..6] == ETH_ADDR_ANY { 105 | set_tap_address(device); 106 | } 107 | }; 108 | device.driver_data = Some(DriverData::new(file, ETH_TAP_IRQ)) 109 | } 110 | 111 | pub fn read_data(device: &mut NetDevice) -> (usize, [u8; ETH_FRAME_MAX]) { 112 | let driver_data = device.driver_data.as_mut().unwrap(); 113 | 114 | let mut buf: [u8; ETH_FRAME_MAX] = [0; ETH_FRAME_MAX]; 115 | let res = driver_data.file.read(&mut buf); 116 | let s = res.unwrap(); 117 | (s, buf) 118 | } 119 | 120 | pub fn write_data(device: &mut NetDevice, data: &[u8]) -> Result<(), ()> { 121 | let result = device.driver_data.as_mut().unwrap().file.write(data); 122 | if let Err(e) = result { 123 | error!("TAP: write data failed: {e}"); 124 | } 125 | Ok(()) 126 | } 127 | -------------------------------------------------------------------------------- /src/interrupt.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | pub const INTR_IRQ_BASE: i32 = 35; // SIGRTMIN: 34 & SIGRTMAX: 64 4 | 5 | #[derive(Debug)] 6 | pub struct IRQEntry { 7 | pub irq: i32, 8 | flags: u8, 9 | next: Option>, 10 | pub custom_data: Option>>, 11 | } 12 | 13 | impl<'a> IRQEntry { 14 | pub fn new(irq: i32, flags: u8) -> IRQEntry { 15 | IRQEntry { 16 | irq, 17 | flags, 18 | next: None, 19 | custom_data: None, 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod app; 2 | mod devices; 3 | mod drivers; 4 | mod interrupt; 5 | mod net; 6 | mod protocols; 7 | mod utils; 8 | 9 | use crate::app::NetApp; 10 | use crate::devices::ethernet::IRQ_ETHERNET; 11 | use crate::devices::loopback::IRQ_LOOPBACK; 12 | use log::debug; 13 | use log::info; 14 | use signal_hook::consts::signal::*; 15 | use signal_hook::consts::TERM_SIGNALS; 16 | use signal_hook::iterator::exfiltrator::origin::WithOrigin; 17 | use signal_hook::iterator::SignalsInfo; 18 | use simplelog::Config; 19 | use simplelog::SimpleLogger; 20 | use std::io::Error; 21 | use std::sync::mpsc; 22 | 23 | fn main() -> Result<(), Error> { 24 | // Signal setup 25 | let mut sigs = vec![SIGHUP, SIGUSR1, IRQ_LOOPBACK, IRQ_ETHERNET]; 26 | sigs.extend(TERM_SIGNALS); 27 | let mut signals = SignalsInfo::::new(&sigs)?; 28 | 29 | // Log setup 30 | SimpleLogger::init(log::LevelFilter::Info, Config::default()).unwrap(); 31 | 32 | let (app_sender, app_receiver) = mpsc::channel(); 33 | let (tcp_sender, tcp_receiver) = mpsc::channel(); 34 | 35 | // Protocol stack start 36 | let mut app = NetApp::new(); 37 | let app_join = app.run(app_receiver); 38 | let tcp_join = app.tcp_transmit_thread(tcp_receiver); 39 | 40 | // Interrupt thread 41 | info!("App: starting signal receiver thread..."); 42 | for info in &mut signals { 43 | debug!("App: ----Signal Received {:?}----\n", info); 44 | match info.signal { 45 | SIGHUP => {} 46 | SIGUSR1 => { 47 | app.handle_protocol(); 48 | } 49 | sig => { 50 | if TERM_SIGNALS.contains(&sig) { 51 | info!("App: terminating..."); 52 | break; 53 | } 54 | app.handle_irq(sig); 55 | } 56 | } 57 | } 58 | info!("App: closing app/TCP retransmission thread..."); 59 | app_sender.send(()).unwrap(); 60 | tcp_sender.send(()).unwrap(); 61 | app.close_sockets(); 62 | app_join.join().unwrap(); 63 | tcp_join.join().unwrap(); 64 | info!("App: closed app/TCP retransmission thread."); 65 | Ok(()) 66 | } 67 | -------------------------------------------------------------------------------- /src/net.rs: -------------------------------------------------------------------------------- 1 | #[derive(PartialEq, Debug)] 2 | pub enum NetInterfaceFamily { 3 | IP, 4 | IPV6, 5 | } 6 | 7 | #[derive(Debug)] 8 | pub struct NetInterface { 9 | pub family: NetInterfaceFamily, 10 | pub next: Option>, 11 | } 12 | -------------------------------------------------------------------------------- /src/protocols/arp.rs: -------------------------------------------------------------------------------- 1 | use super::ip::{IPAdress, IPInterface, IP_ADDR_LEN}; 2 | use super::{ProtocolContexts, ProtocolType}; 3 | use crate::protocols::ip::ip_addr_to_str; 4 | use crate::{ 5 | devices::{ethernet::ETH_ADDR_LEN, NetDevice, NetDeviceType}, 6 | net::NetInterfaceFamily, 7 | utils::byte::{be_to_le_u16, le_to_be_u16}, 8 | utils::{bytes_to_struct, to_u8_slice}, 9 | }; 10 | use log::{debug, error, info, trace, warn}; 11 | use std::{collections::HashMap, convert::TryInto, sync::Arc, time::SystemTime}; 12 | 13 | const ARP_HW_SPACE_ETHER: u16 = 0x0001; 14 | const ARP_PROTO_SPACE_IP: u16 = 0x0800; 15 | const ARP_OP_REQUEST: u16 = 0x0001; 16 | const ARP_OP_REPLY: u16 = 0x0002; 17 | 18 | const ARP_CACHE_TIMEOUT_SECS: u64 = 60 * 60 * 4; // timeout: 4hr 19 | 20 | #[derive(PartialEq, Eq, Hash)] 21 | enum ArpTableEntryState { 22 | Incomplete, 23 | Resolved, 24 | Static, 25 | } 26 | 27 | #[derive(PartialEq, Eq, Hash)] 28 | pub struct ArpTableEntry { 29 | state: ArpTableEntryState, 30 | proto_address: IPAdress, 31 | hw_address: [u8; ETH_ADDR_LEN], 32 | timestamp: SystemTime, 33 | } 34 | 35 | pub struct ArpTable { 36 | entries: HashMap, 37 | } 38 | 39 | impl ArpTable { 40 | pub fn new() -> ArpTable { 41 | ArpTable { 42 | entries: HashMap::::new(), 43 | } 44 | } 45 | 46 | pub fn get(&mut self, ip: IPAdress) -> Option<[u8; 6]> { 47 | let map_entry = self.entries.get(&ip); 48 | if let Some(entry) = map_entry { 49 | let dur = entry.timestamp.elapsed().unwrap(); 50 | if dur.as_secs() > ARP_CACHE_TIMEOUT_SECS { 51 | self.entries.remove(&ip); 52 | return None; 53 | } else { 54 | return Some(entry.hw_address); 55 | } 56 | } 57 | None 58 | } 59 | 60 | pub fn update(&mut self, ip: IPAdress, resolved: [u8; ETH_ADDR_LEN]) { 61 | let map_entry = self.entries.get(&ip); 62 | if let Some(_entry) = map_entry { 63 | self.entries.remove(&ip); 64 | } 65 | self.entries.insert( 66 | ip, 67 | ArpTableEntry { 68 | state: ArpTableEntryState::Resolved, 69 | proto_address: ip, 70 | hw_address: resolved, 71 | timestamp: SystemTime::now(), 72 | }, 73 | ); 74 | } 75 | } 76 | 77 | #[repr(packed)] 78 | struct ArpHeader { 79 | hw_addr_space: u16, // Hardware address space: 0x0001 for Ethernet 80 | proto_addr_space: u16, // Protocol address space: 0x0800 for IP 81 | hw_addr_len: u8, // Hardware address length: Ethernet address size 82 | proto_addr_len: u8, // Protocol address length: IP address size 83 | op: u16, // Operation code: REQUEST or REPLY 84 | } 85 | 86 | #[repr(packed)] 87 | struct ArpMessage { 88 | header: ArpHeader, 89 | sender_hw_addr: [u8; ETH_ADDR_LEN], 90 | sender_proto_addr: [u8; IP_ADDR_LEN], 91 | target_hw_addr: [u8; ETH_ADDR_LEN], 92 | target_proto_addr: [u8; IP_ADDR_LEN], 93 | } 94 | 95 | pub fn arp_request( 96 | device: &mut NetDevice, 97 | interface: Arc, 98 | target_ip: IPAdress, 99 | ) -> Result<(), ()> { 100 | let request_header = ArpHeader { 101 | hw_addr_space: le_to_be_u16(ARP_HW_SPACE_ETHER), 102 | hw_addr_len: ETH_ADDR_LEN as u8, 103 | proto_addr_space: le_to_be_u16(ARP_PROTO_SPACE_IP), 104 | proto_addr_len: IP_ADDR_LEN as u8, 105 | op: le_to_be_u16(ARP_OP_REQUEST), 106 | }; 107 | let request_msg = ArpMessage { 108 | header: request_header, 109 | sender_hw_addr: device.address[..6] 110 | .try_into() 111 | .expect("ARP: request failure with sender hw address."), 112 | sender_proto_addr: interface.unicast.to_le_bytes(), 113 | target_hw_addr: [0; 6], 114 | target_proto_addr: target_ip.to_le_bytes(), 115 | }; 116 | let data = unsafe { to_u8_slice::(&request_msg) }; 117 | let ip_str = ip_addr_to_str(target_ip); 118 | info!("ARP: sending ARP request for IP: {ip_str}"); 119 | trace!("ARP: data = {:x?}", data); 120 | device.transmit( 121 | ProtocolType::Arp, 122 | data.to_vec(), 123 | data.len(), 124 | device.broadcast[..6] 125 | .try_into() 126 | .expect("ARP: reply failure with broadcast address."), 127 | ) 128 | } 129 | 130 | pub fn arp_reply( 131 | device: &mut NetDevice, 132 | interface: Arc, 133 | target_hw_addr: [u8; ETH_ADDR_LEN], 134 | target_ip: IPAdress, 135 | destination_hw_addr: [u8; ETH_ADDR_LEN], 136 | ) -> Result<(), ()> { 137 | let reply_header = ArpHeader { 138 | hw_addr_space: le_to_be_u16(ARP_HW_SPACE_ETHER), 139 | hw_addr_len: ETH_ADDR_LEN as u8, 140 | proto_addr_space: le_to_be_u16(ARP_PROTO_SPACE_IP), 141 | proto_addr_len: IP_ADDR_LEN as u8, 142 | op: le_to_be_u16(ARP_OP_REPLY), 143 | }; 144 | 145 | let reply_msg = ArpMessage { 146 | header: reply_header, 147 | sender_hw_addr: device.address[..6] 148 | .try_into() 149 | .expect("ARP: reply failure with sender hw address."), 150 | sender_proto_addr: interface.unicast.to_le_bytes(), 151 | target_hw_addr, 152 | target_proto_addr: target_ip.to_le_bytes(), 153 | }; 154 | 155 | let data = unsafe { to_u8_slice::(&reply_msg) }; 156 | let ip_str = ip_addr_to_str(target_ip); 157 | info!("ARP: sending ARP reply to IP: {ip_str}"); 158 | trace!("ARP: data = {:x?}", data); 159 | device.transmit( 160 | ProtocolType::Arp, 161 | data.to_vec(), 162 | data.len(), 163 | destination_hw_addr, 164 | ) 165 | } 166 | 167 | pub fn input( 168 | data: &[u8], 169 | _len: usize, 170 | device: &mut NetDevice, 171 | contexts: &mut ProtocolContexts, 172 | ) -> Result<(), ()> { 173 | let msg = unsafe { bytes_to_struct::(data) }; 174 | 175 | if be_to_le_u16(msg.header.hw_addr_space) != ARP_HW_SPACE_ETHER 176 | || msg.header.hw_addr_len as usize != ETH_ADDR_LEN 177 | { 178 | let hw_addr_spc = msg.header.hw_addr_space; 179 | error!( 180 | "ARP: unexpected values. HW address space: {:x?} and HW address length: {:x?}", 181 | hw_addr_spc, msg.header.hw_addr_len 182 | ); 183 | return Err(()); 184 | } 185 | if be_to_le_u16(msg.header.proto_addr_space) != ARP_PROTO_SPACE_IP 186 | || msg.header.proto_addr_len as usize != IP_ADDR_LEN 187 | { 188 | let proto_addr_spc = msg.header.proto_addr_space; 189 | error!( 190 | "ARP: unexpected values. Protocol address space: {:x?} and Protocol address length: {:x?}", 191 | proto_addr_spc, msg.header.proto_addr_len 192 | ); 193 | 194 | return Err(()); 195 | } 196 | 197 | let target_ip = unsafe { bytes_to_struct::(&msg.target_proto_addr) }; 198 | let interface = device.get_interface(NetInterfaceFamily::IP).unwrap(); 199 | if interface.unicast != target_ip { 200 | warn!( 201 | "ARP: input target IP = {:?} not matching with interface unicast IP: {:?}", 202 | ip_addr_to_str(target_ip), 203 | ip_addr_to_str(interface.unicast) 204 | ); 205 | } else { 206 | // Update or insert ARP Table with sender addresses 207 | let sender_ip = unsafe { bytes_to_struct::(&msg.sender_proto_addr) }; 208 | contexts.arp_table.update(sender_ip, msg.sender_hw_addr); 209 | let ip_str = ip_addr_to_str(sender_ip); 210 | 211 | info!( 212 | "ARP: received ARP response for IP = {ip_str} HW Addr is {:x?}", 213 | msg.sender_hw_addr 214 | ); 215 | 216 | // Reply in case of ARP Request 217 | if be_to_le_u16(msg.header.op) == ARP_OP_REQUEST { 218 | let sender_ip = unsafe { bytes_to_struct::(&msg.sender_proto_addr) }; 219 | info!("ARP: replying ARP..."); 220 | return arp_reply( 221 | device, 222 | interface, 223 | msg.sender_hw_addr, 224 | sender_ip, 225 | msg.sender_hw_addr, 226 | ); 227 | } 228 | } 229 | 230 | Ok(()) 231 | } 232 | 233 | pub fn arp_resolve( 234 | device: &mut NetDevice, 235 | interface: Arc, 236 | arp_table: &mut ArpTable, 237 | target_ip: IPAdress, 238 | ) -> Result, ()> { 239 | if device.device_type != NetDeviceType::Ethernet { 240 | return Err(()); 241 | } 242 | // TODO: Check interface family to be IP 243 | if let Some(hw_addr) = arp_table.get(target_ip) { 244 | let ip_str = ip_addr_to_str(target_ip); 245 | debug!("ARP: resolved for IP = {ip_str} HW Addr is {:x?}", hw_addr); 246 | Ok(Some(hw_addr)) 247 | } else if arp_request(device, interface, target_ip).is_ok() { 248 | Ok(None) 249 | } else { 250 | Err(()) 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /src/protocols/ip/icmp.rs: -------------------------------------------------------------------------------- 1 | use super::{IPAdress, IPInterface, IPProtocolType}; 2 | use crate::{ 3 | devices::NetDevice, 4 | protocols::ip::{ControlBlocks, ProtocolContexts}, 5 | utils::{bytes_to_struct, cksum16, to_u8_slice}, 6 | }; 7 | use log::{error, info}; 8 | use std::mem::size_of; 9 | 10 | const ICMP_TYPE_ECHOREPLY: u8 = 0; 11 | const ICMP_TYPE_ECHO: u8 = 8; 12 | 13 | // const ICMP_TYPE_DEST_UNREACH: u8 = 3; 14 | // const ICMP_TYPE_SOURCE_QUENCH: u8 = 4; 15 | // const ICMP_TYPE_REDIRECT: u8 = 5; 16 | // const ICMP_TYPE_TIME_EXCEEDED: u8 = 11; 17 | // const ICMP_TYPE_PARAM_PROBLEM: u8 = 12; 18 | // const ICMP_TYPE_TIMESTAMP: u8 = 13; 19 | // const ICMP_TYPE_TIMESTAMPREPLY: u8 = 14; 20 | // const ICMP_TYPE_INFO_REQUEST: u8 = 15; 21 | // const ICMP_TYPE_INFO_REPLY: u8 = 16; 22 | 23 | // // UNREACH 24 | // const ICMP_CODE_NET_UNREACH: u8 = 0; 25 | // const ICMP_CODE_HOST_UNREACH: u8 = 1; 26 | // const ICMP_CODE_PROTO_UNREACH: u8 = 2; 27 | // const ICMP_CODE_PORT_UNREACH: u8 = 3; 28 | // const ICMP_CODE_FRAGMENT_NEEDED: u8 = 4; 29 | // const ICMP_CODE_SOURCE_ROUTE_FAILED: u8 = 5; 30 | 31 | // // REDIRECT 32 | // const ICMP_CODE_REDIRECT_NET: u8 = 0; 33 | // const ICMP_CODE_REDIRECT_HOST: u8 = 1; 34 | // const ICMP_CODE_REDIRECT_TOS_NET: u8 = 2; 35 | // const ICMP_CODE_REDIRECT_TOS_HOST: u8 = 3; 36 | 37 | // // TIME_EXEEDED 38 | // const ICMP_CODE_EXCEEDED_TTL: u8 = 0; 39 | // const ICMP_CODE_EXCEEDED_FRAGMENT: u8 = 1; 40 | 41 | #[repr(packed)] 42 | pub struct ICMPHeader { 43 | icmp_type: u8, 44 | code: u8, 45 | check_sum: u16, 46 | values: u32, 47 | } 48 | 49 | // pub struct ICMPEcho { 50 | // icmp_type: u8, 51 | // code: u8, 52 | // check_sum: u16, 53 | // id: u16, 54 | // seq: u16, 55 | // } 56 | 57 | pub fn input( 58 | data: &[u8], 59 | len: usize, 60 | src: IPAdress, 61 | mut dst: IPAdress, 62 | device: &mut NetDevice, 63 | iface: &IPInterface, 64 | contexts: &mut ProtocolContexts, 65 | pcbs: &mut ControlBlocks, 66 | ) -> Result<(), ()> { 67 | let icmp_hdr_size = size_of::(); 68 | let hdr = unsafe { bytes_to_struct::(data) }; 69 | 70 | info!("ICMP: input type = {:x?}", hdr.icmp_type); 71 | 72 | let sum = cksum16(data, len, 0); 73 | if sum != 0 { 74 | error!("ICMP: checksum failed: {sum}"); 75 | return Err(()); 76 | } 77 | 78 | if hdr.icmp_type == ICMP_TYPE_ECHO { 79 | let icmp_data = data[icmp_hdr_size..].to_vec(); 80 | if dst != iface.unicast { 81 | // change original destination when addressed to broadcast address 82 | dst = iface.unicast; 83 | } 84 | output( 85 | ICMP_TYPE_ECHOREPLY, 86 | hdr.code, 87 | hdr.values, 88 | icmp_data, 89 | len - icmp_hdr_size, 90 | dst, // src becomes dst for replying 91 | src, // dst becomes src for replying 92 | device, 93 | contexts, 94 | pcbs, 95 | ); 96 | } 97 | Ok(()) 98 | } 99 | 100 | pub fn output( 101 | icmp_type: u8, 102 | code: u8, 103 | values: u32, 104 | mut icmp_data: Vec, 105 | len: usize, 106 | src: IPAdress, 107 | dst: IPAdress, 108 | device: &mut NetDevice, 109 | contexts: &mut ProtocolContexts, 110 | pcbs: &mut ControlBlocks, 111 | ) { 112 | let hlen = size_of::(); 113 | let hdr = ICMPHeader { 114 | icmp_type, 115 | code, 116 | check_sum: 0, 117 | values, 118 | }; 119 | // Add data after header 120 | let header_bytes = unsafe { to_u8_slice::(&hdr) }; 121 | let mut data = header_bytes.to_vec(); 122 | data.append(&mut icmp_data); 123 | 124 | let check_sum = cksum16(&data, hlen + len, 0); 125 | // Update checksum in byte data 126 | data[2] = ((check_sum & 0xff00) >> 8) as u8; 127 | data[3] = (check_sum & 0xff) as u8; 128 | 129 | super::output(IPProtocolType::Icmp, data, src, dst, device, contexts).unwrap(); 130 | } 131 | -------------------------------------------------------------------------------- /src/protocols/ip/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod icmp; 2 | pub mod tcp; 3 | pub mod udp; 4 | 5 | use log::{error, info, trace, warn}; 6 | 7 | use super::arp::arp_resolve; 8 | use super::{ControlBlocks, ProtocolContexts}; 9 | use crate::net::{NetInterface, NetInterfaceFamily}; 10 | use crate::{ 11 | devices::{ethernet::ETH_ADDR_LEN, NetDevice, DEVICE_FLAG_NEED_ARP}, 12 | utils::byte::{be_to_le_u16, be_to_le_u32, le_to_be_u16}, 13 | utils::list::List, 14 | utils::{bytes_to_struct, cksum16, to_u8_slice}, 15 | }; 16 | use std::{ 17 | convert::TryInto, 18 | mem::size_of, 19 | sync::{Arc, Mutex}, 20 | }; 21 | 22 | pub type IPAdress = u32; 23 | 24 | pub const IP_ADDR_LEN: usize = 4; 25 | const IP_MAX_SIZE: usize = u16::MAX as usize; 26 | const IP_HEADER_MIN_SIZE: usize = 20; 27 | const IP_PAYLOAD_MAX_SIZE: usize = IP_MAX_SIZE - IP_HEADER_MIN_SIZE; 28 | 29 | const IP_VERSION_4: u8 = 4; 30 | 31 | const IP_ADDR_ANY: IPAdress = 0x00000000; // 0.0.0.0 32 | const IP_ADDR_BROADCAST: IPAdress = 0xffffffff; // 255.255.255.255 33 | 34 | pub struct IPEndpoint { 35 | pub address: IPAdress, 36 | pub port: u16, 37 | } 38 | 39 | impl IPEndpoint { 40 | pub fn new(addr: IPAdress, port: u16) -> IPEndpoint { 41 | IPEndpoint { 42 | address: addr, 43 | port: le_to_be_u16(port), 44 | } 45 | } 46 | 47 | pub fn new_from_str(addr_str: &str, port: u16) -> IPEndpoint { 48 | IPEndpoint { 49 | address: ip_addr_to_bytes(addr_str).unwrap(), 50 | port: le_to_be_u16(port), 51 | } 52 | } 53 | } 54 | 55 | #[derive(Debug)] 56 | pub struct IPInterface { 57 | pub interface: NetInterface, 58 | pub next: Option>, 59 | pub unicast: IPAdress, 60 | pub netmask: IPAdress, 61 | pub broadcast: IPAdress, 62 | } 63 | 64 | impl IPInterface { 65 | pub fn new(unicast: &str, netmask: &str) -> IPInterface { 66 | let interface = NetInterface { 67 | family: NetInterfaceFamily::IP, 68 | next: None, 69 | }; 70 | let unicast = ip_addr_to_bytes(unicast).unwrap(); 71 | let netmask = ip_addr_to_bytes(netmask).unwrap(); 72 | // unicast & netmask = nw address => nw address | !nestmask (all hosts) = broadcast 73 | let broadcast = (unicast & netmask) | !netmask; 74 | 75 | IPInterface { 76 | interface, 77 | next: None, 78 | unicast, 79 | netmask, 80 | broadcast, 81 | } 82 | } 83 | } 84 | 85 | pub struct IPRoute { 86 | network: IPAdress, 87 | netmask: IPAdress, 88 | next_hop: IPAdress, 89 | pub interface: Arc, 90 | } 91 | 92 | impl IPRoute { 93 | pub fn interface_route(interface: Arc) -> IPRoute { 94 | IPRoute { 95 | network: interface.unicast & interface.netmask, 96 | netmask: interface.netmask, 97 | next_hop: IP_ADDR_ANY, 98 | interface, 99 | } 100 | } 101 | 102 | pub fn gateway_route(gateway_ip: &str, interface: Arc) -> IPRoute { 103 | IPRoute { 104 | network: IP_ADDR_ANY, 105 | netmask: IP_ADDR_ANY, 106 | next_hop: ip_addr_to_bytes(gateway_ip).unwrap(), 107 | interface, 108 | } 109 | } 110 | } 111 | pub struct IPRoutes { 112 | entries: List, 113 | } 114 | 115 | impl IPRoutes { 116 | pub fn new() -> IPRoutes { 117 | IPRoutes { 118 | entries: List::::new(), 119 | } 120 | } 121 | 122 | pub fn register(&mut self, route: IPRoute) { 123 | self.entries.push(route); 124 | } 125 | 126 | pub fn lookup_ip_route(&self, dst: IPAdress) -> Option<&IPRoute> { 127 | let mut candidate = None; 128 | for route in self.entries.iter() { 129 | if (dst & route.netmask) == route.network { 130 | if candidate.is_none() { 131 | candidate = Some(route); 132 | } else { 133 | let candidate_route = candidate.unwrap(); 134 | if be_to_le_u32(candidate_route.netmask) < be_to_le_u32(route.netmask) { 135 | candidate = Some(route); 136 | } 137 | } 138 | } 139 | } 140 | candidate 141 | } 142 | 143 | pub fn get_interface(&self, dst: IPAdress) -> Option> { 144 | let route = self.lookup_ip_route(dst); 145 | route?; 146 | Some(route.unwrap().interface.clone()) 147 | } 148 | } 149 | 150 | // see https://www.iana.org/assignments/protocol-numbers/protocol-numbers.txt 151 | pub enum IPProtocolType { 152 | Icmp = 0x01, 153 | Tcp = 0x06, 154 | Udp = 0x11, 155 | Unknown, 156 | } 157 | 158 | impl IPProtocolType { 159 | pub fn from_u8(value: u8) -> IPProtocolType { 160 | match value { 161 | 0x01 => IPProtocolType::Icmp, 162 | 0x06 => IPProtocolType::Tcp, 163 | 0x11 => IPProtocolType::Udp, 164 | _ => IPProtocolType::Unknown, 165 | } 166 | } 167 | } 168 | 169 | #[repr(packed)] 170 | pub struct IPHeader { 171 | ver_len: u8, // version (4 bits) + IHL (4 bits) 172 | service_type: u8, // | Precedence: 3 | Delay: 1 | Throughput: 1 | Reliability: 1 | Reserved: 2 | 173 | total_len: u16, 174 | id: u16, 175 | offset: u16, // flags: | 0 | Don't fragment: 1 | More fragment: 1 | + fragment offset (13 bits) 176 | ttl: u8, 177 | protocol: u8, 178 | check_sum: u16, 179 | src: IPAdress, 180 | dst: IPAdress, 181 | opts: [u8; 0], 182 | } 183 | 184 | pub struct IPHeaderIdManager { 185 | id_mtx: Mutex, 186 | } 187 | 188 | impl IPHeaderIdManager { 189 | pub fn new() -> IPHeaderIdManager { 190 | IPHeaderIdManager { 191 | id_mtx: Mutex::new(128), 192 | } 193 | } 194 | 195 | pub fn generate_id(&mut self) -> u16 { 196 | let mut id = self.id_mtx.lock().unwrap(); 197 | *id += 1; 198 | *id 199 | } 200 | } 201 | 202 | fn create_ip_header( 203 | ip_proto: IPProtocolType, 204 | src: IPAdress, 205 | dst: IPAdress, 206 | data: &Vec, 207 | id: u16, 208 | ) -> IPHeader { 209 | let hlen = size_of::(); 210 | let len = data.len(); 211 | let total = hlen as u16 + len as u16; 212 | 213 | // TODO: check MTU vs header size + len 214 | 215 | let mut header = IPHeader { 216 | ver_len: (IP_VERSION_4 << 4) | (hlen as u8 >> 2), 217 | service_type: 0, 218 | total_len: le_to_be_u16(total), 219 | id: le_to_be_u16(id), 220 | offset: 0, 221 | ttl: 0xff, 222 | protocol: ip_proto as u8, 223 | check_sum: 0, 224 | src, 225 | dst, 226 | opts: [], 227 | }; 228 | let header_bytes = unsafe { to_u8_slice(&header) }; 229 | header.check_sum = le_to_be_u16(cksum16(header_bytes, hlen, 0)); 230 | header 231 | } 232 | 233 | pub fn output( 234 | ip_proto: IPProtocolType, 235 | mut data: Vec, 236 | src: IPAdress, 237 | dst: IPAdress, 238 | device: &mut NetDevice, 239 | contexts: &mut ProtocolContexts, 240 | ) -> Result<(), ()> { 241 | let route_opt = contexts.ip_routes.lookup_ip_route(dst); 242 | if route_opt.is_none() { 243 | return Err(()); 244 | } 245 | let route = route_opt.unwrap(); 246 | 247 | if src != IP_ADDR_ANY && src != route.interface.unicast { 248 | warn!( 249 | "IP: source address: {:?} not matching with interface unicast: {:?}", 250 | ip_addr_to_str(src), 251 | ip_addr_to_str(route.interface.unicast) 252 | ); 253 | return Err(()); 254 | } 255 | let next_hop = if route.next_hop != IP_ADDR_ANY { 256 | route.next_hop 257 | } else { 258 | dst 259 | }; 260 | 261 | let header = create_ip_header( 262 | ip_proto, 263 | route.interface.unicast, 264 | dst, 265 | &data, 266 | contexts.ip_id_manager.generate_id(), 267 | ); 268 | 269 | let header_dst = header.dst; 270 | trace!( 271 | "IP: output header destination = {:?} src = {:?} nexthop = {:?}", 272 | ip_addr_to_str(header_dst), 273 | ip_addr_to_str(header.src), 274 | ip_addr_to_str(next_hop) 275 | ); 276 | 277 | let header_bytes = unsafe { to_u8_slice::(&header) }; // add icmp data here 278 | let mut ip_data = header_bytes.to_vec(); 279 | ip_data.append(&mut data); 280 | let ip_data_len = ip_data.len(); 281 | 282 | let mut hw_addr: [u8; ETH_ADDR_LEN] = [0; ETH_ADDR_LEN]; 283 | if device.flags & DEVICE_FLAG_NEED_ARP > 0 { 284 | if dst == route.interface.broadcast || dst == IP_ADDR_BROADCAST { 285 | hw_addr = device.broadcast[..ETH_ADDR_LEN + 1].try_into().unwrap(); 286 | } else { 287 | let arp = arp_resolve( 288 | device, 289 | route.interface.clone(), 290 | &mut contexts.arp_table, 291 | next_hop, 292 | ); 293 | if let Ok(result) = arp { 294 | if result.is_none() { 295 | info!("IP: waiting for ARP reply..."); 296 | return Ok(()); 297 | } 298 | hw_addr = result.unwrap(); 299 | } 300 | } 301 | } 302 | 303 | device.transmit(super::ProtocolType::IP, ip_data, ip_data_len, hw_addr) 304 | } 305 | 306 | fn check_ip_header(header: &IPHeader, data_len: usize, header_len: usize) -> Result<(), ()> { 307 | let ip_version = header.ver_len >> 4; 308 | if ip_version != IP_VERSION_4 { 309 | error!("IP: version error with value: {ip_version}"); 310 | return Err(()); 311 | } 312 | if data_len < header_len { 313 | error!("IP: header length error."); 314 | return Err(()); 315 | } 316 | if data_len < be_to_le_u16(header.total_len) as usize { 317 | error!("IP: total length error."); 318 | return Err(()); 319 | } 320 | let header_bytes = unsafe { to_u8_slice(header) }; 321 | if cksum16(header_bytes, header_len, 0) != 0 { 322 | error!("IP: checksum error."); 323 | return Err(()); 324 | } 325 | let offset = be_to_le_u16(header.offset); 326 | if offset & 0x2000 > 0 || offset & 0x1fff > 0 { 327 | error!("IP: fragment is not supported."); 328 | return Err(()); 329 | } 330 | Ok(()) 331 | } 332 | 333 | pub fn input( 334 | data: &[u8], 335 | len: usize, 336 | device: &mut NetDevice, 337 | contexts: &mut ProtocolContexts, 338 | pcbs: &mut ControlBlocks, 339 | ) -> Result<(), ()> { 340 | if len < IP_HEADER_MIN_SIZE { 341 | panic!("IP: data is too short.") 342 | } 343 | let header = unsafe { bytes_to_struct::(data) }; 344 | let header_len = ((header.ver_len & 0x0f) << 2) as usize; 345 | if let Err(_e) = check_ip_header(&header, len, header_len) { 346 | return Err(()); 347 | } 348 | trace!( 349 | "IP: input src: {:?} dst: {:?}", 350 | ip_addr_to_str(header.src), 351 | ip_addr_to_str(header.dst) 352 | ); 353 | let interface_lookup = device.get_interface(NetInterfaceFamily::IP); 354 | if let Some(interface) = interface_lookup { 355 | if interface.unicast != header.dst { 356 | return Err(()); 357 | } 358 | let sub_data = &data[header_len..]; 359 | match IPProtocolType::from_u8(header.protocol) { 360 | IPProtocolType::Icmp => { 361 | return icmp::input( 362 | sub_data, 363 | len - header_len, 364 | header.src, 365 | header.dst, 366 | device, 367 | &interface, 368 | contexts, 369 | pcbs, 370 | ); 371 | } 372 | IPProtocolType::Tcp => { 373 | return tcp::input( 374 | sub_data, 375 | len - header_len, 376 | header.src, 377 | header.dst, 378 | device, 379 | &interface, 380 | contexts, 381 | pcbs, 382 | ); 383 | } 384 | IPProtocolType::Udp => { 385 | return udp::input( 386 | sub_data, 387 | len - header_len, 388 | header.src, 389 | header.dst, 390 | device, 391 | &interface, 392 | contexts, 393 | pcbs, 394 | ); 395 | } 396 | IPProtocolType::Unknown => { 397 | return Ok(()); 398 | } 399 | }; 400 | } 401 | Ok(()) 402 | } 403 | 404 | /// Converts string IP to bytes in big endian. 405 | pub fn ip_addr_to_bytes(addr: &str) -> Option { 406 | let mut parts = addr.split('.'); 407 | let mut part; 408 | let mut res: u32 = 0; 409 | for i in 0..4 { 410 | part = parts.next(); 411 | part?; 412 | let b = part.unwrap().parse::().unwrap(); 413 | res |= (b as u32) << (8 * i); 414 | } 415 | Some(res) 416 | } 417 | 418 | /// Converts IP bytes in big endian to string. 419 | pub fn ip_addr_to_str(addr: IPAdress) -> String { 420 | let mut parts = Vec::new(); 421 | for i in 0..4 { 422 | let d = (addr >> (8 * i)) & 255; 423 | parts.push(d.to_string()); 424 | } 425 | parts.join(".") 426 | } 427 | 428 | #[cfg(test)] 429 | mod tests { 430 | use super::{ip_addr_to_bytes, ip_addr_to_str}; 431 | 432 | #[test] 433 | fn test_ip_addr_to_bytes() { 434 | let b = ip_addr_to_bytes("127.0.0.1"); 435 | assert_eq!(0x0100007F, b.unwrap()); 436 | } 437 | 438 | #[test] 439 | fn test_ip_addr_to_str() { 440 | let s = ip_addr_to_str(0x0100007F); 441 | assert_eq!("127.0.0.1", s); 442 | } 443 | } 444 | 445 | #[cfg(test)] 446 | mod test { 447 | use std::mem::{size_of, size_of_val}; 448 | 449 | use crate::{ 450 | protocols::ip::ip_addr_to_bytes, 451 | utils::byte::le_to_be_u16, 452 | utils::{cksum16, to_u8_slice}, 453 | }; 454 | 455 | use super::{IPHeader, IPHeaderIdManager, IPProtocolType, IP_VERSION_4}; 456 | 457 | #[test] 458 | fn test_ip_header() { 459 | let data: [u8; 4] = [0x01, 0x02, 0x03, 0x04]; 460 | let hlen = size_of::(); 461 | let len = size_of_val(&data); 462 | let total = hlen as u16 + len as u16; 463 | let mut id_manager = IPHeaderIdManager::new(); 464 | let id = id_manager.generate_id(); 465 | 466 | let hdr = IPHeader { 467 | ver_len: (IP_VERSION_4 << 4) | (hlen as u8 >> 2), // devide by 4 468 | service_type: 0, 469 | total_len: le_to_be_u16(total), 470 | id: le_to_be_u16(id), 471 | offset: 0, 472 | ttl: 0xff, 473 | protocol: IPProtocolType::Icmp as u8, 474 | check_sum: 0, 475 | src: ip_addr_to_bytes("192.0.0.1").unwrap(), 476 | dst: ip_addr_to_bytes("54.0.2.121").unwrap(), 477 | opts: [], 478 | }; 479 | let header_bytes = unsafe { to_u8_slice(&hdr) }; 480 | let res = cksum16(header_bytes, hlen, 0); 481 | assert_eq!(0xC2E9, res); 482 | } 483 | } 484 | -------------------------------------------------------------------------------- /src/protocols/ip/tcp.rs: -------------------------------------------------------------------------------- 1 | use super::{ControlBlocks, ProtocolContexts}; 2 | use super::{IPAdress, IPEndpoint, IPInterface, IPProtocolType, IP_ADDR_ANY, IP_HEADER_MIN_SIZE}; 3 | use crate::devices::NetDevices; 4 | use crate::{ 5 | devices::NetDevice, 6 | protocols::ip::ip_addr_to_str, 7 | utils::byte::{be_to_le_u16, be_to_le_u32, le_to_be_u16, le_to_be_u32}, 8 | utils::{bytes_to_struct, cksum16, to_u8_slice}, 9 | }; 10 | use log::{debug, error, info, warn}; 11 | use rand::Rng; 12 | use std::{ 13 | cmp, 14 | collections::VecDeque, 15 | mem::size_of, 16 | sync::{ 17 | mpsc::{self, Sender}, 18 | Arc, Mutex, 19 | }, 20 | time::{Duration, SystemTime}, 21 | vec, 22 | }; 23 | 24 | const TCP_PCB_COUNT: usize = 16; 25 | const TCP_DEFAULT_ITVL_MICROS: u64 = 200000; 26 | const TCP_RETRANSMIT_TIMOUT_SEC: u64 = 12; 27 | const TCP_TIMEWAIT_SEC: u64 = 30; // substitute for 2MSL 28 | const TCP_SRC_PORT_MIN: u16 = 49152; 29 | const TCP_SRC_PORT_MAX: u16 = 65535; 30 | const PCB_BUF_LEN: usize = 65535; 31 | 32 | #[derive(Debug)] 33 | struct PseudoHeader { 34 | src: IPAdress, 35 | dst: IPAdress, 36 | zero: u8, 37 | protocol: u8, 38 | len: u16, 39 | } 40 | 41 | enum TcpFlag { 42 | FIN = 0x01, 43 | SYN = 0x02, 44 | RST = 0x04, // Reset 45 | PSH = 0x08, // Push up to receiving application immediately 46 | ACK = 0x10, 47 | URG = 0x20, 48 | } 49 | 50 | fn tcp_flag_is(flags: u8, flag: TcpFlag) -> bool { 51 | (flags & 0x3f) == flag as u8 52 | } 53 | 54 | fn tcp_flag_exists(flags: u8, flag: TcpFlag) -> bool { 55 | (flags & 0x3f) & (flag as u8) != 0 56 | } 57 | 58 | #[repr(packed)] 59 | struct TcpHeader { 60 | src_port: u16, 61 | dst_port: u16, 62 | seq_num: u32, 63 | ack_num: u32, 64 | offset: u8, // Offset: 4 bits | Reserved: 4 out of 6 bits 65 | flags: u8, // Reserved: 2 out of 6 bits | Flags: 6 bits (URG/ACK/PSH/RST/SYN/FIN) 66 | window: u16, 67 | sum: u16, 68 | urg_ptr: u16, 69 | } 70 | 71 | #[derive(Debug)] 72 | struct TcpSegmentInfo { 73 | seq_num: u32, 74 | ack_num: u32, 75 | len: u16, 76 | window: u16, 77 | urg_ptr: u16, 78 | } 79 | 80 | struct TcpPcbSendContext { 81 | next: u32, 82 | una: u32, // Send unacknowledged 83 | window: u16, 84 | urg_ptr: u16, 85 | wl1: u32, // Segment sequence number for last window update 86 | wl2: u32, // Segment acknowledgement number for last window update 87 | } 88 | 89 | struct TcpPcbRecvContext { 90 | next: u32, 91 | window: u16, 92 | urg_ptr: u16, 93 | } 94 | 95 | #[derive(PartialEq, Clone, Copy, Debug)] 96 | enum TcpPcbState { 97 | Free, 98 | Closed, 99 | Listen, 100 | SynSent, 101 | SynReceived, 102 | Established, 103 | FinWait1, 104 | FinWait2, 105 | Closing, 106 | TimeWait, 107 | CloseWait, 108 | LastAck, 109 | } 110 | 111 | #[derive(PartialEq, Clone, Copy)] 112 | enum TcpPcbMode { 113 | NotSet, 114 | Rfc793, 115 | Socket, 116 | } 117 | 118 | struct TcpDataQueueEntry { 119 | first_sent_at: SystemTime, 120 | last_sent_at: SystemTime, 121 | retry_interval: Duration, 122 | seq_num: u32, 123 | flags: u8, 124 | data: Vec, 125 | } 126 | 127 | pub struct TcpDataQueue { 128 | entries: VecDeque, 129 | } 130 | 131 | impl TcpDataQueue { 132 | pub fn new() -> TcpDataQueue { 133 | TcpDataQueue { 134 | entries: VecDeque::::new(), 135 | } 136 | } 137 | } 138 | 139 | pub struct TcpBacklog { 140 | pcb_ids: VecDeque, 141 | } 142 | 143 | impl TcpBacklog { 144 | pub fn new() -> TcpBacklog { 145 | TcpBacklog { 146 | pcb_ids: VecDeque::::new(), 147 | } 148 | } 149 | } 150 | 151 | pub struct TcpPcb { 152 | state: TcpPcbState, 153 | mode: TcpPcbMode, 154 | local: IPEndpoint, 155 | remote: IPEndpoint, 156 | send_context: TcpPcbSendContext, 157 | iss: u32, // Initial send sequence number 158 | recv_context: TcpPcbRecvContext, 159 | irs: u32, // Initial receive sequence number 160 | mtu: u16, 161 | mss: u16, 162 | buf: Vec, // [u8; 65535], 163 | wait_time: Option, 164 | sender: Option>, 165 | data_queue: TcpDataQueue, 166 | parent_id: Option, 167 | backlog: TcpBacklog, 168 | } 169 | 170 | impl TcpPcb { 171 | pub fn new() -> TcpPcb { 172 | TcpPcb { 173 | state: TcpPcbState::Free, 174 | mode: TcpPcbMode::NotSet, 175 | local: IPEndpoint { 176 | address: IP_ADDR_ANY, 177 | port: 0, 178 | }, 179 | remote: IPEndpoint { 180 | address: IP_ADDR_ANY, 181 | port: 0, 182 | }, 183 | iss: 0, 184 | send_context: TcpPcbSendContext { 185 | next: 0, 186 | una: 0, 187 | window: 0, 188 | urg_ptr: 0, 189 | wl1: 0, 190 | wl2: 0, 191 | }, 192 | recv_context: TcpPcbRecvContext { 193 | next: 0, 194 | window: 0, 195 | urg_ptr: 0, 196 | }, 197 | irs: 0, 198 | mtu: 0, 199 | mss: 0, 200 | buf: Vec::with_capacity(PCB_BUF_LEN), 201 | wait_time: None, 202 | sender: None, 203 | data_queue: TcpDataQueue::new(), 204 | parent_id: None, 205 | backlog: TcpBacklog::new(), 206 | } 207 | } 208 | 209 | pub fn add_data_queue(&mut self, seq_num: u32, flags: u8, data: Vec) { 210 | let now = SystemTime::now(); 211 | let entry = TcpDataQueueEntry { 212 | first_sent_at: now, 213 | last_sent_at: now, 214 | retry_interval: Duration::from_micros(TCP_DEFAULT_ITVL_MICROS), 215 | seq_num, 216 | flags, 217 | data, 218 | }; 219 | self.data_queue.entries.push_back(entry); 220 | } 221 | 222 | pub fn clean_data_queue(&mut self) { 223 | let mut found = false; 224 | let mut index_to_delete = 0; 225 | for (i, entry) in self.data_queue.entries.iter().enumerate() { 226 | if entry.seq_num >= self.send_context.una { 227 | break; 228 | } 229 | found = true; 230 | index_to_delete = i; 231 | } 232 | if found { 233 | self.data_queue.entries.remove(index_to_delete); 234 | } 235 | } 236 | 237 | pub fn release(&mut self) { 238 | self.state = TcpPcbState::Free; 239 | if self.sender.is_some() { 240 | if self.sender.as_ref().unwrap().send(false).is_err() { 241 | warn!("TCP: attempting PRB release, however channel not listening."); 242 | } 243 | } 244 | self.data_queue.entries.clear(); 245 | 246 | // TODO: close all backlog pcbs also 247 | // for pcb in self.backlog.pcb_ids.iter_mut() {} 248 | self.backlog.pcb_ids.clear(); 249 | } 250 | 251 | pub fn add_backlog(&mut self, pcb_id: usize) { 252 | self.backlog.pcb_ids.push_back(pcb_id); 253 | } 254 | } 255 | 256 | pub struct TcpPcbs { 257 | pub entries: Vec, 258 | } 259 | 260 | impl TcpPcbs { 261 | pub fn new() -> TcpPcbs { 262 | let mut entries = Vec::with_capacity(TCP_PCB_COUNT); 263 | for _ in 0..TCP_PCB_COUNT { 264 | entries.push(TcpPcb::new()); 265 | } 266 | TcpPcbs { entries } 267 | } 268 | 269 | pub fn new_entry(&mut self) -> Option<(usize, &mut TcpPcb)> { 270 | for (i, pcb) in self.entries.iter_mut().enumerate() { 271 | if pcb.state == TcpPcbState::Free { 272 | pcb.state = TcpPcbState::Closed; 273 | return Some((i, pcb)); 274 | } 275 | } 276 | None 277 | } 278 | 279 | pub fn get_mut_by_id(&mut self, pcb_id: usize) -> Option<&mut TcpPcb> { 280 | self.entries.get_mut(pcb_id) 281 | } 282 | 283 | pub fn select( 284 | &mut self, 285 | local: &IPEndpoint, 286 | remote_opt: Option<&IPEndpoint>, 287 | ) -> Option<(usize, &mut TcpPcb)> { 288 | let mut listen_pcb = None; 289 | for (i, pcb) in self.entries.iter_mut().enumerate() { 290 | if (pcb.local.address == IP_ADDR_ANY || pcb.local.address == local.address) 291 | && pcb.local.port == local.port 292 | { 293 | // Bindable check for local address only 294 | if remote_opt.is_none() { 295 | return Some((i, pcb)); 296 | } 297 | let remote = remote_opt.unwrap(); 298 | // Both remote address and port match 299 | if pcb.remote.address == remote.address { 300 | return Some((i, pcb)); 301 | } 302 | // Listen without specifying remote address 303 | if pcb.state == TcpPcbState::Listen { 304 | if pcb.remote.address == IP_ADDR_ANY && pcb.remote.port == 0 { 305 | listen_pcb = Some((i, pcb)); 306 | } 307 | } 308 | } 309 | } 310 | listen_pcb 311 | } 312 | 313 | pub fn close_sockets(&mut self) { 314 | for pcb in self.entries.iter_mut() { 315 | pcb.release(); 316 | } 317 | } 318 | } 319 | 320 | fn pcb_by_id(pcbs: &mut TcpPcbs, pcb_id: usize) -> &mut TcpPcb { 321 | pcbs.get_mut_by_id(pcb_id) 322 | .expect("TCP: PCB with specified id was not found.") 323 | } 324 | 325 | fn set_wait_time(pcb: &mut TcpPcb) { 326 | let addition = Duration::from_secs(TCP_TIMEWAIT_SEC); 327 | if pcb.wait_time.is_none() { 328 | pcb.wait_time = SystemTime::now().checked_add(addition); 329 | } else { 330 | pcb.wait_time.unwrap().checked_add(addition); 331 | } 332 | } 333 | 334 | pub fn retransmit(pcbs: &mut TcpPcbs, device: &mut NetDevice, contexts: &mut ProtocolContexts) { 335 | for pcb in pcbs.entries.iter_mut() { 336 | if pcb.state == TcpPcbState::Free { 337 | continue; 338 | } 339 | if pcb.state == TcpPcbState::TimeWait { 340 | if pcb.wait_time.unwrap().elapsed().unwrap().as_micros() > 0 { 341 | info!( 342 | "TCP: timewait has elapsed for local = {:?} remote = {:?}", 343 | ip_addr_to_str(pcb.local.address), 344 | ip_addr_to_str(pcb.remote.address) 345 | ); 346 | pcb.release(); 347 | continue; 348 | } 349 | } 350 | while let Some(queue) = pcb.data_queue.entries.pop_front() { 351 | if queue.first_sent_at.elapsed().unwrap().as_secs() >= TCP_RETRANSMIT_TIMOUT_SEC { 352 | pcb.release(); 353 | continue; 354 | } 355 | let timeout = queue 356 | .last_sent_at 357 | .checked_add(queue.retry_interval) 358 | .unwrap(); 359 | if timeout.elapsed().is_err() { 360 | // elapsed errors when time is before now 361 | info!("TCP: retransmitting a segment..."); 362 | output_segment( 363 | queue.seq_num, 364 | pcb.recv_context.next, 365 | queue.flags, 366 | pcb.recv_context.window, 367 | queue.data.clone(), // TODO: fix clone 368 | &pcb.local, 369 | &pcb.remote, 370 | device, 371 | contexts, 372 | ); 373 | } 374 | } 375 | } 376 | } 377 | 378 | pub fn output_segment( 379 | seq_num: u32, 380 | ack_num: u32, 381 | flags: u8, 382 | window: u16, 383 | mut tcp_data: Vec, 384 | local: &IPEndpoint, 385 | remote: &IPEndpoint, 386 | device: &mut NetDevice, 387 | contexts: &mut ProtocolContexts, 388 | ) -> usize { 389 | let tcp_hdr_size = size_of::(); 390 | let tcp_data_len = tcp_data.len(); 391 | let total_len = tcp_data_len + tcp_hdr_size; 392 | let tcp_header = TcpHeader { 393 | src_port: local.port, 394 | dst_port: remote.port, 395 | seq_num: le_to_be_u32(seq_num), 396 | ack_num: le_to_be_u32(ack_num), 397 | offset: ((tcp_hdr_size >> 2) << 4) as u8, 398 | flags, 399 | window: le_to_be_u16(window), 400 | sum: 0, 401 | urg_ptr: 0, 402 | }; 403 | let pseudo_header = PseudoHeader { 404 | src: local.address, 405 | dst: remote.address, 406 | zero: 0, 407 | protocol: IPProtocolType::Tcp as u8, 408 | len: le_to_be_u16(total_len as u16), 409 | }; 410 | let pseudo_hdr_bytes = unsafe { to_u8_slice(&pseudo_header) }; 411 | let pseudo_sum = cksum16(pseudo_hdr_bytes, pseudo_hdr_bytes.len(), 0); 412 | 413 | let tcp_hdr_bytes = unsafe { to_u8_slice::(&tcp_header) }; 414 | let mut data = tcp_hdr_bytes.to_vec(); 415 | data.append(&mut tcp_data); 416 | // Update checksum 417 | let sum = cksum16(&data, total_len, !pseudo_sum as u32); 418 | data[16] = ((sum & 0xff00) >> 8) as u8; 419 | data[17] = (sum & 0xff) as u8; 420 | 421 | super::output( 422 | IPProtocolType::Tcp, 423 | data, 424 | local.address, 425 | remote.address, 426 | device, 427 | contexts, 428 | ) 429 | .unwrap(); 430 | tcp_data_len 431 | } 432 | 433 | pub fn output( 434 | pcb: &mut TcpPcb, 435 | flags: u8, 436 | data: Vec, 437 | device: &mut NetDevice, 438 | contexts: &mut ProtocolContexts, 439 | ) -> usize { 440 | let mut seq_num = pcb.send_context.next; 441 | if tcp_flag_exists(flags, TcpFlag::SYN) { 442 | seq_num = pcb.iss; 443 | } 444 | if (tcp_flag_exists(flags, TcpFlag::SYN) || tcp_flag_exists(flags, TcpFlag::FIN)) 445 | || data.len() > 0 446 | { 447 | pcb.add_data_queue(seq_num, flags, data.clone()); // TODO: fix clone 448 | } 449 | output_segment( 450 | seq_num, 451 | pcb.recv_context.next, 452 | flags, 453 | pcb.recv_context.window, 454 | data, 455 | &pcb.local, 456 | &pcb.remote, 457 | device, 458 | contexts, 459 | ) 460 | } 461 | 462 | // rfc793 section 3.9 463 | fn segment_arrives( 464 | seg: TcpSegmentInfo, 465 | flags: u8, 466 | data: &[u8], 467 | len: usize, 468 | local: IPEndpoint, 469 | remote: IPEndpoint, 470 | device: &mut NetDevice, 471 | contexts: &mut ProtocolContexts, 472 | pcbs: &mut ControlBlocks, 473 | ) { 474 | let pcb_state; 475 | let pcb_id; 476 | let pcb_mode; 477 | 478 | debug!("TCP: segment flag byte = {:#010b}", flags); 479 | 480 | { 481 | let pcb_opt = pcbs.tcp_pcbs.select(&local, Some(&remote)); 482 | // No PCB or PCB is closed state 483 | if pcb_opt.is_none() || pcb_opt.as_ref().unwrap().1.state == TcpPcbState::Closed { 484 | info!("TCP: segment received for new/closed connection."); 485 | if tcp_flag_exists(flags, TcpFlag::RST) { 486 | info!("TCP: RST found. Returning..."); 487 | return; 488 | } 489 | // Segment to unused port. Return RST. 490 | if tcp_flag_exists(flags, TcpFlag::ACK) { 491 | info!("TCP: ACK found. Replying with RST..."); 492 | output_segment( 493 | seg.ack_num, 494 | 0, 495 | TcpFlag::RST as u8, 496 | 0, 497 | vec![], 498 | &local, 499 | &remote, 500 | device, 501 | contexts, 502 | ); 503 | } else { 504 | info!("TCP: non-ACK received. Replying RST-ACK..."); 505 | output_segment( 506 | 0, 507 | seg.seq_num + (seg.len as u32), 508 | TcpFlag::RST as u8 | TcpFlag::ACK as u8, 509 | 0, 510 | vec![], 511 | &local, 512 | &remote, 513 | device, 514 | contexts, 515 | ); 516 | } 517 | return; 518 | } 519 | let (id, pcb) = pcb_opt.unwrap(); 520 | pcb_state = pcb.state; 521 | pcb_id = id; 522 | pcb_mode = pcb.mode; 523 | } 524 | 525 | let mut acceptable = false; 526 | 527 | // Listen state 528 | if pcb_state == TcpPcbState::Listen { 529 | info!("TCP: connection in LISTEN state."); 530 | // Check for reset first. 531 | if tcp_flag_exists(flags, TcpFlag::RST) { 532 | return; 533 | } 534 | // Secondly check for ack. 535 | if tcp_flag_exists(flags, TcpFlag::ACK) { 536 | info!("TCP: ACK found. Replying with RST..."); 537 | output_segment( 538 | seg.ack_num, 539 | 0, 540 | TcpFlag::RST as u8, 541 | 0, 542 | vec![], 543 | &local, 544 | &remote, 545 | device, 546 | contexts, 547 | ); 548 | return; 549 | } 550 | // Third check on SYN 551 | if tcp_flag_exists(flags, TcpFlag::SYN) { 552 | info!("TCP: SYN found."); 553 | // Ignore: security / compartment / precedence checks 554 | let pcb = { 555 | if pcb_mode == TcpPcbMode::Socket { 556 | let new_pcb = pcbs 557 | .tcp_pcbs 558 | .new_entry() 559 | .expect("TCP: failed to allocate new pcb.") 560 | .1; 561 | new_pcb.mode = TcpPcbMode::Socket; 562 | new_pcb.parent_id = Some(pcb_id); 563 | new_pcb 564 | } else { 565 | pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id) 566 | } 567 | }; 568 | pcb.local = local; 569 | pcb.remote = remote; 570 | pcb.recv_context.window = PCB_BUF_LEN as u16; 571 | pcb.recv_context.next = seg.seq_num + 1; 572 | pcb.iss = rand::thread_rng().gen_range(0..u32::MAX); 573 | info!("TCP: replying with SYN-ACK..."); 574 | output( 575 | pcb, 576 | TcpFlag::SYN as u8 | TcpFlag::ACK as u8, 577 | vec![], 578 | device, 579 | contexts, 580 | ); 581 | pcb.send_context.next = pcb.iss + 1; 582 | pcb.send_context.una = pcb.iss; 583 | pcb.state = TcpPcbState::SynReceived; 584 | // Any other incoming control or data with SYN will be processed in SYN-RECEIVED state. 585 | // But processing SYN or ACK should not be repeated. 586 | return; 587 | } 588 | // Fourth: other text or control 589 | return; // drop segment 590 | } else if pcb_state == TcpPcbState::SynSent { 591 | info!("TCP: connection in SYN-SENT state."); 592 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 593 | // First: check ACK 594 | if tcp_flag_exists(flags, TcpFlag::ACK) { 595 | if seg.ack_num <= pcb.iss || seg.ack_num > pcb.send_context.next { 596 | info!("TCP: ACK found with glitches. Replying with RST..."); 597 | output_segment( 598 | seg.ack_num, 599 | 0, 600 | TcpFlag::RST as u8, 601 | 0, 602 | vec![], 603 | &local, 604 | &remote, 605 | device, 606 | contexts, 607 | ); 608 | return; 609 | } 610 | if pcb.send_context.una <= seg.ack_num && seg.ack_num <= pcb.send_context.next { 611 | acceptable = true; 612 | } 613 | } 614 | // Second: check RST 615 | if tcp_flag_exists(flags, TcpFlag::RST) { 616 | if acceptable { 617 | info!("TCP: RST found. Closing connection."); 618 | pcb.release(); 619 | } 620 | return; 621 | } 622 | // Third: check security and precedence (ignored) 623 | // Fourth: check SYN 624 | if tcp_flag_exists(flags, TcpFlag::SYN) { 625 | info!("TCP: SYN found."); 626 | pcb.recv_context.next = seg.seq_num + 1; 627 | pcb.irs = seg.seq_num; 628 | if acceptable { 629 | pcb.send_context.una = seg.ack_num; 630 | pcb.clean_data_queue(); 631 | } 632 | if pcb.send_context.una > pcb.iss { 633 | pcb.state = TcpPcbState::Established; 634 | info!("TCP: send.una > iss = Established. Replying with ACK..."); 635 | output(pcb, TcpFlag::ACK as u8, vec![], device, contexts); 636 | // RFC793 does not specify, but send window initialization reqiured 637 | pcb.send_context.window = seg.window; 638 | pcb.send_context.wl1 = seg.seq_num; 639 | pcb.send_context.wl2 = seg.ack_num; 640 | if pcb.sender.is_some() { 641 | info!("TCP: waking up sleeping PCB of open command..."); 642 | if pcb.sender.as_ref().unwrap().send(true).is_err() { 643 | info!("TCP: PCB channel not listening."); 644 | }; 645 | } 646 | // Ignore: continue to sixth check on URG 647 | } else { 648 | info!("TCP: send.una <= iss = Syn-Received. Replying with SYN-ACK..."); 649 | pcb.state = TcpPcbState::SynReceived; 650 | output( 651 | pcb, 652 | TcpFlag::SYN as u8 | TcpFlag::ACK as u8, 653 | vec![], 654 | device, 655 | contexts, 656 | ); 657 | // Ignore: other controls or texts of segment should be queued after ESTABLISHED 658 | return; 659 | } 660 | } 661 | // Fifth: neither SYN or RST so drop segment 662 | return; 663 | } 664 | 665 | info!( 666 | "TCP: connection checked for LISTEN or SYN-SENT state. It is in {:?}", 667 | pcb_state 668 | ); 669 | 670 | // First: check sequence number. 671 | if pcb_state == TcpPcbState::SynReceived 672 | || pcb_state == TcpPcbState::Established 673 | || pcb_state == TcpPcbState::FinWait1 674 | || pcb_state == TcpPcbState::FinWait2 675 | || pcb_state == TcpPcbState::CloseWait 676 | || pcb_state == TcpPcbState::Closing 677 | || pcb_state == TcpPcbState::LastAck 678 | || pcb_state == TcpPcbState::TimeWait 679 | { 680 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 681 | info!( 682 | "TCP: PCB recv.window = {:x} recv.next = {:x}", 683 | pcb.recv_context.window, pcb.recv_context.next 684 | ); 685 | if seg.len < 1 { 686 | if pcb.recv_context.window < 1 { 687 | if seg.seq_num == pcb.recv_context.next { 688 | acceptable = true; 689 | } 690 | } else { 691 | if pcb.recv_context.next <= seg.seq_num 692 | && seg.seq_num < pcb.recv_context.next + pcb.recv_context.window as u32 693 | { 694 | acceptable = true; 695 | } 696 | } 697 | } else { 698 | if pcb.recv_context.window < 1 { 699 | // not acceptable 700 | } else { 701 | if (pcb.recv_context.next <= seg.seq_num 702 | && seg.seq_num < pcb.recv_context.next + pcb.recv_context.window as u32) 703 | || (pcb.recv_context.next <= seg.seq_num + seg.len as u32 - 1 704 | && seg.seq_num + seg.len as u32 - 1 705 | < pcb.recv_context.next + pcb.recv_context.window as u32) 706 | { 707 | acceptable = true; 708 | } 709 | } 710 | } 711 | if !acceptable { 712 | info!("TCP: seq not acceptable."); 713 | if tcp_flag_exists(flags, TcpFlag::RST) { 714 | info!("TCP: RST found and sequence/window not acceptable. Replying with ACK..."); 715 | output(pcb, TcpFlag::ACK as u8, vec![], device, contexts); 716 | } 717 | return; 718 | } 719 | // In the following it is assumed that the segment is the idealized 720 | // segment that begins at RCV.NXT and does not exceed the window. 721 | // One could tailor actual segments to fit this assumption by 722 | // trimming off any portions that lie outside the window (including 723 | // SYN and FIN), and only processing further if the segment then 724 | // begins at RCV.NXT. Segments with higher begining sequence 725 | // numbers may be held for later processing. 726 | } 727 | // Second: check RST bit 728 | if pcb_state == TcpPcbState::SynReceived { 729 | if tcp_flag_exists(flags, TcpFlag::RST) { 730 | info!("TCP: RST found for connection in SYN-RECEIVED state. Closing..."); 731 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 732 | pcb.release(); 733 | return; 734 | } 735 | } else if pcb_state == TcpPcbState::Established 736 | || pcb_state == TcpPcbState::FinWait1 737 | || pcb_state == TcpPcbState::FinWait2 738 | || pcb_state == TcpPcbState::CloseWait 739 | { 740 | if tcp_flag_exists(flags, TcpFlag::RST) { 741 | info!("TCP: connection reset."); 742 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 743 | pcb.release(); 744 | return; 745 | } 746 | } else if pcb_state == TcpPcbState::Closing 747 | || pcb_state == TcpPcbState::LastAck 748 | || pcb_state == TcpPcbState::TimeWait 749 | { 750 | info!("TCP: connection in final state. Closing..."); 751 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 752 | pcb.release(); 753 | return; 754 | } 755 | 756 | // Third: security and precedence check (ignored) 757 | 758 | // Fourth: check SYN bit 759 | if pcb_state == TcpPcbState::SynReceived 760 | || pcb_state == TcpPcbState::Established 761 | || pcb_state == TcpPcbState::FinWait1 762 | || pcb_state == TcpPcbState::FinWait2 763 | || pcb_state == TcpPcbState::CloseWait 764 | || pcb_state == TcpPcbState::Closing 765 | || pcb_state == TcpPcbState::LastAck 766 | || pcb_state == TcpPcbState::TimeWait 767 | { 768 | if tcp_flag_exists(flags, TcpFlag::SYN) { 769 | info!("TCP: SYN found. Connection reset."); 770 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 771 | pcb.release(); 772 | return; 773 | } 774 | } 775 | 776 | // Fifth: check ACK 777 | if !tcp_flag_exists(flags, TcpFlag::ACK) { 778 | return; // drop segment 779 | } 780 | info!("TCP: ACK found."); 781 | if pcb_state == TcpPcbState::SynReceived { 782 | info!("TCP: connection in SYN-RECEIVED state."); 783 | let mut parent_id = None; 784 | { 785 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 786 | if pcb.send_context.una <= seg.ack_num && seg.ack_num <= pcb.send_context.next { 787 | info!("TCP: send.una <= seg.ack = ESTABLISHED. Waking up sleeping PCB..."); 788 | pcb.state = TcpPcbState::Established; 789 | if pcb.sender.is_some() { 790 | if pcb.sender.as_ref().unwrap().send(true).is_err() { 791 | warn!("TCP: PCB channel not listening."); 792 | } 793 | } 794 | if pcb.parent_id.is_some() { 795 | parent_id = pcb.parent_id; 796 | } 797 | } else { 798 | info!("TCP: send.una > seg.ack = not ESTABLISHED. Replying with RST..."); 799 | output_segment( 800 | seg.ack_num, 801 | 0, 802 | TcpFlag::RST as u8, 803 | 0, 804 | vec![], 805 | &local, 806 | &remote, 807 | device, 808 | contexts, 809 | ); 810 | return; 811 | } 812 | } 813 | if parent_id.is_some() { 814 | info!("TCP: parent PCB found. Waking up sleeping parent PCB..."); 815 | let parent_pcb = pcb_by_id(&mut pcbs.tcp_pcbs, parent_id.unwrap()); 816 | parent_pcb.add_backlog(pcb_id); 817 | if parent_pcb.sender.is_some() { 818 | if parent_pcb.sender.as_ref().unwrap().send(true).is_err() { 819 | warn!("TCP: parent PCB channel not listening."); 820 | } 821 | } 822 | } 823 | } else if pcb_state == TcpPcbState::Established 824 | || pcb_state == TcpPcbState::FinWait1 825 | || pcb_state == TcpPcbState::FinWait2 826 | || pcb_state == TcpPcbState::CloseWait 827 | || pcb_state == TcpPcbState::Closing 828 | { 829 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 830 | // Received ack including unacked sequence number 831 | if pcb.send_context.una < seg.ack_num && seg.ack_num <= pcb.send_context.next { 832 | info!( 833 | "TCP: received ack including unacked seq number. Updating send.una with seg.ack." 834 | ); 835 | pcb.send_context.una = seg.ack_num; 836 | pcb.clean_data_queue(); 837 | 838 | // Ignore: users should receive positive acknowledgments for buffers which have been SENT 839 | // and fully acknowledged (i.e., SEND buffer should be returned with "ok" response) 840 | if pcb.send_context.wl1 < seg.seq_num 841 | || (pcb.send_context.wl1 == seg.seq_num && pcb.send_context.wl2 <= seg.ack_num) 842 | { 843 | pcb.send_context.window = seg.window; 844 | pcb.send_context.wl1 = seg.seq_num; 845 | pcb.send_context.wl2 = seg.ack_num; 846 | } 847 | } else if seg.ack_num < pcb.send_context.una { 848 | // Ignore: already checked ack 849 | } else if seg.ack_num > pcb.send_context.next { 850 | info!("TCP: seg.ack > send.next. Replying with ACK..."); 851 | output(pcb, TcpFlag::ACK as u8, vec![], device, contexts); 852 | return; 853 | } 854 | if pcb_state == TcpPcbState::Closing { 855 | if seg.ack_num == pcb.send_context.next { 856 | info!("TCP: connection in CLOSING state and seg.ack == send.next. Waking up PCB with wait time..."); 857 | pcb.state = TcpPcbState::TimeWait; 858 | set_wait_time(pcb); 859 | if pcb.sender.is_some() { 860 | if pcb.sender.as_ref().unwrap().send(true).is_err() { 861 | warn!("TCP: PCB channel not listening."); 862 | }; 863 | } 864 | } 865 | } 866 | } else if pcb_state == TcpPcbState::LastAck { 867 | info!("TCP: connection in LAST-ACK state."); 868 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 869 | if seg.ack_num == pcb.send_context.next { 870 | pcb.release(); 871 | } 872 | return; 873 | } else if pcb_state == TcpPcbState::TimeWait { 874 | if tcp_flag_exists(flags, TcpFlag::FIN) { 875 | info!("TCP: FIN found for connection in TIME-WAIT state. Extending wait time..."); 876 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 877 | set_wait_time(pcb); 878 | } 879 | } 880 | 881 | // Sixth: check URG (ignored) 882 | 883 | // Seventh: process segment text 884 | if pcb_state == TcpPcbState::Established 885 | || pcb_state == TcpPcbState::FinWait1 886 | || pcb_state == TcpPcbState::FinWait2 887 | { 888 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 889 | if len > 0 { 890 | info!("TCP: received data. Updating window, replying with ACK and waking up PCB..."); 891 | // memcpy(pcb->buf + (sizeof(pcb->buf) - pcb->rcv.wnd), data, len); 892 | pcb.buf.append(&mut data.to_vec()); 893 | pcb.recv_context.next = seg.seq_num + seg.len as u32; 894 | pcb.recv_context.window -= len as u16; 895 | output(pcb, TcpFlag::ACK as u8, vec![], device, contexts); 896 | if pcb.sender.is_some() { 897 | if pcb.sender.as_ref().unwrap().send(true).is_err() { 898 | warn!("TCP: PCB channel in receive not listening."); 899 | }; 900 | } 901 | } 902 | } else if pcb_state == TcpPcbState::CloseWait 903 | || pcb_state == TcpPcbState::Closing 904 | || pcb_state == TcpPcbState::LastAck 905 | || pcb_state == TcpPcbState::TimeWait 906 | { 907 | // Ignore: segment text 908 | } 909 | 910 | // Eighth: check FIN 911 | if tcp_flag_exists(flags, TcpFlag::FIN) { 912 | info!("TCP: FIN flag found."); 913 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 914 | if pcb_state == TcpPcbState::Closed 915 | || pcb_state == TcpPcbState::Listen 916 | || pcb_state == TcpPcbState::SynSent 917 | { 918 | return; // drop segment 919 | } 920 | 921 | info!("TCP: sending ACK..."); 922 | pcb.recv_context.next = seg.seq_num + 1; 923 | output(pcb, TcpFlag::ACK as u8, vec![], device, contexts); 924 | 925 | if pcb_state == TcpPcbState::SynReceived || pcb_state == TcpPcbState::Established { 926 | info!("TCP: connection in SYN-RECEIVED / ESTABLISHED state. Moving to CLOSE-WAIT and waking up PCB..."); 927 | pcb.state = TcpPcbState::CloseWait; 928 | if pcb.sender.is_some() { 929 | if pcb.sender.as_ref().unwrap().send(true).is_err() { 930 | warn!("TCP: PCB channel not listening."); 931 | } 932 | } 933 | } else if pcb_state == TcpPcbState::FinWait1 { 934 | if seg.ack_num == pcb.send_context.next { 935 | info!("TCP: connection in FIN-WAIT1 state and seg.ack == send.next. Moving to TIME-WAIT and waking up PCB..."); 936 | pcb.state = TcpPcbState::TimeWait; 937 | set_wait_time(pcb); 938 | } else { 939 | info!("TCP: connection in FIN-WAIT1 state and seg.ack != send.next. Moving to CLOSING..."); 940 | pcb.state = TcpPcbState::Closing; 941 | } 942 | } else if pcb_state == TcpPcbState::FinWait2 { 943 | info!("TCP: connection in FIN-WAIT2 state. Moving to TIME-WAIT..."); 944 | pcb.state = TcpPcbState::TimeWait; 945 | } else if pcb_state == TcpPcbState::CloseWait { 946 | // Remain in CLOSE-WAIT state. 947 | } else if pcb_state == TcpPcbState::Closing { 948 | // Remain in CLOSING state. 949 | } else if pcb_state == TcpPcbState::LastAck { 950 | // Remain in LAST-ACK state. 951 | } else if pcb_state == TcpPcbState::TimeWait { 952 | // Remain in TIME-WAIT state. 953 | set_wait_time(pcb); 954 | } 955 | } 956 | } 957 | 958 | pub fn input( 959 | data: &[u8], 960 | len: usize, 961 | src: IPAdress, 962 | dst: IPAdress, 963 | device: &mut NetDevice, 964 | iface: &IPInterface, 965 | contexts: &mut ProtocolContexts, 966 | pcbs: &mut ControlBlocks, 967 | ) -> Result<(), ()> { 968 | let tcp_hdr_size = size_of::(); 969 | let header = unsafe { bytes_to_struct::(data) }; 970 | 971 | if len < tcp_hdr_size { 972 | panic!("TCP input: too short data."); 973 | } 974 | 975 | let pseudo_header = PseudoHeader { 976 | src, 977 | dst, 978 | zero: 0, 979 | protocol: IPProtocolType::Tcp as u8, 980 | len: le_to_be_u16(len as u16), 981 | }; 982 | let pseudo_hdr_bytes = unsafe { to_u8_slice(&pseudo_header) }; 983 | let pseudo_sum = !cksum16(pseudo_hdr_bytes, pseudo_hdr_bytes.len(), 0); 984 | let sum = cksum16(data, len, pseudo_sum as u32); 985 | if sum != 0 { 986 | error!("TCP input checksum failure: value = {sum}"); 987 | return Err(()); 988 | } 989 | 990 | if src == IP_ADDR_ANY || src == iface.broadcast || dst == IP_ADDR_ANY || dst == iface.broadcast 991 | { 992 | panic!("TCP input: only unicast is supported."); 993 | } 994 | 995 | info!( 996 | "TCP input: source port = {:?} destination port: {:?}", 997 | be_to_le_u16(header.src_port), 998 | be_to_le_u16(header.dst_port) 999 | ); 1000 | 1001 | let local = IPEndpoint { 1002 | address: dst, 1003 | port: header.dst_port, 1004 | }; 1005 | let remote = IPEndpoint { 1006 | address: src, 1007 | port: header.src_port, 1008 | }; 1009 | let header_len = ((header.offset >> 4) << 2) as usize; 1010 | let mut seg_len = len - header_len; 1011 | if tcp_flag_exists(header.flags, TcpFlag::SYN) { 1012 | seg_len += 1; 1013 | } 1014 | if tcp_flag_exists(header.flags, TcpFlag::FIN) { 1015 | seg_len += 1; 1016 | } 1017 | let seg = TcpSegmentInfo { 1018 | seq_num: be_to_le_u32(header.seq_num), 1019 | ack_num: be_to_le_u32(header.ack_num), 1020 | len: seg_len as u16, 1021 | window: be_to_le_u16(header.window), 1022 | urg_ptr: be_to_le_u16(header.urg_ptr), 1023 | }; 1024 | 1025 | info!("TCP: received segment = {:?}", seg); 1026 | 1027 | segment_arrives( 1028 | seg, 1029 | header.flags, 1030 | &data[tcp_hdr_size..], 1031 | len - header_len, 1032 | local, 1033 | remote, 1034 | device, 1035 | contexts, 1036 | pcbs, 1037 | ); 1038 | 1039 | Ok(()) 1040 | } 1041 | 1042 | // User commands (RFC793) 1043 | 1044 | pub fn rfc793_open( 1045 | local: IPEndpoint, 1046 | remote_opt: Option, 1047 | active: bool, 1048 | pcbs_arc: Arc>, 1049 | devices_arc: Arc>, 1050 | contexts_arc: Arc>, 1051 | ) -> Option { 1052 | let pcb_id; 1053 | let pcb_state; 1054 | let initial_pcb_state; 1055 | let (sender, receiver) = mpsc::channel(); 1056 | { 1057 | let pcbs = &mut pcbs_arc.lock().unwrap(); 1058 | let devices = &mut devices_arc.lock().unwrap(); 1059 | let contexts = &mut contexts_arc.lock().unwrap(); 1060 | let eth_device = devices 1061 | .get_mut_by_type(crate::devices::NetDeviceType::Ethernet) 1062 | .unwrap(); 1063 | 1064 | let (new_pcb_id, pcb) = pcbs 1065 | .tcp_pcbs 1066 | .new_entry() 1067 | .expect("TCP: failed to create a new PCB."); 1068 | pcb_id = new_pcb_id; 1069 | pcb.mode = TcpPcbMode::Rfc793; 1070 | pcb.local = local; 1071 | pcb.sender = Some(sender); 1072 | if remote_opt.is_some() { 1073 | pcb.remote = remote_opt.unwrap(); 1074 | } 1075 | 1076 | if !active { 1077 | info!( 1078 | "TCP: passive open with local IP = {:?} port = {:?}", 1079 | ip_addr_to_str(pcb.local.address), 1080 | be_to_le_u16(pcb.local.port) 1081 | ); 1082 | pcb.state = TcpPcbState::Listen; 1083 | } else { 1084 | info!( 1085 | "TCP: active open with local = {:?} and remote = {:?}", 1086 | ip_addr_to_str(pcb.local.address), 1087 | ip_addr_to_str(pcb.remote.address) 1088 | ); 1089 | pcb.recv_context.window = PCB_BUF_LEN as u16; 1090 | pcb.iss = rand::thread_rng().gen_range(0..u32::MAX); 1091 | 1092 | output(pcb, TcpFlag::SYN as u8, vec![], eth_device, contexts); 1093 | // if res.is_err() { 1094 | // pcb.state = TcpPcbState::Closed; 1095 | // } 1096 | pcb.send_context.una = pcb.iss; 1097 | pcb.send_context.next = pcb.iss + 1; 1098 | pcb.state = TcpPcbState::SynSent; 1099 | } 1100 | pcb_state = pcb.state; 1101 | initial_pcb_state = pcb.state; 1102 | } 1103 | while pcb_state == initial_pcb_state { 1104 | let proceed = receiver.recv().unwrap(); 1105 | { 1106 | let pcbs = &mut pcbs_arc.lock().unwrap(); 1107 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 1108 | if pcb.state == TcpPcbState::Established { 1109 | break; 1110 | } 1111 | if !proceed || pcb.state != TcpPcbState::SynReceived { 1112 | pcb.release(); 1113 | return None; 1114 | } 1115 | } 1116 | } 1117 | info!("TCP rfc793_open: connection established."); 1118 | Some(pcb_id) 1119 | } 1120 | 1121 | // User commands (Socket) 1122 | 1123 | pub fn open(pcbs: &mut ControlBlocks) -> usize { 1124 | let (pcb_id, pcb) = pcbs 1125 | .tcp_pcbs 1126 | .new_entry() 1127 | .expect("TCP open: failed to create a new PCB."); 1128 | pcb.mode = TcpPcbMode::Socket; 1129 | pcb_id 1130 | } 1131 | 1132 | pub fn connect( 1133 | pcb_id: usize, 1134 | remote: &IPEndpoint, 1135 | device: &mut NetDevice, 1136 | contexts: &mut ProtocolContexts, 1137 | pcbs_arc: &mut Arc>, 1138 | ) -> Option { 1139 | let mut local = { 1140 | let pcbs = &mut pcbs_arc.lock().unwrap(); 1141 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 1142 | if pcb.mode != TcpPcbMode::Socket { 1143 | panic!("TCP: pcb is not opened as socket mode."); 1144 | } 1145 | IPEndpoint::new(pcb.local.address, pcb.local.port) 1146 | }; 1147 | if local.address == IP_ADDR_ANY { 1148 | let interface = contexts 1149 | .ip_routes 1150 | .get_interface(remote.address) 1151 | .expect("TCP: interface was not found."); 1152 | local.address = interface.unicast; 1153 | } 1154 | if local.port == 0 { 1155 | let pcbs = &mut pcbs_arc.lock().unwrap(); 1156 | for port in TCP_SRC_PORT_MIN..TCP_SRC_PORT_MAX { 1157 | local.port = port; 1158 | if pcbs.tcp_pcbs.select(&local, Some(remote)).is_none() { 1159 | break; 1160 | } 1161 | } 1162 | if local.port == 0 { 1163 | panic!("TCP: dynamic port assignment failed."); 1164 | } 1165 | } 1166 | let (sender, receiver) = mpsc::channel(); 1167 | { 1168 | let pcbs = &mut pcbs_arc.lock().unwrap(); 1169 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 1170 | pcb.local.address = local.address; 1171 | pcb.local.port = local.port; 1172 | pcb.remote.address = remote.address; 1173 | pcb.remote.port = remote.port; 1174 | pcb.recv_context.window = PCB_BUF_LEN as u16; 1175 | pcb.iss = rand::thread_rng().gen_range(0..u32::MAX); 1176 | output(pcb, TcpFlag::SYN as u8, vec![], device, contexts); 1177 | // close & release if fails 1178 | pcb.send_context.una = pcb.iss; 1179 | pcb.send_context.next = pcb.iss + 1; 1180 | pcb.state = TcpPcbState::SynSent; 1181 | pcb.sender = Some(sender); 1182 | } 1183 | loop { 1184 | let wakeup = receiver.recv().unwrap(); 1185 | { 1186 | let pcbs = &mut pcbs_arc.lock().unwrap(); 1187 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 1188 | 1189 | if !wakeup { 1190 | pcb.state = TcpPcbState::Closed; 1191 | return None; 1192 | } 1193 | if pcb.state == TcpPcbState::Established { 1194 | break; 1195 | } 1196 | if pcb.state != TcpPcbState::SynReceived { 1197 | pcb.state = TcpPcbState::Closed; 1198 | return None; 1199 | } 1200 | } 1201 | } 1202 | Some(pcb_id) 1203 | } 1204 | 1205 | pub fn bind(pcb_id: usize, local: IPEndpoint, pcbs: &mut ControlBlocks) { 1206 | { 1207 | let existing = pcbs.tcp_pcbs.select(&local, None); 1208 | if existing.is_some() { 1209 | panic!("TCP: ip address and port already exist."); 1210 | } 1211 | } 1212 | let pcb = pcbs 1213 | .tcp_pcbs 1214 | .get_mut_by_id(pcb_id) 1215 | .expect("TCP: PCB with specified id was not found."); 1216 | if pcb.mode != TcpPcbMode::Socket { 1217 | panic!("TCP: PCB was not open in socket mode."); 1218 | } 1219 | pcb.local = local; 1220 | info!( 1221 | "TCP: bound local address = {:?} port = {:?}", 1222 | ip_addr_to_str(pcb.local.address), 1223 | pcb.local.port 1224 | ); 1225 | } 1226 | 1227 | pub fn listen(pcb_id: usize, pcbs: &mut ControlBlocks) { 1228 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 1229 | if pcb.mode != TcpPcbMode::Socket { 1230 | panic!("TCP: PCB was not open in socket mode."); 1231 | } 1232 | pcb.state = TcpPcbState::Listen; 1233 | } 1234 | 1235 | pub fn accept( 1236 | pcb_id: usize, 1237 | remote: &IPEndpoint, 1238 | pcbs_arc: &mut Arc>, 1239 | ) -> Option { 1240 | let (sender, receiver) = mpsc::channel(); 1241 | let mut next_backlog; 1242 | { 1243 | let pcbs = &mut pcbs_arc.lock().unwrap(); 1244 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 1245 | if pcb.mode != TcpPcbMode::Socket { 1246 | panic!("TCP: PCB was not open in socket mode."); 1247 | } 1248 | if pcb.state != TcpPcbState::Listen { 1249 | panic!("TCP: PCB is not in LISTEN state."); 1250 | } 1251 | pcb.sender = Some(sender); 1252 | next_backlog = pcb.backlog.pcb_ids.pop_front(); 1253 | } 1254 | let mut backlog_id = None; 1255 | loop { 1256 | if next_backlog.is_some() { 1257 | if !receiver.recv().unwrap() { 1258 | return None; 1259 | } 1260 | { 1261 | let pcbs = &mut pcbs_arc.lock().unwrap(); 1262 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 1263 | if pcb.state == TcpPcbState::Closed { 1264 | warn!("TCP accept: PCB is in closed state."); 1265 | return None; 1266 | } 1267 | backlog_id = next_backlog; 1268 | next_backlog = pcb.backlog.pcb_ids.pop_front(); 1269 | } 1270 | } else { 1271 | break; 1272 | } 1273 | } 1274 | backlog_id 1275 | } 1276 | 1277 | pub fn send( 1278 | pcb_id: usize, 1279 | data: Vec, 1280 | device: &mut NetDevice, 1281 | contexts: &mut ProtocolContexts, 1282 | pcbs_arc: &mut Arc>, 1283 | ) -> Option { 1284 | let (sender, receiver) = mpsc::channel(); 1285 | let mut sent = 0; 1286 | let mut retry = false; 1287 | let mut pcb_state; 1288 | let mut pcb_send_window; 1289 | let mut pcb_send_next; 1290 | let mut pcb_send_una; 1291 | { 1292 | let pcbs = &mut pcbs_arc.lock().unwrap(); 1293 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 1294 | pcb.sender = Some(sender); 1295 | } 1296 | 1297 | loop { 1298 | { 1299 | let pcbs = &mut pcbs_arc.lock().unwrap(); 1300 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 1301 | pcb_state = pcb.state; 1302 | pcb_send_window = pcb.send_context.window as u32; 1303 | pcb_send_next = pcb.send_context.next; 1304 | pcb_send_una = pcb.send_context.una; 1305 | } 1306 | if pcb_state == TcpPcbState::Closed { 1307 | error!("TCP: connection does not exist."); 1308 | return None; 1309 | } else if pcb_state == TcpPcbState::Listen { 1310 | error!("TCP: this connection is passive."); 1311 | return None; 1312 | } else if pcb_state == TcpPcbState::SynSent || pcb_state == TcpPcbState::SynReceived { 1313 | error!("TCP: insufficient resources."); 1314 | return None; 1315 | } else if pcb_state == TcpPcbState::Established || pcb_state == TcpPcbState::CloseWait { 1316 | let mss = device.mtu - (IP_HEADER_MIN_SIZE + size_of::()); 1317 | let len = data.len(); 1318 | while sent < len { 1319 | let capacity = (pcb_send_window - (pcb_send_next - pcb_send_una)) as usize; 1320 | if capacity < 1 { 1321 | if !receiver.recv().unwrap() { 1322 | return None; 1323 | } 1324 | retry = true; 1325 | break; 1326 | } else { 1327 | let pcbs = &mut pcbs_arc.lock().unwrap(); 1328 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 1329 | let send_len = cmp::min(cmp::min(mss, len - sent), capacity); 1330 | output( 1331 | pcb, 1332 | TcpFlag::ACK as u8 | TcpFlag::PSH as u8, 1333 | data[sent..].to_vec(), 1334 | device, 1335 | contexts, 1336 | ); 1337 | pcb.send_context.next += send_len as u32; 1338 | sent += send_len; 1339 | retry = false; 1340 | } 1341 | } 1342 | if !retry { 1343 | break; 1344 | } 1345 | } else if pcb_state == TcpPcbState::FinWait1 1346 | || pcb_state == TcpPcbState::FinWait2 1347 | || pcb_state == TcpPcbState::Closing 1348 | || pcb_state == TcpPcbState::LastAck 1349 | || pcb_state == TcpPcbState::TimeWait 1350 | { 1351 | warn!("TCP: connection is closing."); 1352 | return None; 1353 | } else { 1354 | warn!("TCP: unknown state."); 1355 | return None; 1356 | } 1357 | } 1358 | Some(sent) 1359 | } 1360 | 1361 | pub fn receive(pcb_id: usize, size: usize, pcbs_arc: Arc>) -> Option> { 1362 | let (sender, receiver) = mpsc::channel(); 1363 | let mut remain = None; 1364 | let mut pcb_state; 1365 | let pcb_buf_len = PCB_BUF_LEN; 1366 | let mut pcb_recv_window; 1367 | { 1368 | let pcbs = &mut pcbs_arc.lock().unwrap(); 1369 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 1370 | pcb.sender = Some(sender); 1371 | pcb_state = pcb.state; 1372 | pcb_recv_window = pcb.recv_context.window as usize; 1373 | } 1374 | 1375 | loop { 1376 | if pcb_state == TcpPcbState::Closed { 1377 | error!("TCP: connection does not exist."); 1378 | return None; 1379 | } else if pcb_state == TcpPcbState::Listen 1380 | || pcb_state == TcpPcbState::SynSent 1381 | || pcb_state == TcpPcbState::SynReceived 1382 | { 1383 | error!("TCP: insufficient resources."); 1384 | return None; 1385 | } else if pcb_state == TcpPcbState::Established 1386 | || pcb_state == TcpPcbState::FinWait1 1387 | || pcb_state == TcpPcbState::FinWait2 1388 | { 1389 | if pcb_recv_window >= pcb_buf_len { 1390 | info!("TCP: sleeping for incoming data..."); 1391 | if !receiver.recv().unwrap() { 1392 | return None; 1393 | } 1394 | let pcbs = &mut pcbs_arc.lock().unwrap(); 1395 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 1396 | pcb_state = pcb.state; 1397 | pcb_recv_window = pcb.recv_context.window as usize; 1398 | remain = Some(pcb_buf_len - pcb_recv_window); 1399 | } else { 1400 | info!("TCP: buffer size > recv.window..."); 1401 | break; 1402 | } 1403 | } else if pcb_state == TcpPcbState::CloseWait { 1404 | if pcb_buf_len > pcb_recv_window { 1405 | remain = Some(pcb_buf_len - pcb_recv_window); 1406 | break; 1407 | } 1408 | break; // fall through 1409 | } else if pcb_state == TcpPcbState::Closing 1410 | || pcb_state == TcpPcbState::LastAck 1411 | || pcb_state == TcpPcbState::TimeWait 1412 | { 1413 | info!("TCP: connection closing."); 1414 | } else { 1415 | warn!("TCP: unknown state."); 1416 | } 1417 | debug!("TCP receive: retrying..."); 1418 | } 1419 | let pcbs = &mut pcbs_arc.lock().unwrap(); 1420 | let pcb = pcb_by_id(&mut pcbs.tcp_pcbs, pcb_id); 1421 | let buf_len = pcb.buf.len(); 1422 | let len = { 1423 | if remain.is_none() { 1424 | cmp::min(buf_len, size) 1425 | } else { 1426 | cmp::min(buf_len, cmp::min(size, remain.unwrap())) 1427 | } 1428 | }; 1429 | let data = pcb.buf[..len].to_vec(); 1430 | pcb.buf = pcb.buf[len..].to_vec(); 1431 | pcb.recv_context.window += len as u16; 1432 | Some(data) 1433 | } 1434 | 1435 | pub fn close( 1436 | pcb_id: usize, 1437 | pcbs: &mut ControlBlocks, 1438 | device: &mut NetDevice, 1439 | contexts: &mut ProtocolContexts, 1440 | ) { 1441 | let pcb_opt = pcbs.tcp_pcbs.get_mut_by_id(pcb_id); 1442 | if pcb_opt.is_some() { 1443 | let pcb = pcb_opt.unwrap(); 1444 | output(pcb, TcpFlag::RST as u8, vec![], device, contexts); 1445 | pcb.release(); 1446 | } 1447 | } 1448 | -------------------------------------------------------------------------------- /src/protocols/ip/udp.rs: -------------------------------------------------------------------------------- 1 | use super::{ControlBlocks, ProtocolContexts}; 2 | use super::{IPAdress, IPEndpoint, IPInterface, IPProtocolType, IP_ADDR_ANY, IP_PAYLOAD_MAX_SIZE}; 3 | use crate::{ 4 | devices::NetDevice, 5 | utils::byte::{be_to_le_u16, le_to_be_u16}, 6 | utils::{bytes_to_struct, cksum16, to_u8_slice}, 7 | }; 8 | use log::{debug, error, info, trace, warn}; 9 | use std::{ 10 | collections::VecDeque, 11 | mem::size_of, 12 | sync::{ 13 | mpsc::{self, Sender}, 14 | Arc, Mutex, 15 | }, 16 | }; 17 | 18 | const UDP_PCB_COUNT: usize = 16; 19 | const UDP_SRC_PORT_MIN: u16 = 49152; 20 | const UDP_SRC_PORT_MAX: u16 = 65535; 21 | 22 | struct PseudoHeader { 23 | src: IPAdress, 24 | dst: IPAdress, 25 | zero: u8, 26 | protocol: u8, 27 | len: u16, 28 | } 29 | 30 | struct UdpHeader { 31 | src_port: u16, 32 | dst_port: u16, 33 | len: u16, 34 | checksum: u16, 35 | } 36 | 37 | // PCB: protocol control block 38 | 39 | #[derive(PartialEq)] 40 | enum UdpPcbState { 41 | Free, 42 | Open, 43 | Closing, 44 | } 45 | 46 | // Protocol control block 47 | pub struct UdpPcb { 48 | state: UdpPcbState, 49 | local_endpoint: IPEndpoint, 50 | pub sender: Option>, 51 | data_entries: VecDeque, 52 | } 53 | 54 | impl UdpPcb { 55 | pub fn new() -> UdpPcb { 56 | UdpPcb { 57 | state: UdpPcbState::Free, 58 | local_endpoint: IPEndpoint { 59 | address: IP_ADDR_ANY, 60 | port: 0, 61 | }, 62 | sender: None, 63 | data_entries: VecDeque::new(), 64 | } 65 | } 66 | } 67 | 68 | pub struct UdpDataEntry { 69 | pub remote_endpoint: IPEndpoint, 70 | pub len: usize, 71 | pub data: Vec, 72 | } 73 | 74 | pub struct UdpPcbs { 75 | pub entries: Vec, 76 | } 77 | 78 | impl UdpPcbs { 79 | pub fn new() -> UdpPcbs { 80 | let mut entries = Vec::with_capacity(UDP_PCB_COUNT); 81 | for _ in 0..UDP_PCB_COUNT { 82 | entries.push(UdpPcb::new()); 83 | } 84 | UdpPcbs { entries } 85 | } 86 | 87 | fn delete_entry(&mut self, pcb_id: usize) { 88 | let mut entry = &mut self.entries[pcb_id]; 89 | 90 | entry.state = UdpPcbState::Closing; 91 | if entry.sender.is_some() { 92 | entry.sender.as_ref().unwrap().send(false).unwrap(); 93 | } 94 | 95 | entry.state = UdpPcbState::Free; 96 | entry.local_endpoint.address = IP_ADDR_ANY; 97 | entry.local_endpoint.port = 0; 98 | entry.data_entries.clear(); 99 | } 100 | 101 | pub fn get_by_id(&self, pcb_id: usize) -> Option<&UdpPcb> { 102 | self.entries.get(pcb_id) 103 | } 104 | 105 | pub fn get_mut_by_id(&mut self, pcb_id: usize) -> Option<&mut UdpPcb> { 106 | self.entries.get_mut(pcb_id) 107 | } 108 | 109 | pub fn get_by_host(&mut self, host_addr: IPAdress, host_port: u16) -> Option<&mut UdpPcb> { 110 | for pcb in self.entries.iter_mut() { 111 | if pcb.state == UdpPcbState::Open { 112 | if (pcb.local_endpoint.address == IP_ADDR_ANY 113 | || host_addr == IP_ADDR_ANY 114 | || pcb.local_endpoint.address == host_addr) 115 | && pcb.local_endpoint.port == host_port 116 | { 117 | return Some(pcb); 118 | } 119 | } 120 | } 121 | None 122 | } 123 | 124 | pub fn is_endpoint_used(&self, host_addr: IPAdress, host_port: u16) -> bool { 125 | for pcb in self.entries.iter() { 126 | if pcb.state == UdpPcbState::Open { 127 | if (pcb.local_endpoint.address == IP_ADDR_ANY 128 | || host_addr == IP_ADDR_ANY 129 | || pcb.local_endpoint.address == host_addr) 130 | && pcb.local_endpoint.port == host_port 131 | { 132 | return true; 133 | } 134 | } 135 | } 136 | false 137 | } 138 | 139 | pub fn close_sockets(&mut self) { 140 | for pcb in self.entries.iter() { 141 | if pcb.sender.is_some() { 142 | pcb.sender.as_ref().unwrap().send(false).unwrap(); 143 | } 144 | } 145 | } 146 | } 147 | 148 | pub fn input( 149 | data: &[u8], 150 | len: usize, 151 | src: IPAdress, 152 | dst: IPAdress, 153 | device: &mut NetDevice, 154 | iface: &IPInterface, 155 | contexts: &mut ProtocolContexts, 156 | pcbs: &mut ControlBlocks, 157 | ) -> Result<(), ()> { 158 | trace!("UDP: received data {:02x?}", data); 159 | 160 | let udp_hdr_size = size_of::(); 161 | let header = unsafe { bytes_to_struct::(data) }; 162 | 163 | let header_len = be_to_le_u16(header.len); 164 | if header_len != len as u16 { 165 | panic!( 166 | "UDP: data length = {:?} and header length = {:?} do not match.", 167 | len, header_len 168 | ); 169 | } 170 | let pseudo_header = PseudoHeader { 171 | src, 172 | dst, 173 | zero: 0, 174 | protocol: IPProtocolType::Udp as u8, 175 | len: header.len, 176 | }; 177 | let pseudo_hdr_bytes = unsafe { to_u8_slice(&pseudo_header) }; 178 | let pseudo_sum = !cksum16(pseudo_hdr_bytes, pseudo_hdr_bytes.len(), 0); 179 | let sum = cksum16(data, len, pseudo_sum as u32); 180 | if sum != 0 { 181 | error!("UDP: input checksum failure: value = {sum}"); 182 | return Err(()); 183 | } 184 | 185 | let pcb_opt = pcbs.udp_pcbs.get_by_host(dst, header.dst_port); 186 | let dst_port = header.dst_port; 187 | if pcb_opt.is_none() { 188 | error!( 189 | "UDP: there is no connection for IP: {:?}:{:?}", 190 | dst, dst_port 191 | ); 192 | return Err(()); 193 | } 194 | 195 | debug!( 196 | "UDP: input source port = {:?} destination port: {:?}", 197 | be_to_le_u16(header.src_port), 198 | be_to_le_u16(header.dst_port) 199 | ); 200 | 201 | let pcb = pcb_opt.unwrap(); 202 | let udp_data = data[udp_hdr_size..].to_vec(); 203 | let remote_endpoint = IPEndpoint { 204 | address: src, // packet source is remote address 205 | port: header.src_port, 206 | }; 207 | let data_entry = UdpDataEntry { 208 | remote_endpoint, 209 | len: len - udp_hdr_size, 210 | data: udp_data, 211 | }; 212 | pcb.data_entries.push_back(data_entry); 213 | 214 | let sender = pcb.sender.as_ref().unwrap(); 215 | sender.send(true).unwrap(); 216 | 217 | Ok(()) 218 | } 219 | 220 | pub fn output( 221 | src: IPEndpoint, 222 | dst: IPEndpoint, 223 | mut udp_data: Vec, 224 | device: &mut NetDevice, 225 | contexts: &mut ProtocolContexts, 226 | pcbs: &mut ControlBlocks, 227 | ) { 228 | info!("UDP: output"); 229 | let udp_hdr_size = size_of::(); 230 | let len = udp_data.len(); 231 | if len > (IP_PAYLOAD_MAX_SIZE - udp_hdr_size) { 232 | panic!("UDP: data too big for output."); 233 | } 234 | let total_len = udp_hdr_size + len; 235 | let total_len_in_be = le_to_be_u16(total_len as u16); 236 | let udp_header = UdpHeader { 237 | src_port: src.port, 238 | dst_port: dst.port, 239 | len: total_len_in_be, 240 | checksum: 0, 241 | }; 242 | let pseudo_hdr = PseudoHeader { 243 | src: src.address, 244 | dst: dst.address, 245 | zero: 0, 246 | protocol: IPProtocolType::Udp as u8, 247 | len: total_len_in_be, 248 | }; 249 | let pseudo_hdr_bytes = unsafe { to_u8_slice(&pseudo_hdr) }; 250 | let pseudo_sum = cksum16(pseudo_hdr_bytes, pseudo_hdr_bytes.len(), 0); 251 | 252 | let udp_hdr_bytes = unsafe { to_u8_slice::(&udp_header) }; 253 | let mut data = udp_hdr_bytes.to_vec(); 254 | data.append(&mut udp_data); 255 | // Update checksum 256 | let sum = cksum16(&data, total_len, !pseudo_sum as u32); 257 | data[6] = ((sum & 0xff00) >> 8) as u8; 258 | data[7] = (sum & 0xff) as u8; 259 | 260 | super::output( 261 | IPProtocolType::Udp, 262 | data, 263 | src.address, 264 | dst.address, 265 | device, 266 | contexts, 267 | ) 268 | .unwrap(); 269 | } 270 | 271 | // Public APIs 272 | 273 | pub fn open(pcbs: &mut UdpPcbs) -> usize { 274 | for (i, entry) in pcbs.entries.iter_mut().enumerate() { 275 | if entry.state == UdpPcbState::Free { 276 | entry.state = UdpPcbState::Open; 277 | return i; 278 | } 279 | } 280 | panic!("UDP: there's no open PCB entry."); 281 | } 282 | 283 | pub fn bind(pcbs: &mut UdpPcbs, pcb_id: usize, local_endpoint: IPEndpoint) { 284 | let existing = pcbs.get_by_host(local_endpoint.address, local_endpoint.port); 285 | if existing.is_some() { 286 | panic!( 287 | "UDP: IP address {:?} & port {:?} is already in use.", 288 | local_endpoint.address, local_endpoint.port 289 | ); 290 | } 291 | info!("UDP: binding host and port..."); 292 | for (i, entry) in pcbs.entries.iter_mut().enumerate() { 293 | if pcb_id == i { 294 | entry.local_endpoint = local_endpoint; 295 | return; 296 | } 297 | } 298 | panic!("UDP: no PCB entry with specified id: {pcb_id}."); 299 | } 300 | 301 | pub fn send_to( 302 | pcb_id: usize, 303 | data: Vec, 304 | remote: IPEndpoint, 305 | device: &mut NetDevice, 306 | contexts: &mut ProtocolContexts, 307 | pcbs: &mut ControlBlocks, 308 | ) { 309 | let pcb = pcbs 310 | .udp_pcbs 311 | .get_by_id(pcb_id) 312 | .expect("UDP: no specified PCB entry for send."); 313 | 314 | // Local address setup in case not set in PCB 315 | let mut local_endpoint = IPEndpoint::new(pcb.local_endpoint.address, 0); 316 | if local_endpoint.address == IP_ADDR_ANY { 317 | let interface = contexts 318 | .ip_routes 319 | .get_interface(remote.address) 320 | .expect("UDP: interface not found for remote address."); 321 | local_endpoint.address = interface.unicast; 322 | } 323 | // Local port setup in case not set in PCB 324 | if pcb.local_endpoint.port == 0 { 325 | for p in UDP_SRC_PORT_MIN..UDP_SRC_PORT_MAX { 326 | let is_used = pcbs.udp_pcbs.is_endpoint_used(local_endpoint.address, p); 327 | if is_used == false { 328 | info!("UDP: assigned a port number: {p}"); 329 | local_endpoint.port = p; 330 | break; 331 | } 332 | } 333 | if local_endpoint.port == 0 { 334 | panic!("UDP: failed to dynamically assign port.") 335 | } 336 | } 337 | 338 | output(local_endpoint, remote, data, device, contexts, pcbs) 339 | } 340 | 341 | pub fn receive_from(pcb_id: usize, pcbs_arc: Arc>) -> Option { 342 | let (sender, receiver) = mpsc::channel(); 343 | { 344 | let pcbs = &mut pcbs_arc.lock().unwrap(); 345 | let pcb = pcbs 346 | .udp_pcbs 347 | .get_mut_by_id(pcb_id) 348 | .expect("UDP: no specified PCB entry for receive."); 349 | 350 | pcb.sender = Some(sender); 351 | } 352 | 353 | loop { 354 | if !receiver.recv().unwrap() { 355 | return None; 356 | } 357 | 358 | { 359 | let mut pcbs = pcbs_arc.lock().unwrap(); 360 | let pcb = pcbs 361 | .udp_pcbs 362 | .get_mut_by_id(pcb_id) 363 | .expect("UDP: no specified PCB entry for receive."); 364 | 365 | if pcb.state != UdpPcbState::Open { 366 | warn!("UDP: PCB got closed for receive."); 367 | return None; 368 | } 369 | return pcb.data_entries.pop_front(); 370 | } 371 | } 372 | } 373 | -------------------------------------------------------------------------------- /src/protocols/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod arp; 2 | pub mod ip; 3 | 4 | use self::{ 5 | arp::ArpTable, 6 | ip::{tcp::TcpPcbs, udp::UdpPcbs, IPHeaderIdManager, IPRoutes}, 7 | }; 8 | use crate::{ 9 | devices::{NetDevice, NetDevices}, 10 | utils::list::List, 11 | }; 12 | use log::{info, trace}; 13 | use std::{collections::VecDeque, sync::Arc}; 14 | 15 | #[derive(PartialEq, Debug)] 16 | pub enum ProtocolType { 17 | Arp = 0x0806, 18 | IP = 0x0800, 19 | // IPV6 = 0x86dd, 20 | Unknown, 21 | } 22 | 23 | impl ProtocolType { 24 | pub fn from_u16(value: u16) -> ProtocolType { 25 | match value { 26 | 0x0800 => ProtocolType::IP, 27 | 0x0806 => ProtocolType::Arp, 28 | _ => ProtocolType::Unknown, 29 | } 30 | } 31 | } 32 | 33 | pub struct ProtocolData { 34 | irq: i32, 35 | data: Option>>, // accessed from input/output threads for loopback 36 | len: usize, 37 | } 38 | 39 | impl ProtocolData { 40 | pub fn new(irq: i32, data: Option>>, len: usize) -> ProtocolData { 41 | ProtocolData { irq, data, len } 42 | } 43 | } 44 | 45 | pub struct NetProtocol { 46 | pub protocol_type: ProtocolType, 47 | pub input_head: VecDeque, 48 | } 49 | 50 | impl NetProtocol { 51 | pub fn new(t: ProtocolType) -> NetProtocol { 52 | NetProtocol { 53 | protocol_type: t, 54 | input_head: VecDeque::new(), 55 | } 56 | } 57 | 58 | /// Calls input handler for all data till a queue is empty. 59 | pub fn handle_input( 60 | &mut self, 61 | // proto_stack: &mut ProtocolStack, 62 | devices: &mut NetDevices, 63 | contexts: &mut ProtocolContexts, 64 | pcbs: &mut ControlBlocks, 65 | ) { 66 | loop { 67 | if self.input_head.is_empty() { 68 | break; 69 | } 70 | let proto_data = self.input_head.pop_front().unwrap(); 71 | let data = proto_data.data.unwrap(); 72 | let len = proto_data.len; 73 | 74 | // let devices = proto_stack.devices.lock().unwrap(); 75 | for device in devices.entries.iter_mut() { 76 | if device.irq_entry.irq == proto_data.irq { 77 | self.input(data.as_slice(), len, device, contexts, pcbs); 78 | break; 79 | } 80 | } 81 | } 82 | } 83 | 84 | /// Handles input data per a protocol type. 85 | pub fn input( 86 | &self, 87 | data: &[u8], 88 | len: usize, 89 | device: &mut NetDevice, 90 | contexts: &mut ProtocolContexts, 91 | pcbs: &mut ControlBlocks, 92 | ) { 93 | // let parsed = u32::from_be_bytes(data.as_slice()); 94 | info!("Protocol: ----Start of Input----"); 95 | match self.protocol_type { 96 | ProtocolType::Arp => { 97 | trace!("Protocol: ARP | Received: {:02x?}", data); 98 | arp::input(data, len, device, contexts).unwrap(); 99 | } 100 | ProtocolType::IP => { 101 | trace!("Protocol: IP | Received: {:02x?}", data); 102 | ip::input(data, len, device, contexts, pcbs).unwrap(); 103 | } 104 | ProtocolType::Unknown => { 105 | trace!("Protocol: Unknown | Received: {:x?}", data); 106 | } 107 | } 108 | info!("Protocol: ----End of Input----\n") 109 | } 110 | } 111 | 112 | pub struct NetProtocols { 113 | pub entries: List, 114 | } 115 | 116 | impl NetProtocols { 117 | pub fn new() -> NetProtocols { 118 | NetProtocols { 119 | entries: List::::new(), 120 | } 121 | } 122 | 123 | pub fn register(&mut self, protocol: NetProtocol) { 124 | self.entries.push(protocol); 125 | } 126 | 127 | pub fn handle_data( 128 | &mut self, 129 | devices: &mut NetDevices, 130 | contexts: &mut ProtocolContexts, 131 | pcbs: &mut ControlBlocks, 132 | ) { 133 | for protocol in self.entries.iter_mut() { 134 | protocol.handle_input(devices, contexts, pcbs); 135 | } 136 | } 137 | } 138 | pub struct ProtocolContexts { 139 | pub arp_table: ArpTable, 140 | pub ip_routes: IPRoutes, 141 | pub ip_id_manager: IPHeaderIdManager, 142 | } 143 | 144 | pub struct ControlBlocks { 145 | pub udp_pcbs: UdpPcbs, 146 | pub tcp_pcbs: TcpPcbs, 147 | } 148 | 149 | impl ControlBlocks { 150 | pub fn new() -> ControlBlocks { 151 | ControlBlocks { 152 | udp_pcbs: UdpPcbs::new(), 153 | tcp_pcbs: TcpPcbs::new(), 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/utils/byte.rs: -------------------------------------------------------------------------------- 1 | const TARGET_BIG_ENDIAN: bool = cfg!(target_endian = "big"); 2 | 3 | fn byte_swap_u16(v: u16) -> u16 { 4 | (v & 0x00ff) << 8 | (v & 0xff00) >> 8 5 | } 6 | 7 | fn byte_swap_u32(v: u32) -> u32 { 8 | (v & 0x000000ff) << 24 | (v & 0x0000ff00) << 8 | (v & 0x00ff0000) >> 8 | (v & 0xff000000) >> 24 9 | } 10 | 11 | /// Converts big endian u16 to little endian if a target is a little endian machine. 12 | pub fn be_to_le_u16(v: u16) -> u16 { 13 | if TARGET_BIG_ENDIAN { 14 | return v; 15 | } 16 | byte_swap_u16(v) 17 | } 18 | 19 | /// Converts little endian u16 to big endian if a target is a little endian machine. 20 | pub fn le_to_be_u16(v: u16) -> u16 { 21 | if TARGET_BIG_ENDIAN { 22 | return v; 23 | } 24 | byte_swap_u16(v) 25 | } 26 | 27 | /// Converts big endian u32 to little endian if a target is a little endian machine. 28 | pub fn be_to_le_u32(v: u32) -> u32 { 29 | if TARGET_BIG_ENDIAN { 30 | return v; 31 | } 32 | byte_swap_u32(v) 33 | } 34 | 35 | /// Converts little endian u32 to big endian if a target is a little endian machine. 36 | pub fn le_to_be_u32(v: u32) -> u32 { 37 | if TARGET_BIG_ENDIAN { 38 | return v; 39 | } 40 | byte_swap_u32(v) 41 | } 42 | -------------------------------------------------------------------------------- /src/utils/list.rs: -------------------------------------------------------------------------------- 1 | type Link = Option>>; 2 | struct Node { 3 | elem: T, 4 | next: Link, 5 | } 6 | pub struct List { 7 | head: Link, 8 | } 9 | 10 | pub struct Iter<'a, T> { 11 | next: Option<&'a Node>, 12 | } 13 | 14 | impl<'a, T> Iterator for Iter<'a, T> { 15 | type Item = &'a T; 16 | fn next(&mut self) -> Option { 17 | self.next.map(|node| { 18 | self.next = node.next.as_deref(); 19 | &node.elem 20 | }) 21 | } 22 | } 23 | 24 | pub struct IterMut<'a, T> { 25 | next: Option<&'a mut Node>, 26 | } 27 | 28 | impl<'a, T> Iterator for IterMut<'a, T> { 29 | type Item = &'a mut T; 30 | fn next(&mut self) -> Option { 31 | self.next.take().map(|node| { 32 | self.next = node.next.as_deref_mut(); 33 | &mut node.elem 34 | }) 35 | } 36 | } 37 | 38 | impl List { 39 | pub fn new() -> Self { 40 | List { head: None } 41 | } 42 | 43 | pub fn push(&mut self, elem: T) { 44 | let new_node = Box::new(Node { elem, next: None }); 45 | let mut head = self.head.as_mut(); 46 | if head.is_none() { 47 | self.head = Some(new_node); 48 | return; 49 | } 50 | while head.is_some() { 51 | let node = head.unwrap(); 52 | if node.next.is_none() { 53 | node.next = Some(new_node); 54 | break; 55 | } 56 | head = node.next.as_mut(); 57 | } 58 | } 59 | 60 | pub fn iter(&self) -> Iter<'_, T> { 61 | Iter { 62 | next: self.head.as_deref(), 63 | } 64 | } 65 | 66 | pub fn iter_mut(&mut self) -> IterMut<'_, T> { 67 | IterMut { 68 | next: self.head.as_deref_mut(), 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod byte; 2 | pub mod list; 3 | 4 | /// Converts a struct to u8 slice. 5 | pub unsafe fn to_u8_slice(p: &T) -> &[u8] { 6 | ::std::slice::from_raw_parts((p as *const T) as *const u8, ::std::mem::size_of::()) 7 | } 8 | 9 | /// Converts u8 slice to a struct. 10 | pub unsafe fn bytes_to_struct(b: &[u8]) -> T { 11 | let s: T = std::ptr::read(b.as_ptr() as *const _); 12 | s 13 | } 14 | 15 | pub fn cksum16(data: &[u8], len: usize, init: u32) -> u16 { 16 | let mut i = 0; 17 | let mut len = len; 18 | let mut sum = init; 19 | 20 | // Add by 16 bit blocks 21 | while len > 1 { 22 | sum += ((data[i] as u16) << 8 | (data[i + 1] as u16)) as u32; 23 | len -= 2; 24 | i += 2; 25 | } 26 | if len > 0 { 27 | sum += ((data[i] as u16) << 8) as u32 28 | } 29 | // Add overflowed value 30 | while (sum >> 16) != 0 { 31 | sum = (sum & 0xffff) + (sum >> 16); 32 | } 33 | !(sum as u16) // return NOT value 34 | } 35 | 36 | #[cfg(test)] 37 | mod test { 38 | use super::list::List; 39 | 40 | #[test] 41 | fn test_list() { 42 | let mut list = List::new(); 43 | list.push(1); 44 | list.push(2); 45 | list.push(3); 46 | let mut iteration = list.iter(); 47 | assert_eq!(iteration.next(), Some(&1)); 48 | assert_eq!(iteration.next(), Some(&2)); 49 | assert_eq!(iteration.next(), Some(&3)); 50 | } 51 | } 52 | --------------------------------------------------------------------------------