{"id":22296778,"url":"https://github.com/webklex/romb","last_synced_at":"2025-03-25T22:41:07.048Z","repository":{"id":71428110,"uuid":"455648341","full_name":"Webklex/romb","owner":"Webklex","description":null,"archived":false,"fork":false,"pushed_at":"2022-02-05T15:45:10.000Z","size":20,"stargazers_count":7,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-30T19:55:51.197Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Webklex.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-04T18:05:53.000Z","updated_at":"2022-02-09T09:48:08.000Z","dependencies_parsed_at":"2023-03-11T10:31:13.013Z","dependency_job_id":null,"html_url":"https://github.com/Webklex/romb","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Webklex%2Fromb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Webklex%2Fromb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Webklex%2Fromb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Webklex%2Fromb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Webklex","download_url":"https://codeload.github.com/Webklex/romb/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245556961,"owners_count":20634888,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-03T17:47:38.898Z","updated_at":"2025-03-25T22:41:07.025Z","avatar_url":"https://github.com/Webklex.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ROMB - Rust bomb\nSounds more dramatic than it is...\n\n# How I tried to learn rust in 6 days\n\n## Prolog\nI'm usually creating web apps with php, js, go or python. I've played around with\nC, C++ and C# but never used them in a bigger project.\n\nSo why rust? I've heard a lot of people talk about it. It's supposed to be pretty fast\nand provides some additional features which, regarding app security, are great as well.\nAt the end [d0nutptr](https://github.com/d0nutptr) motivated me to participate in his\n[giveaway/challenge](https://twitter.com/d0nutptr/status/1487259366524817410).\n\n## Scope \u0026 Description\nI recently thought about what would happen if you try to race against a firewall / IDS; Are they \nfast enough, or could you \"squeeze\" in a bunch of request before the client gets blocked? \nBasically a one-shot port scan.\n\nThis application will scan a port range of a given target simultaneously, in an attempt to race \nagainst a firewall IDS. The result can be saved or printed as csv, json or xml.\n\n### The application should:\n- Spawn a new thread for each port to be scanned\n- Thread is halted until all threads are ready\n- All threads are released as soon as the last thread is ready\n- A \"Scan thread\" should do nothing besides connecting to a given port after it has been released\n- Accept command line arguments to configure the target and port range\n\n### Nice to have:\n- Export open ports as json, xml or txt file\n- Possibility to use UDP instead of TCP\n- If a port is considered open, check if any response is returned\n\n# Result \u0026 Conclusion\nWell the time has come to an end. I had a lot of plans and even though I failed to realize all of them,\nI'm still a bit proud of having realized at least the core feature (port check). This might not sound\nlike much but for my first steps at rust, I'm pretty happy with it :)\n\nThe exports and udp / response filtering support is still missing, the code isn't cleaned up and the\n`Options` are never used. Oh and you can't spawn more than ~16337 threads - I still haven't figured out\nwhy that's the case.\n\nI spend the most time trying to understand how `Response` works and how to handle errors. I'm still\nnot fully sure, but I feel comfortable to play around with them some more.\nRust definitely isn't like any other language I've played around with.\nIt is extremely strict, has a unique logic and app \"life cycle\". \n\nHave I failed my quest? Yes and no, the application isn't finished but my second goal, to learn some \nrust was a success!\n\nI tried to document my journey and took some notes along the way. Those are all listed below under \n**Timeline**.\n\n## Timeline\n### 1. Development / IDE setup\n- Searched for \"rust install\"\n    - https://www.rust-lang.org/tools/install\n- Searching for an IDE\n    - https://www.rust-lang.org/tools\n    - Decided to use \"CLion\" (30-day trial version)\n        - https://www.jetbrains.com/clion/\n        - Installed the Rust plugin\n            - https://plugins.jetbrains.com/plugin/8182-rust\n- Like always, lets google for a \"Hello World\" example\n    - https://doc.rust-lang.org/rust-by-example/hello.html\n- Tested \"Hello World\" and made sure everything works as expected\n\n### 2. Created a new rust project inside the IDE\n- This created a folder in my projects directory:\n    - Cargo.lock\n    - Cargo.toml\n    - src/main.rs\n- running `cargo run` looks good:\n```\n   Compiling rust_test v0.1.0 (/mnt/raid1/projects/rust_test)\n    Finished dev [unoptimized + debuginfo] target(s) in 0.52s\n     Running `target/debug/rust_test`\nHello, world!\n```\n\n### 3. Build the application\n- Developing the actual application and gather some information on how this can be accomplished.\n- I'll like to use something like objects or structs\n    - Searching for \"rust structs\" brought up some interesting results:\n        - https://doc.rust-lang.org/book/ch05-01-defining-structs.html\n        - Nice, also an example project! https://doc.rust-lang.org/book/ch05-02-example-structs.html\n- I'll need to thread all potential port checks\n    - Searching for \"rust threading\"\n        - https://doc.rust-lang.org/book/ch16-01-threads.html\n- I want to \"hold\" the thread until all threads are ready. I know of \"WaitGroups\" from golang. So perhaps they exist in rust as well?\n    - Searching for \"rust waitgroup\"\n        - This seems to be like what I'm looking for... https://docs.rs/crossbeam/0.5.0/crossbeam/sync/struct.WaitGroup.html\n            - References https://doc.rust-lang.org/std/sync/struct.Barrier.html\n            - \"Barrier\" looks like what I want. I'll know the number of potential threads so this should be fine\n- I used the provided examples and created a first simple program\n    - Got hooked on a Question; Using the \"Barrier\" example and going over the documentation I couldn't figure out at which point the `c.wait();` lock would release\n        - I've decided to put a sleep command before and after the `c.wait();` lock and watched the behavior\n            - https://doc.rust-lang.org/std/thread/fn.sleep.html\n            - The `c.wait();` lock is released as soon as the \"last\" thread got pushed into the \"Barrier Arc\"\n    - Great it works. I can spawn a dynamic number of threads, hold them until they are all \"initialized\", continue them and wait until they've all run.\n- Next I'll need to make some structs\n    - Where do I place them? In their own file, inside a new directory?\n        - Decided to use a new file called \"scanner.rs\"\n            - Created a struct called `Scanner`\n                - What's the correct type for and unsigned integer? The port is always \u003e= 0\n                    - Searching \"rust unsigned int\"\n                        - https://doc.rust-lang.org/book/ch03-02-data-types.html\n                        - `u16` seems to be the type I'm looking for\n```rust\nuse std::sync::{Arc, Barrier};\nuse std::thread::JoinHandle;\nuse std::time::Duration;\n\nstruct Scanner {\n   handles: Vec\u003cJoinHandle\u003c()\u003e\u003e,\n   barrier: Arc\u003cBarrier\u003e,\n\n   target: String,\n   start_port: u16,\n   max_port: u16,\n   timeout: Duration\n}\n```\n- The Scanner struct now need to have some methods\n    - Searching for \"rust struct methods\"\n        - https://doc.rust-lang.org/book/ch05-03-method-syntax.html\n        - `impl StructName` is the magic syntax\n    - Turns out you have to use `\u0026mut self` instead of `self` if the method \"mutates?\" / updates an attribute\n    - `pub(crate)` in front of a function makes it accessible outside the file\n- The scanner might need some options, so I added a new struct called `Options` and added it to the Scanner\n```rust\nstruct Options {\n    pub response: bool, // Check if the connection returns any bytes\n    pub udp: bool,      // use udp\n    pub tcp: bool       // use tcp\n}\n```\n- How are getters and setters handled?\n    - Searching for \"rust getter setter convention\"\n        - https://users.rust-lang.org/t/idiomatic-naming-for-getters-setters/3581\n            - `set_attribute_name(attr: Type)` and `attribute_name() -\u003e Type` for the getter\n        - https://www.reddit.com/r/rust/comments/65ud89/how_to_name_setters_and_getters_when_a_struct_can/\n            - There is an \"auto builder\"?\n                - https://docs.rs/derive_builder/0.4.4/derive_builder/\n                - Looks easy to implement.\n```rust\n#[derive(Builder)]\npub(crate) struct Options {\n    pub response: bool, // Check if the connection returns any bytes\n    pub udp: bool,      // use udp\n    pub tcp: bool       // use tcp\n}\n```\n- Putting everything together:\n```rust\nfn main() {\n    let target = String::from(\"somedomain.tld\");\n    let opt = scanner::Options::default().udp(false).tcp(true).response(false).build().unwrap();\n\n    let mut s = scanner::build_scanner(opt);\n    s.set_target(target);\n    s.set_port_range(0, 65535);\n    s.set_timeout(Duration::from_secs(10));\n}\n```\n- The next steps will require some error and \"response\" handling\n- How are errors handled?\n    - Searching for \"rust error handling\"\n        - https://doc.rust-lang.org/book/ch09-00-error-handling.html\n            - Well, that was underwhelming\n        - https://www.sheshbabu.com/posts/rust-error-handling/\n            - Error / response handling works differently than expected\n            - Custom error structs not required in an application project but a nice to have\n            - Response is always an enum (OK, Error)\n            - Error can be an enum of many error types\n            - There is a \"?\" operator which is a bit magic but seems to return the error if it occurred\n            - Where do you handle the errors? Are all errors handled within main or along the way?\n                - Depends on the use case - if the error is recoverable, then handle the error in between\n            - Using `Box\u003cdyn std::error::Error\u003e` many errors can be returned / handled\n                - Searching for \"rust Box\u003cdyn\"\n                    - https://doc.rust-lang.org/rust-by-example/trait/dyn.html\n                        - A \"Box\" is just a reference to some function\n            - Custom errors can be implemented via enums\n- How is `match` correctly used?\n    - Searching for \"rust match\"\n        - https://doc.rust-lang.org/rust-by-example/flow_control/match.html\n            - It's basically a switch statement with magic\n            - Returns the assigned value\n- Time to run the code and see what's getting thrown\n- Getting error \"error: cannot find derive macro `Builder` in this scope\"\n    - Searching \"error: cannot find derive macro `Builder` in this scope\"\n    - Searching for \"rust derive(Builder)\"\n        - https://docs.rs/derive_builder/latest/derive_builder/\n        - Dependency and macro wasn't set\n- Getting error \"error[E0468]: an `extern crate` loading macros must be at the crate root\"\n    - https://stackoverflow.com/questions/39175953/how-do-you-import-macros-in-submodules-in-rust\n        - `extern crate derive_builder;` has to be placed within the main.rs\n        - `derive_builder` dependency was missing inside the Cargo.toml file\n- Searching \"rust getters and setters struct\"\n    - https://stackoverflow.com/questions/35390615/writing-getter-setter-properties-in-rust\n        - Looks like setters work a bit different - update the attribute pointer instead of updating the attribute itself\n- Get error \"cannot move out of `*self` which is behind a mutable reference\"\n    - Searching for \"cannot move out of `*self` which is behind a mutable reference\"\n        - Happens if you move literal inside an implementation and switch between mut and simple methods\n    - CLI help `rustc --explain E0507`\n    - Combining the questionable method with the one using it. Problem solved :)\n- Refactoring the Options struct and the main method to implement the recent changes\n```rust\n#[derive(Default)]\npub(crate) struct Options {\n  pub response: bool,\n  // Check if the connection returns any bytes\n  pub udp: bool,\n  // use udp\n  pub tcp: bool, // use tcp\n}\n```\n```rust\nfn main() {\n    let target = String::from(\"somedomain.tld\");\n\n    let mut opt = scanner::build_options();\n    *opt.udp_mut() = false;\n    *opt.tcp_mut() = false;\n    *opt.response_mut() = false;\n\n    let mut s = scanner::build_scanner(opt);\n    s.set_target(target);\n    s.set_port_range(0, 65535);\n    s.set_timeout(Duration::from_secs(10));\n\n    match s.start() {\n        Ok(()) =\u003e println!(\"Completed\"),\n        Err(e) =\u003e {\n            match e {\n                ScannerError::InvalidPortRange =\u003e println!(\"Scanner error: {}\", e),\n            }\n        }\n    };\n}\n```\n- Getting a stack overflow error\n    - Using `RUST_BACKTRACE=1 cargo run` can be used to get additional information\n        - `RUST_BACKTRACE=full` provides even more detail\n- Searching for \"thread '\u003cunnamed\u003e' panicked at 'failed to allocate an alternative stack\"\n    - https://github.com/rust-lang/rust/issues/78497\n        - Looks like I'm not the first who wants to spawn up to 65530 threads\n            - It's not going to happen?\n- Searching for \"rust spawn thousands of threads\"\n    - https://stackoverflow.com/questions/49573335/what-is-the-maximum-number-of-threads-a-rust-program-can-spawn\n        - https://stackoverflow.com/questions/344203/maximum-number-of-threads-per-process-in-linux\n            - Max number of threads can be determined under linux with this command: `cat /proc/sys/kernel/threads-max`\n                - Returns `255609` - So this isn't the problem\n- Keeps crashing at ~16337 spawned threads\n    - Checking my available ram `free -h`\n```\n              total        used        free      shared  buff/cache   available\nMem:           31Gi        22Gi       1,4Gi       312Mi       7,5Gi       8,2Gi\nSwap:          11Gi        46Mi        11Gi\n```\n- Killed Firefox:\n```\n              total        used        free      shared  buff/cache   available\nMem:           31Gi        14Gi       9,2Gi       266Mi       7,5Gi        15Gi\nSwap:          11Gi        46Mi        11Gi\n```\n- Still can't spawn more threads\n- How many threads are currently being executed by the system?\n    - Looking at htop revels ~2400\n- Searching for `rust failed to spawn thread \"Resource temporarily unavailable\"`\n    - https://github.com/rust-lang/rust/issues/46345\n        - Introducing a delay doesn't work `thread::sleep(Duration::from_millis(1))`\n    - https://github.com/rust-lang/rust/issues/77894\n        - There might be something like a process limit\n            - Searching for \"rust process limit\"\n                - Nothing interesting comes up\n    - https://unix.stackexchange.com/questions/253903/creating-threads-fails-with-resource-temporarily-unavailable-with-4-3-kernel\n        - https://www.freedesktop.org/software/systemd/man/systemd.resource-control.html#TasksMax=N\n            - There might be some os limitations in place\n            - Is `TasksMax` set in my environment?\n                - `cat /etc/systemd/system.conf | grep \"TasksMax\"` returns a disabled config parameter \"#DefaultTasksMax=\"\n                - `cat /etc/systemd/user.conf | grep \"TasksMax\"` returns nothing\n                - What's the default value if it isn't set?\n                    - \"freedesktop\" links to https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/pids.html which doesn't reveal anything\n                    - https://www.freedesktop.org/software/systemd/man/systemd-system.conf.html#\n                        - 4915 is the default - which seems odd, since I was able to spawn ~16337 threads\n                            - Ahh the default isn't always 4915 - only sometimes..\n- Searching for \"rust spawn threads\"\n    - https://doc.rust-lang.org/std/thread/fn.spawn.html\n        - A Channel might help?\n            - No it can't help, since I can't keep it alive and monitor its incoming messages\n        - https://doc.rust-lang.org/std/thread/struct.Builder.html#method.spawn\n            - Perhaps a custom builder helps..\n            - ..no it doesn't. The problem persists.\n            - \u003e Limiting myself to fewer threads inorder to be able to continue\n- Searching for \"rust send tcp packet\"\n    - https://doc.rust-lang.org/std/net/struct.TcpStream.html\n        - Looks simple enough but perhaps unnecessary overhead?\n        - I suspect this would limit the app to only do ACK checks\n- How can you implement `std::io::Error` inside the `ScannerError`?\n    - Searching for \"rust implement std::io::Error\"\n        - https://stevedonovan.github.io/rust-gentle-intro/6-error-handling.html\n- Searching for \"rust resolve host to ip\"\n    - https://doc.rust-lang.org/std/net/trait.ToSocketAddrs.html\n- Getting error \"expected struct `Vec`, found struct `std::io::Error`\"\n    - Searching for \"expected struct `Vec`, found struct `std::io::Error`\"\n        - https://stackoverflow.com/questions/62417235/expected-enum-stdresultresult-found-struct-stdvecvec\n- Getting error \"could not find `time` in `tokio`\"\n    - Searching for \"could not find `time` in `tokio`\"\n        - https://users.rust-lang.org/t/could-not-find-time-in-tokio-0-2-10/37533\n            - \"time\" is a feature that has to be loaded / included within the \"Cargo.toml\" file\n- Searching for \"rust timeout tcp stream\"\n    - https://stackoverflow.com/questions/30022084/how-do-i-set-connect-timeout-on-tcpstream\n        - `tokio::time::timeout` provides this feature\n- Getting the error \"`Result\u003cstd::net::TcpStream, std::io::Error\u003e` is not a future\" after implementing the timeout\n    - Searching for \"`Result\u003cstd::net::TcpStream, std::io::Error\u003e` is not a future\"\n    - Getting the hint \"help: the trait `Future` is not implemented for `Result\u003cstd::net::TcpStream, std::io::Error\u003e`\"\n        - What is \"trait `Future`\"?\n            - Searching for \"rust trait `Future`\"\n                - https://doc.rust-lang.org/std/future/trait.Future.html\n                    - Something with async function results / await\n                    - Result polling instead of... ?\n    - Searching for \"the trait `Future` is not implemented for `Result\u003cstd::net::TcpStream, std::io::Error\u003e`\"\n    - `match tokio::time::timeout(self.timeout, TcpStream::connect(\u0026target)).await` inside a thread isn't working because some `Future` is missing\n        - required because of the requirements on the impl of `Future` for `tokio::time::Timeout\u003cResult\u003cstd::net::TcpStream, std::io::Error\u003e\u003e` what ever that's supposed to mean\n    - Searching for \"rust required by this bound in `timeout`\"\n        - https://www.reddit.com/r/rust/comments/ejkf3w/asyncstd_timeout_with_custom_error_types_question/\n            - block_on doesn't seem to work in this combination either\n    - CLI help `rustc --explain E0277`\n        - Not really helpful - types mismatch, but why does it want a \"Future\"?\n- Searching for \"rust tokio timeout tcpstream future\"\n    - https://fasterthanli.me/articles/understanding-rust-futures-by-going-way-too-deep\n        - Dependencies can be added by calling `cargo add dependency_name@version`\n- Searching for \"rust tokio::time::timeout with TcpStream::connect\"\n    - https://docs.rs/tokio-postgres/0.5.0-alpha.1/i686-apple-darwin/src/tokio_postgres/connect_socket.rs.html\n- Checked the TcpStream::connect source code and found the method `connect_timeout`\n    - Removed tokio and switched to this one\n        - Getting error \" `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement\"\n            - The timeout has been moved into a new variable `let timeout = self.timeout;` this fixes the issue\n- Searching for \"rust cli arguments\"\n    - https://doc.rust-lang.org/book/ch12-01-accepting-command-line-arguments.html\n        - Basic argument parsing\n    - https://github.com/clap-rs/clap\n        - Advanced parsing, perhaps a bit overpowered\n        - Searching for \"rust clap cli example\"\n            - https://rustrepo.com/repo/clap-rs-clap-rust-command-line\n                - The Builder seems about perfect\n                - To run `cargo run` with arguments, you have to appended \"--\" and use it like this: \"cargo run -- --max_port 25 --start_port 20 target.tld\"\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebklex%2Fromb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebklex%2Fromb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebklex%2Fromb/lists"}