Compare commits

..
5 Commits
Author SHA1 Message Date
Brandon 7cb23de82f fixed merge conflicts 2020-10-18 12:54:59 +01:00
Brandon 3783d04d12 added readme 2020-10-18 12:53:32 +01:00
Brandon 5f208d29e0 added readme 2020-10-18 12:53:08 +01:00
Oskar f854b400c3 Merge branch 'master' into scripting-tests 2020-10-17 19:32:28 +02:00
okrplay bd222eeb1c Add tests for rustscan scripting engine (#286) 2020-10-17 19:18:32 +02:00
22 changed files with 602 additions and 804 deletions

No files matched your search

+25 -3
View File
@@ -13,9 +13,9 @@ jobs:
profile: minimal
toolchain: stable
override: true
# - uses: actions-rs/cargo@v1
# with:
# command: check
- uses: actions-rs/cargo@v1
with:
command: check
test:
name: Test Suite
@@ -46,3 +46,25 @@ jobs:
with:
command: fmt
args: --all -- --check
clippy:
name: Clippy linting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
components: clippy
override: true
- uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --all-features
links:
name: markdown-link-check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: gaurav-nelson/github-action-markdown-link-check@v1
+15
View File
@@ -0,0 +1,15 @@
on:
push:
tags: '*'
jobs:
homebrew:
name: Bump Homebrew formula
runs-on: ubuntu-latest
steps:
- uses: mislav/bump-homebrew-formula-action@v1
with:
# A PR will be sent to github.com/Homebrew/homebrew-core to update this formula:
formula-name: rustscan
env:
COMMITTER_TOKEN: ${{secrets.brew}}
Generated
+392 -391
View File
File diff suppressed because it is too large. Load diff
+8 -8
View File
@@ -1,7 +1,7 @@
[package]
name = "rustscan"
version = "2.1.1"
authors = ["Autumn <autum[email protected]>"]
version = "1.10.0"
authors = ["Bee <brando[email protected]>"]
edition = "2018"
description = "Faster Nmap Scanning with Rust"
homepage = "https://github.com/rustscan/rustscan"
@@ -19,24 +19,24 @@ exclude = [
[dependencies]
colored = "2.0.0"
structopt = "0.3.20"
async-std = "1.7.0"
async-std = "1.6.4"
futures = "0.3"
rlimit = "0.8.3"
rlimit = "0.5.2"
shell-words = "1.0.0"
log = "0.4.0"
env_logger = "0.8.2"
env_logger = "0.7.1"
dirs = "3.0.1"
gcd = "2.0.1"
rand = "0.7.3"
colorful = "0.2.1"
ansi_term = "0.12.1"
toml = "0.5.7"
serde = "1.0.124"
serde = "1.0.117"
serde_derive = "1.0.116"
cidr-utils = "0.5.1"
cidr-utils = "0.5.0"
itertools = "0.9.0"
trust-dns-resolver = { version = "0.19.5", features = ["dns-over-rustls"] }
anyhow = "1.0.40"
anyhow = "1.0.33"
subprocess = "0.2.6"
text_placeholder = { version = "0.4", features = ["struct_context"] }
+11 -25
View File
@@ -1,6 +1,6 @@
<p align="center">
➡️
<a href="http://discord.skerritt.blog">Discord</a> |
<a href="https://discord.gg/GFrQsGy">Discord</a> |
<a href="https://github.com/RustScan/RustScan/wiki/Installation-Guide">Installation Guide</a> |
<a href="https://github.com/RustScan/RustScan#-usage">Usage Guide</a>
⬅️
@@ -15,7 +15,7 @@
<img src="https://img.shields.io/badge/Built%20with-Rust-Purple">
<img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/rustscan/rustscan/total?label=GitHub%20Downloads">
<img alt="Crates.io" src="https://img.shields.io/crates/d/rustscan?label=Cargo%20Downloads">
<img alt="Discord" src="https://img.shields.io/discord/754001738184392704">
<img alt="Discord" src="https://img.shields.io/discord/736614461313515576">
<img alt="Actions" src="https://github.com/RustScan/RustScan/workflows/Continuous%20integration/badge.svg?branch=master">
</p>
<hr>
@@ -23,14 +23,12 @@
| <p align="center"><a href="https://hub.docker.com/r/cmnatic/rustscan">🐋 Docker (Recommended) </a></p> | <p align="center"><a href="https://github.com/RustScan/RustScan/releases">👩‍💻 Kali / Debian </p> | <p align="center"><a href="https://aur.archlinux.org/packages/rustscan/">🏗️ Arch </a></p> | <p align="center"><a href="https://crates.io/crates/rustscan">🔧 Homebrew </a></p> |
| ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| <p align="center"><img src="https://github.com/RustScan/RustScan/blob/master/pictures/docker.png?raw=true" /></p> | <p align="center"><img src="https://github.com/RustScan/RustScan/blob/master/pictures/kali.png?raw=true" /></p> | <p align="center"><img src="https://github.com/RustScan/RustScan/blob/master/pictures/arch.png?raw=true" /></p> | <p align="center"><img src="https://raw.githubusercontent.com/RustScan/RustScan/master/pictures/apple.png" /></p> |
| `docker pull rustscan/rustscan:2.0.0` <p>[Usage](https://github.com/RustScan/RustScan/wiki/Installation-Guide#docker-whale) | [Read the install guide](https://github.com/RustScan/RustScan/wiki/Installation-Guide#%EF%B8%8F-debian--kali) | `yay -S rustscan` | `brew install rustscan` |
| `docker pull rustscan/rustscan:2.0.0` <p>[Usage](https://github.com/RustScan/RustScan#docker-whale) | [Read the install guide](https://github.com/Rustscan/RustScan/blob/master/README.md#%EF%B8%8F-debian--kali) | `yay -S rustscan` | `brew install rustscan` |
<hr>
# 🤔 What is this?
![fast](pictures/fast.gif)
The Modern Port Scanner. **Find ports quickly (3 seconds at its fastest)**. Run scripts through our scripting engine (Python, Lua, Shell supported).
# ✨ Features
@@ -45,13 +43,13 @@ The Modern Port Scanner. **Find ports quickly (3 seconds at its fastest)**. Run
| Installation Guide | Documentation | Discord |
| -------------------------------------------------------------------------------------- | -------------------------------------------------------- | ---------------------------------------- |
| 📖 [Installation Guide](https://github.com/RustScan/RustScan#-full-installation-guide) | 📚 [Documentation](https://rustscan.github.io/RustScan/) | 🦜 [Discord](http://discord.skerritt.blog) |
| 📖 [Installation Guide](https://github.com/RustScan/RustScan#-full-installation-guide) | 📚 [Documentation](https://rustscan.github.io/RustScan/) | 🦜 [Discord](https://discord.gg/GFrQsGy) |
## 🙋 Table of Contents
- 📖 [Installation Guide](https://github.com/RustScan/RustScan/wiki/Installation-Guide)
- 🐋 [Docker Usage](https://github.com/RustScan/RustScan/wiki/Installation-Guide)
- 🦜 [Discord](http://discord.skerritt.blog)
- 🦜 [Discord](https://discord.gg/GFrQsGy)
- 🤸 [Usage](https://github.com/RustScan/RustScan/wiki/Usage)
- 🎪 [Community](https://github.com/RustScan/RustScan#-community)
@@ -61,28 +59,22 @@ RustScan is a modern take on the port scanner. Sleek & fast. All while providing
Not to mention RustScan uses Adaptive Learning to improve itself over time, making it the best port scanner for **you**.
## 🧋 Speed
## Speed
![fast](pictures/fast.gif)
Speed is guaranteed via RustScan. However, if you want to run a slow scan due to stealth that is possible too.
Speed is guranteed via RustScan. However, if you want to run a slow scan that stealth reasons that is possible too.
Firstly, let's talk code.
We have tests that check to see if RustScan is significantly slower than the previous version. If it is, the continuous integration fails and we can't commit code to master unless we make it faster.
We have tests that check to see if RustScan is significantly lower than the previous version. If it is, the continuous integration fails and we can't commit code to master unless we make it faster.
[HyperFine](https://github.com/sharkdp/hyperfine) is used to monitor RustScan's performance over time to answer the question "Are we getting faster? Are we getting slower?".
Every pull request is reviewed by 1 person, but more often than not 2 people review it. We test it manually and make sure the code doesn't affect performance negatively.
Every pull request is reviewed by 1 person, but more often than not 2 people review it. We test it manually and make sure the code doesn't effect performance negatively.
[Read more here](https://github.com/RustScan/RustScan/wiki/Increasing-Speed-&-Accuracy).
## ⚙️ Extensible
![scripts](pictures/scripts.gif)
_RustScan piping results into the custom Python script_
RustScan has a new scripting engine which allows anyone to write scripts in most languages. Python, Lua, Shell are all supported.
Want to take your found ports and pipe them into Nmap for further analysis? That's possible. Want to run `smb-enum` if SMB is found open? Possible.
@@ -93,21 +85,15 @@ The possibilities are endless -- and you can write scripts in whatever language
## 🌊 Adaptive
![adaptive](pictures/adaptive.gif)
_RustScan automatically fine-tuning itself to match the host OS_.
RustScan has a cool set of features called "Adaptive Learning". These features "learn" about the environment you are scanning and how _you_ use RustScan to **improve itself over time**.
This is an umbrella term we use for any feature that fits this criteria. The list is constantly changing, so [check out our wiki for more information](https://github.com/RustScan/RustScan/wiki/Adaptive-Learning).
## 👩‍🦯 Accessible
![fast](pictures/accessible.gif)
RustScan is one of the first penetration testing tools that aims to be entirely accessible.
[Most penetration testing tools are not accessible](https://bees.substack.com/p/making-hacking-accessible), which negatively affects the whole industry.
[Most penetration testing tools are not accessible](https://bees.substack.com/p/making-hacking-accessible), which negatively effects the whole industry.
RustScan has continuous integration testing that aims to make sure it is accessible, and we are constantly working on ways to improve our accessibility and make sure _everyone_ can use RustScan.
@@ -130,7 +116,7 @@ If you maintain a community distribution and want it listed here, leave an issue
We have 2 usage guides. [Basic Usage](https://github.com/RustScan/RustScan/wiki/Usage) and [Things you may want to do](https://github.com/RustScan/RustScan/wiki/Things-you-may-want-to-do-with-RustScan-but-don't-understand-how).
We also have documentation about our config file [here](https://github.com/RustScan/RustScan/wiki/Config-File).
We also have documentation on our config file [here](https://github.com/RustScan/RustScan/wiki/Config-File).
# 🎪 Community
-5
View File
@@ -1,5 +0,0 @@
FROM rust
# Install nmap first.
RUN apt-get update -qy && apt-get install -qy nmap
# Then install rustfmt and clippy for cargo.
RUN rustup component add rustfmt clippy
+10 -48
View File
@@ -7,21 +7,19 @@ Before contributing, read our [code of conduct](https://github.com/RustScan/Rust
TL;DR if you abuse members of our community you will be **perma-banned** with no chance to get unbanned. No warnings either. 🤗
RustScan has 2 major labels for GitHub issues you should look at:
- Good First issue
These are issues for newcomers to open source!
[https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22](https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
- Help wanted
These are issues that aren't really for newcomers, but we could still do with help!
[https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22+label%3A%22help+wanted%22](https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22+label%3A%22help+wanted%22)
* Good First issue
These are issues for newcomers to open source!
[https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22](https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
* Help wanted
These are issues that aren't really for newcomers, but we could still do with help!
[https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22+label%3A%22help+wanted%22](https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22+label%3A%22help+wanted%22)
If you want to, solve the issue or comment on the issue for help.
The flow for contributing to open source software is:
- Fork the repo
- Make changes
- Pull request to the repo
The [flow for contributing](https://guides.github.com/introduction/flow/) to open source software is:
* Fork the repo
* Make changes
* Pull request to the repo
And then comment on the issue that you've done.
@@ -30,40 +28,4 @@ RustScan also has some `// TODO`'s in the codebase, which are meant more for the
If you have any feature suggestions or bugs, leave a GitHub issue. We welcome any and all support :D
## Rewarding you
I cannot pay you :-( But, I can place your GitHub profile on the README under `#Contributors` as a thank you! :)
## Contributing development environment
To ease contribution to RustScan, you can use the `contributing.Dockerfile` to create a Docker image ready to build and play with RustScan.
To build it you just need to run:
```bash
you@home:~/RustScan$ docker build -t rustscan_contributing -f contributing.Dockerfile
```
Then you need to run the container with a volume so it can access, _with read and write permissions_, to RustScan files:
```bash
you@home:~/RustScan$ docker run -ti --rm -v "$PWD":/rustscan -w /rustscan rustscan_contributing bash
```
You can now modify RustScan files with your favorite editor, once you want to compile and test your modifications, type the following in the container prompt:
```bash
root@container:/rustscan# cargo build
```
You are now ready to use RustScan:
```bash
root@container:/rustscan# cargo run -- -b 2000 -t 5000 -a 127.0.0.1
```
You can also format, lint with `clippy` and test the code with the following commands:
```bash
root@container:/rustscan# cargo fmt
root@container:/rustscan# cargo clippy
root@container:/rustscan# cargo test
```
Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

-131
View File
@@ -1,131 +0,0 @@
# The configurations that used for the recording, feel free to edit them
config:
# Specify a command to be executed
# like `/bin/bash -l`, `ls`, or any other commands
# the default is bash for Linux
# or powershell.exe for Windows
command: zsh
# Specify the current working directory path
# the default is the current working directory path
cwd: /home/bee/Documents/RustScan
# Export additional ENV variables
env:
recording: true
# Explicitly set the number of columns
# or use `auto` to take the current
# number of columns of your shell
cols: 107
# Explicitly set the number of rows
# or use `auto` to take the current
# number of rows of your shell
rows: 43
# Amount of times to repeat GIF
# If value is -1, play once
# If value is 0, loop indefinitely
# If value is a positive number, loop n times
repeat: 0
# Quality
# 1 - 100
quality: 100
# Delay between frames in ms
# If the value is `auto` use the actual recording delays
frameDelay: auto
# Maximum delay between frames in ms
# Ignored if the `frameDelay` isn't set to `auto`
# Set to `auto` to prevent limiting the max idle time
maxIdleTime: 2000
# The surrounding frame box
# The `type` can be null, window, floating, or solid`
# To hide the title use the value null
# Don't forget to add a backgroundColor style with a null as type
frameBox:
type: floating
title: Terminalizer
style:
border: 0px black solid
# boxShadow: none
# margin: 0px
# Add a watermark image to the rendered gif
# You need to specify an absolute path for
# the image on your machine or a URL, and you can also
# add your own CSS styles
watermark:
imagePath: null
style:
position: absolute
right: 15px
bottom: 15px
width: 100px
opacity: 0.9
# Cursor style can be one of
# `block`, `underline`, or `bar`
cursorStyle: block
# Font family
# You can use any font that is installed on your machine
# in CSS-like syntax
fontFamily: "Monaco, Lucida Console, Ubuntu Mono, Monospace"
# The size of the font
fontSize: 12
# The height of lines
lineHeight: 1
# The spacing between letters
letterSpacing: 0
# Theme
theme:
background: "transparent"
foreground: "#afafaf"
cursor: "#c7c7c7"
black: "#232628"
red: "#fc4384"
green: "#b3e33b"
yellow: "#ffa727"
blue: "#75dff2"
magenta: "#ae89fe"
cyan: "#708387"
white: "#d5d5d0"
brightBlack: "#626566"
brightRed: "#ff7fac"
brightGreen: "#c8ed71"
brightYellow: "#ebdf86"
brightBlue: "#75dff2"
brightMagenta: "#ae89fe"
brightCyan: "#b1c6ca"
brightWhite: "#f9f9f4"
# Records, feel free to edit them
records:
- delay: 436
content: "\e[1m\e[7m%\e[27m\e[1m\e[0m \r \r\e]2;bee@beehive:~/Documents/RustScan\a\e]1;..ents/RustScan\a"
- delay: 162
content: "\r\e[0m\e[27m\e[24m\e[J\r\n\e[1m\e[0m\e[1m\e[36mRustScan\e[0m\e[36m\e[39m\e[1m \e[0m\e[1mon \e[0m\e[1m\e[37m\e[1m\e[37m\e[0m\e[37m\e[1m\e[37m\e[35m master\e[0m\e[35m\e[39m\e[1m\e[0m\e[1m\e[0m\e[1m\e[31m [?]\e[0m\e[31m\e[39m\e[1m\e[0m\e[0m\e[39m\e[1m \e[0m\e[1mis \e[0m\e[1m\e[31m\U0001F4E6 vrustscan:1.10.0\e[0m\e[31m\e[39m\e[1m \e[0m\e[1mvia \e[0m\e[1m\e[31m\U0001D5E5 v1.46.0\e[0m\e[31m\e[39m\e[1m \e[0m\r\n\e[1m\e[0m\e[1m\e[32m➜ \e[0m\e[32m\e[39m\e[1m\e[0m\e[K\e[?1h\e=\e[?2004h"
- delay: 471
content: "r\brustscan 127.0.0.1 --accessible --no-nmap --ulimit 5000\e[55D\e[7mr\e[7mu\e[7ms\e[7mt\e[7ms\e[7mc\e[7ma\e[7mn\e[7m \e[7m1\e[7m2\e[7m7\e[7m.\e[7m0\e[7m.\e[7m0\e[7m.\e[7m1\e[7m \e[7m-\e[7m-\e[7ma\e[7mc\e[7mc\e[7me\e[7ms\e[7ms\e[7mi\e[7mb\e[7ml\e[7me\e[7m \e[7m-\e[7m-\e[7mn\e[7mo\e[7m-\e[7mn\e[7mm\e[7ma\e[7mp\e[7m \e[7m-\e[7m-\e[7mu\e[7ml\e[7mi\e[7mm\e[7mi\e[7mt\e[7m \e[7m5\e[7m0\e[7m0\e[7m0\e[27m"
- delay: 269
content: "\e[55D\e[27mr\e[27mu\e[27ms\e[27mt\e[27ms\e[27mc\e[27ma\e[27mn\e[27m \e[27m1\e[27m2\e[27m7\e[27m.\e[27m0\e[27m.\e[27m0\e[27m.\e[27m1\e[27m \e[27m-\e[27m-\e[27ma\e[27mc\e[27mc\e[27me\e[27ms\e[27ms\e[27mi\e[27mb\e[27ml\e[27me\e[27m \e[27m-\e[27m-\e[27mn\e[27mo\e[27m-\e[27mn\e[27mm\e[27ma\e[27mp\e[27m \e[27m-\e[27m-\e[27mu\e[27ml\e[27mi\e[27mm\e[27mi\e[27mt\e[27m \e[27m5\e[27m0\e[27m0\e[27m0\e[?1l\e>\e[?2004l\r\r\n\e]2;rustscan 127.0.0.1 --accessible --no-nmap --ulimit 5000\a\e]1;rustscan\aAutomatically increasing ulimit value to 5000.\r\n"
- delay: 1536
content: "Open 127.0.0.1:38602\r\n"
- delay: 395
content: "Open 127.0.0.1:50078\r\n"
- delay: 450
content: "127.0.0.1 -> [38602,50078]\r\n\e[1m\e[7m%\e[27m\e[1m\e[0m \r \r\e]2;bee@beehive:~/Documents/RustScan\a\e]1;..ents/RustScan\a"
- delay: 143
content: "\r\e[0m\e[27m\e[24m\e[J\r\n\e[1m\e[0m\e[1m\e[36mRustScan\e[0m\e[36m\e[39m\e[1m \e[0m\e[1mon \e[0m\e[1m\e[37m\e[1m\e[37m\e[0m\e[37m\e[1m\e[37m\e[35m master\e[0m\e[35m\e[39m\e[1m\e[0m\e[1m\e[0m\e[1m\e[31m [?]\e[0m\e[31m\e[39m\e[1m\e[0m\e[0m\e[39m\e[1m \e[0m\e[1mis \e[0m\e[1m\e[31m\U0001F4E6 vrustscan:1.10.0\e[0m\e[31m\e[39m\e[1m \e[0m\e[1mvia \e[0m\e[1m\e[31m\U0001D5E5 v1.46.0\e[0m\e[31m\e[39m\e[1m \e[0m\e[1mtook \e[0m\e[1m\e[33m2s\e[0m\e[33m\e[39m\e[1m \e[0m\r\n\e[1m\e[0m\e[1m\e[32m➜ \e[0m\e[32m\e[39m\e[1m\e[0m\e[K\e[?1h\e=\e[?2004h"
- delay: 563
content: "\e[?2004l\r\r\n"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 KiB

+15 -27
View File
@@ -1,7 +1,6 @@
use serde_derive::Deserialize;
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use structopt::{clap::arg_enum, StructOpt};
const LOWEST_PORT_NUMBER: u16 = 1;
@@ -11,7 +10,7 @@ arg_enum! {
/// Represents the strategy in which the port scanning will run.
/// - Serial will run from start to end, for example 1 to 1_000.
/// - Random will randomize the order in which ports will be scanned.
#[derive(Deserialize, Debug, StructOpt, Clone, Copy, PartialEq)]
#[derive(Deserialize, Debug, StructOpt, Clone, PartialEq)]
pub enum ScanOrder {
Serial,
Random,
@@ -42,7 +41,7 @@ pub struct PortRange {
fn parse_range(input: &str) -> Result<PortRange, String> {
let range = input
.split('-')
.map(str::parse)
.map(|x| x.parse::<u16>())
.collect::<Result<Vec<u16>, std::num::ParseIntError>>();
if range.is_err() {
@@ -64,14 +63,13 @@ fn parse_range(input: &str) -> Result<PortRange, String> {
#[derive(StructOpt, Debug, Clone)]
#[structopt(name = "rustscan", setting = structopt::clap::AppSettings::TrailingVarArg)]
#[allow(clippy::struct_excessive_bools)]
/// Fast Port Scanner built in Rust.
/// WARNING Do not use this program against sensitive infrastructure since the
/// specified server may not be able to handle this many socket connections at once.
/// - Discord https://discord.gg/GFrQsGy
/// - GitHub https://github.com/RustScan/RustScan
pub struct Opts {
/// A comma-delimited list or newline-delimited file of separated CIDRs, IPs, or hosts to be scanned.
/// A list of comma separated CIDRs, IPs, or hosts to be scanned.
#[structopt(short, long, use_delimiter = true)]
pub addresses: Vec<String>,
@@ -87,10 +85,6 @@ pub struct Opts {
#[structopt(short, long)]
pub no_config: bool,
/// Custom path to config file
#[structopt(short, long, parse(from_os_str))]
pub config_path: Option<PathBuf>,
/// Greppable mode. Only output the ports. No Nmap. Useful for grep or outputting to a file.
#[structopt(short, long)]
pub greppable: bool,
@@ -117,7 +111,7 @@ pub struct Opts {
/// Automatically ups the ULIMIT with the value you provided.
#[structopt(short, long)]
pub ulimit: Option<u64>,
pub ulimit: Option<rlimit::RawRlim>,
/// The order of scanning to be performed. The "serial" option will
/// scan ports in ascending order while the "random" option will scan
@@ -135,7 +129,7 @@ pub struct Opts {
/// The Script arguments to run.
/// To use the argument -A, end RustScan's args with '-- -A'.
/// Example: 'rustscan -T 1500 -a 127.0.0.1 -- -A -sC'.
/// Example: 'rustscan -T 1500 127.0.0.1 -- -A -sC'.
/// This command adds -Pn -vvv -p $PORTS automatically to nmap.
/// For things like --script '(safe and vuln)' enclose it in quotations marks \"'(safe and vuln)'\"")
#[structopt(last = true)]
@@ -221,7 +215,7 @@ pub struct Config {
batch_size: Option<u16>,
timeout: Option<u32>,
tries: Option<u8>,
ulimit: Option<u64>,
ulimit: Option<rlimit::RawRlim>,
scan_order: Option<ScanOrder>,
command: Option<Vec<String>>,
scripts: Option<ScriptsRequired>,
@@ -239,11 +233,16 @@ impl Config {
/// greppable = true
/// scan_order: "Serial"
///
pub fn read(custom_config_path: Option<PathBuf>) -> Self {
pub fn read() -> Self {
let mut home_dir = match dirs::home_dir() {
Some(dir) => dir,
None => panic!("Could not infer config file path."),
};
home_dir.push(".rustscan.toml");
let mut content = String::new();
let config_path = custom_config_path.unwrap_or_else(default_config_path);
if config_path.exists() {
content = match fs::read_to_string(config_path) {
if home_dir.exists() {
content = match fs::read_to_string(home_dir) {
Ok(content) => content,
Err(_) => String::new(),
}
@@ -261,16 +260,6 @@ impl Config {
}
}
/// Constructs default path to config toml
pub fn default_config_path() -> PathBuf {
let mut config_path = match dirs::home_dir() {
Some(dir) => dir,
None => panic!("Could not infer config file path."),
};
config_path.push(".rustscan.toml");
config_path
}
#[cfg(test)]
mod tests {
use super::{Config, Opts, PortRange, ScanOrder, ScriptsRequired};
@@ -310,7 +299,6 @@ mod tests {
no_config: true,
top: false,
scripts: ScriptsRequired::Default,
config_path: None,
}
}
}
+81 -115
View File
@@ -1,7 +1,3 @@
#![deny(clippy::all)]
#![warn(clippy::pedantic)]
#![allow(clippy::doc_markdown, clippy::if_not_else, clippy::non_ascii_literal)]
extern crate shell_words;
mod tui;
@@ -24,32 +20,27 @@ use scripts::{init_scripts, Script, ScriptFile};
use cidr_utils::cidr::IpCidr;
use colorful::{Color, Colorful};
use futures::executor::block_on;
use rlimit::{getrlimit, setrlimit, RawRlim, Resource, Rlim};
use std::collections::HashMap;
use std::fs::File;
use std::io::{prelude::*, BufReader};
use std::net::{IpAddr, ToSocketAddrs};
use std::path::Path;
use std::string::ToString;
use std::time::Duration;
use trust_dns_resolver::{
config::{ResolverConfig, ResolverOpts},
Resolver,
};
use trust_dns_resolver::{config::*, Resolver};
extern crate colorful;
extern crate dirs;
// Average value for Ubuntu
#[cfg(unix)]
const DEFAULT_FILE_DESCRIPTORS_LIMIT: u64 = 8000;
const DEFAULT_FILE_DESCRIPTORS_LIMIT: RawRlim = 8000;
// Safest batch size based on experimentation
const AVERAGE_BATCH_SIZE: u16 = 3000;
const AVERAGE_BATCH_SIZE: RawRlim = 3000;
#[macro_use]
extern crate log;
#[cfg(not(tarpaulin_include))]
#[allow(clippy::too_many_lines)]
/// Faster Nmap scanning with Rust
/// If you're looking for the actual scanning, check out the module Scanner
fn main() {
@@ -58,23 +49,13 @@ fn main() {
let mut rustscan_bench = NamedTimer::start("RustScan");
let mut opts: Opts = Opts::read();
let config = Config::read(opts.config_path.clone());
let config = Config::read();
opts.merge(&config);
debug!("Main() `opts` arguments are {:?}", opts);
let scripts_to_run: Vec<ScriptFile> = match init_scripts(opts.scripts) {
Ok(scripts_to_run) => scripts_to_run,
Err(e) => {
warning!(
format!("Initiating scripts failed!\n{}", e),
opts.greppable,
opts.accessible
);
std::process::exit(1);
}
};
let scripts_to_run: Vec<ScriptFile> =
init_scripts(opts.scripts).expect("could not initiate scripting part.");
debug!("Scripts initialized {:?}", &scripts_to_run);
if !opts.greppable && !opts.accessible {
@@ -92,11 +73,8 @@ fn main() {
std::process::exit(1);
}
#[cfg(unix)]
let batch_size: u16 = infer_batch_size(&opts, adjust_ulimit_size(&opts));
#[cfg(not(unix))]
let batch_size: u16 = AVERAGE_BATCH_SIZE;
let ulimit: RawRlim = adjust_ulimit_size(&opts);
let batch_size: u16 = infer_batch_size(&opts, ulimit);
let scanner = Scanner::new(
&ips,
@@ -104,7 +82,7 @@ fn main() {
Duration::from_millis(opts.timeout.into()),
opts.tries,
opts.greppable,
PortStrategy::pick(&opts.range, opts.ports, opts.scan_order),
PortStrategy::pick(opts.range, opts.ports, opts.scan_order),
opts.accessible,
);
debug!("Scanner finished building: {:?}", scanner);
@@ -136,13 +114,13 @@ fn main() {
\n Alternatively, increase the timeout if your ping is high. Rustscan -t 2000 for 2000 milliseconds (2s) timeout.\n",
ip,
opts.batch_size,
"'rustscan -b <batch_size> -a <ip address>'");
"'rustscan -b <batch_size> <ip address>'");
warning!(x, opts.greppable, opts.accessible);
}
let mut script_bench = NamedTimer::start("Scripts");
for (ip, ports) in &ports_per_ip {
let vec_str_ports: Vec<String> = ports.iter().map(ToString::to_string).collect();
for (ip, ports) in ports_per_ip.iter_mut() {
let vec_str_ports: Vec<String> = ports.iter().map(|port| port.to_string()).collect();
// nmap port style is 80,443. Comma separated with no spaces.
let ports_str = vec_str_ports.join(",");
@@ -156,20 +134,19 @@ fn main() {
// Run all the scripts we found and parsed based on the script config file tags field.
for mut script_f in scripts_to_run.clone() {
output!(
format!("Script to be run {:?}\n", script_f.call_format,),
opts.greppable,
opts.accessible
);
// This part allows us to add commandline arguments to the Script call_format, appending them to the end of the command.
if !opts.command.is_empty() {
let user_extra_args = &opts.command.join(" ");
debug!("Extra args vec {:?}", user_extra_args);
let user_extra_args: Vec<String> = shell_words::split(&opts.command.join(" "))
.expect("Failed to parse extra user commandline arguments");
if script_f.call_format.is_some() {
let mut call_f = script_f.call_format.unwrap();
call_f.push(' ');
call_f.push_str(user_extra_args);
output!(
format!("Running script {:?} on ip {}\nDepending on the complexity of the script, results may take some time to appear.", call_f, &ip),
opts.greppable,
opts.accessible
);
debug!("Call format {}", call_f);
call_f.push_str(&format!(" {}", &user_extra_args.join(" ")));
script_f.call_format = Some(call_f);
}
}
@@ -178,7 +155,7 @@ fn main() {
let script = Script::build(
script_f.path,
*ip,
ports.clone(),
ports.to_vec(),
script_f.port,
script_f.ports_separator,
script_f.tags,
@@ -189,7 +166,11 @@ fn main() {
detail!(script_result.to_string(), opts.greppable, opts.accessible);
}
Err(e) => {
warning!(&format!("Error {}", e), opts.greppable, opts.accessible);
warning!(
&format!("Error {}", e.to_string()),
opts.greppable,
opts.accessible
);
}
}
}
@@ -207,29 +188,22 @@ fn main() {
/// Prints the opening title of RustScan
fn print_opening(opts: &Opts) {
debug!("Printing opening");
let s = format!(
"{}\n{}\n{}\n{}\n{}",
r#".----. .-. .-. .----..---. .----. .---. .--. .-. .-."#,
r#"| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |"#,
r#"| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |"#,
r#"`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'"#,
r#"The Modern Day Port Scanner."#
);
let s = r#".----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner."#;
println!("{}", s.gradient(Color::Green).bold());
let info = format!(
"{}\n{}\n{}\n{}",
r#"________________________________________"#,
r#": http://discord.skerritt.blog :"#,
r#": https://github.com/RustScan/RustScan :"#,
r#" --------------------------------------"#
);
let info = r#"________________________________________
: https://discord.gg/GFrQsGy :
: https://github.com/RustScan/RustScan :
--------------------------------------"#;
println!("{}", info.gradient(Color::Yellow).bold());
funny_opening!();
let config_path = opts
.config_path
.clone()
.unwrap_or_else(input::default_config_path);
let config_path = dirs::home_dir()
.expect("Could not infer config file path.")
.join(".rustscan.toml");
detail!(
format!("The config file is expected to be at {:?}", config_path),
@@ -243,11 +217,11 @@ fn print_opening(opts: &Opts) {
fn parse_addresses(input: &Opts) -> Vec<IpAddr> {
let mut ips: Vec<IpAddr> = Vec::new();
let mut unresolved_addresses: Vec<&str> = Vec::new();
let backup_resolver =
Resolver::new(ResolverConfig::cloudflare_tls(), ResolverOpts::default()).unwrap();
let resolver =
&Resolver::new(ResolverConfig::cloudflare_tls(), ResolverOpts::default()).unwrap();
for address in &input.addresses {
let parsed_ips = parse_address(address, &backup_resolver);
let parsed_ips = parse_address(address, resolver);
if !parsed_ips.is_empty() {
ips.extend(parsed_ips);
} else {
@@ -269,7 +243,7 @@ fn parse_addresses(input: &Opts) -> Vec<IpAddr> {
continue;
}
if let Ok(x) = read_ips_from_file(file_path, &backup_resolver) {
if let Ok(x) = read_ips_from_file(file_path, &resolver) {
ips.extend(x);
} else {
warning!(
@@ -300,25 +274,18 @@ fn parse_address(address: &str, resolver: &Resolver) -> Vec<IpAddr> {
}
/// Uses DNS to get the IPS assiocated with host
fn resolve_ips_from_host(source: &str, backup_resolver: &Resolver) -> Vec<IpAddr> {
let mut ips: Vec<std::net::IpAddr> = Vec::new();
if let Ok(addrs) = source.to_socket_addrs() {
for ip in addrs {
ips.push(ip.ip());
}
} else if let Ok(addrs) = backup_resolver.lookup_ip(source) {
ips.extend(addrs.iter());
}
ips
fn resolve_ips_from_host(source: &str, resolver: &Resolver) -> Vec<IpAddr> {
resolver
.lookup_ip(source)
.map(|x| x.iter().collect())
.unwrap_or_default()
}
#[cfg(not(tarpaulin_include))]
/// Parses an input file of IPs and uses those
fn read_ips_from_file(
ips: &std::path::Path,
backup_resolver: &Resolver,
resolver: &Resolver,
) -> Result<Vec<std::net::IpAddr>, std::io::Error> {
let file = File::open(ips)?;
let reader = BufReader::new(file);
@@ -327,7 +294,7 @@ fn read_ips_from_file(
for address_line in reader.lines() {
if let Ok(address) = address_line {
ips.extend(parse_address(&address, backup_resolver));
ips.extend(parse_address(&address, resolver));
} else {
debug!("Line in file is not valid");
}
@@ -336,34 +303,35 @@ fn read_ips_from_file(
Ok(ips)
}
#[cfg(unix)]
fn adjust_ulimit_size(opts: &Opts) -> u64 {
use rlimit::Resource;
if let Some(limit) = opts.ulimit {
if Resource::NOFILE.set(limit, limit).is_ok() {
detail!(
format!("Automatically increasing ulimit value to {}.", limit),
opts.greppable,
opts.accessible
);
} else {
warning!(
"ERROR. Failed to set ulimit value.",
opts.greppable,
opts.accessible
);
fn adjust_ulimit_size(opts: &Opts) -> RawRlim {
if opts.ulimit.is_some() {
let limit: Rlim = Rlim::from_raw(opts.ulimit.unwrap());
match setrlimit(Resource::NOFILE, limit, limit) {
Ok(_) => {
detail!(
format!("Automatically increasing ulimit value to {}.", limit),
opts.greppable,
opts.accessible
);
}
Err(_) => {
warning!(
"ERROR. Failed to set ulimit value.",
opts.greppable,
opts.accessible
);
}
}
}
let (soft, _) = Resource::NOFILE.get().unwrap();
soft
let (rlim, _) = getrlimit(Resource::NOFILE).unwrap();
rlim.as_raw()
}
#[cfg(unix)]
fn infer_batch_size(opts: &Opts, ulimit: u64) -> u16 {
use std::convert::TryInto;
let mut batch_size: u64 = opts.batch_size.into();
fn infer_batch_size(opts: &Opts, ulimit: RawRlim) -> u16 {
let mut batch_size: RawRlim = opts.batch_size.into();
// Adjust the batch size when the ulimit value is lower than the desired batch size
if ulimit < batch_size {
@@ -374,18 +342,18 @@ fn infer_batch_size(opts: &Opts, ulimit: u64) -> u16 {
// When the OS supports high file limits like 8000, but the user
// selected a batch size higher than this we should reduce it to
// a lower number.
if ulimit < AVERAGE_BATCH_SIZE.into() {
if ulimit < AVERAGE_BATCH_SIZE {
// ulimit is smaller than aveage batch size
// user must have very small ulimit
// decrease batch size to half of ulimit
warning!("Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'. ", opts.greppable, opts.accessible);
info!("Halving batch_size because ulimit is smaller than average batch size");
batch_size = ulimit / 2;
batch_size = ulimit / 2
} else if ulimit > DEFAULT_FILE_DESCRIPTORS_LIMIT {
info!("Batch size is now average batch size");
batch_size = AVERAGE_BATCH_SIZE.into();
batch_size = AVERAGE_BATCH_SIZE
} else {
batch_size = ulimit - 100;
batch_size = ulimit - 100
}
}
// When the ulimit is higher than the batch size let the user know that the
@@ -395,9 +363,7 @@ fn infer_batch_size(opts: &Opts, ulimit: u64) -> u16 {
opts.greppable, opts.accessible);
}
batch_size
.try_into()
.expect("Couldn't fit the batch size into a u16.")
batch_size as u16
}
#[cfg(test)]
@@ -448,8 +414,8 @@ mod tests {
opts.ulimit = Some(2_000);
// print opening should not panic
print_opening(&opts);
assert!(1 == 1);
}
#[test]
fn test_high_ulimit_no_greppable_mode() {
let mut opts = Opts::default();
+5 -5
View File
@@ -16,7 +16,7 @@ pub enum PortStrategy {
}
impl PortStrategy {
pub fn pick(range: &Option<PortRange>, ports: Option<Vec<u16>>, order: ScanOrder) -> Self {
pub fn pick(range: Option<PortRange>, ports: Option<Vec<u16>>, order: ScanOrder) -> Self {
match order {
ScanOrder::Serial if ports.is_none() => {
let range = range.as_ref().unwrap();
@@ -102,7 +102,7 @@ mod tests {
#[test]
fn serial_strategy_with_range() {
let range = PortRange { start: 1, end: 100 };
let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Serial);
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Serial);
let result = strategy.order();
let expected_range = (1..100).into_iter().collect::<Vec<u16>>();
assert_eq!(expected_range, result);
@@ -110,7 +110,7 @@ mod tests {
#[test]
fn random_strategy_with_range() {
let range = PortRange { start: 1, end: 100 };
let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random);
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Random);
let mut result = strategy.order();
let expected_range = (1..100).into_iter().collect::<Vec<u16>>();
assert_ne!(expected_range, result);
@@ -121,14 +121,14 @@ mod tests {
#[test]
fn serial_strategy_with_ports() {
let strategy = PortStrategy::pick(&None, Some(vec![80, 443]), ScanOrder::Serial);
let strategy = PortStrategy::pick(None, Some(vec![80, 443]), ScanOrder::Serial);
let result = strategy.order();
assert_eq!(vec![80, 443], result);
}
#[test]
fn random_strategy_with_ports() {
let strategy = PortStrategy::pick(&None, Some((1..10).collect()), ScanOrder::Random);
let strategy = PortStrategy::pick(None, Some((1..10).collect()), ScanOrder::Random);
let mut result = strategy.order();
let expected_range = (1..10).into_iter().collect::<Vec<u16>>();
assert_ne!(expected_range, result);
+1 -6
View File
@@ -1,6 +1,5 @@
use gcd::Gcd;
use rand::Rng;
use std::convert::TryInto;
pub struct RangeIterator {
active: bool,
@@ -61,11 +60,7 @@ impl Iterator for RangeIterator {
}
self.normalized_pick = next_pick;
Some(
(self.actual_start + current_pick)
.try_into()
.expect("Could not convert u32 to u16"),
)
Some((self.actual_start + current_pick) as u16)
}
}
+19 -23
View File
@@ -6,10 +6,10 @@ use socket_iterator::SocketIterator;
use async_std::io;
use async_std::net::TcpStream;
use async_std::prelude::*;
use colored::Colorize;
use colored::*;
use futures::stream::FuturesUnordered;
use std::{
collections::HashSet,
io::ErrorKind,
net::{IpAddr, Shutdown, SocketAddr},
num::NonZeroU8,
time::Duration,
@@ -49,7 +49,7 @@ impl Scanner {
tries: NonZeroU8::new(std::cmp::max(tries, 1)).unwrap(),
greppable,
port_strategy,
ips: ips.iter().map(ToOwned::to_owned).collect(),
ips: ips.iter().map(|ip| ip.to_owned()).collect(),
accessible,
}
}
@@ -62,7 +62,6 @@ impl Scanner {
let mut socket_iterator: SocketIterator = SocketIterator::new(&self.ips, &ports);
let mut open_sockets: Vec<SocketAddr> = Vec::new();
let mut ftrs = FuturesUnordered::new();
let mut errors: HashSet<String> = HashSet::with_capacity(self.ips.len() * 1000);
for _ in 0..self.batch_size {
if let Some(socket) = socket_iterator.next() {
@@ -83,17 +82,10 @@ impl Scanner {
ftrs.push(self.scan_socket(socket));
}
match result {
Ok(socket) => open_sockets.push(socket),
Err(e) => {
let error_string = e.to_string();
if errors.len() < self.ips.len() * 1000 {
errors.insert(error_string);
}
}
if let Ok(socket) = result {
open_sockets.push(socket);
}
}
debug!("Typical socket connection errors {:?}", errors);
debug!("Open Sockets found: {:?}", &open_sockets);
open_sockets
}
@@ -135,15 +127,19 @@ impl Scanner {
return Ok(socket);
}
Err(e) => {
let mut error_string = e.to_string();
let error_string = e.to_string();
if error_string.to_lowercase().contains("too many open files") {
panic!("Too many open files. Please reduce batch size. The default is 5000. Try -b 2500.");
if e.kind() == ErrorKind::Other {
debug!("Socket connect error: {} {}", &error_string, &socket);
if !error_string.contains("No route to host")
&& !error_string.contains("Network is unreachable")
{
panic!("Too many open files. Please reduce batch size. The default is 5000. Try -b 2500.");
}
}
if nr_try == tries {
error_string.push(' ');
error_string.push_str(&socket.ip().to_string());
return Err(io::Error::new(io::ErrorKind::Other, error_string));
}
}
@@ -188,7 +184,7 @@ mod tests {
start: 1,
end: 1_000,
};
let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random);
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Random);
let scanner = Scanner::new(
&addrs,
10,
@@ -210,7 +206,7 @@ mod tests {
start: 1,
end: 1_000,
};
let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random);
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Random);
let scanner = Scanner::new(
&addrs,
10,
@@ -231,7 +227,7 @@ mod tests {
start: 1,
end: 1_000,
};
let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random);
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Random);
let scanner = Scanner::new(
&addrs,
10,
@@ -251,7 +247,7 @@ mod tests {
start: 400,
end: 445,
};
let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random);
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Random);
let scanner = Scanner::new(
&addrs,
10,
@@ -274,7 +270,7 @@ mod tests {
start: 400,
end: 600,
};
let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random);
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Random);
let scanner = Scanner::new(
&addrs,
10,
+20 -16
View File
@@ -43,18 +43,14 @@
//!
//! If the format is different, the script will be silently discarded and will not run. With the Debug option it's possible to see where it goes wrong.
#![allow(clippy::module_name_repetitions)]
use crate::input::ScriptsRequired;
use anyhow::{anyhow, Result};
use serde_derive::{Deserialize, Serialize};
use std::collections::HashSet;
use std::convert::TryInto;
use std::fs::{self, File};
use std::io::{self, prelude::*};
use std::net::IpAddr;
use std::path::PathBuf;
use std::string::ToString;
use subprocess::{Exec, ExitStatus};
use text_placeholder::Template;
@@ -201,7 +197,7 @@ impl Script {
let mut ports_str = self
.open_ports
.iter()
.map(ToString::to_string)
.map(|port| port.to_string())
.collect::<Vec<String>>()
.join(&separator);
if let Some(port) = self.trigger_port {
@@ -231,9 +227,17 @@ impl Script {
};
to_run = default_template.fill_with_struct(&exec_parts)?;
}
debug!("\nScript format to run {}", to_run);
let arguments = shell_words::split(&to_run).expect("Failed to parse script arguments");
debug!("\nTo run {}", to_run);
let arguments = shell_words::split(
&to_run
.split(' ')
.map(|arg| arg.to_string())
.collect::<Vec<String>>()
.join(" "),
)
.expect("Failed to parse script arguments");
execute_script(arguments)
}
@@ -241,15 +245,15 @@ impl Script {
#[cfg(not(tarpaulin_include))]
fn execute_script(mut arguments: Vec<String>) -> Result<String> {
debug!("\nScript arguments vec: {:?}", &arguments);
debug!("\nArguments vec: {:?}", &arguments);
let process = Exec::cmd(&arguments.remove(0)).args(&arguments);
match process.capture() {
Ok(c) => {
let es = match c.exit_status {
ExitStatus::Exited(c) => c.try_into().unwrap(),
ExitStatus::Signaled(c) => c.into(),
ExitStatus::Exited(c) => c as i32,
ExitStatus::Signaled(c) => c as i32,
ExitStatus::Other(c) => c,
ExitStatus::Undetermined => -1,
_ => -1,
};
if es != 0 {
return Err(anyhow!("Exit code = {}", es));
@@ -274,7 +278,7 @@ pub fn find_scripts(mut path: PathBuf) -> Result<Vec<PathBuf>> {
}
Ok(files_vec)
} else {
Err(anyhow!("Can't find scripts folder {}", path.display()))
Err(anyhow!("Can't find scripts folder"))
}
}
@@ -298,7 +302,7 @@ impl ScriptFile {
if line.starts_with('#') {
line.retain(|c| c != '#');
line = line.trim().to_string();
line.push('\n');
line.push_str("\n");
lines_buf.push_str(&line);
} else {
break;
@@ -376,7 +380,7 @@ mod tests {
#[test]
#[should_panic]
fn find_invalid_folder() {
let _scripts = find_scripts("Cargo.toml".into()).unwrap();
let scripts = find_scripts("Cargo.toml".into()).unwrap();
}
#[test]
@@ -393,7 +397,7 @@ mod tests {
ScriptFile::new("fixtures/.rustscan_scripts/test_script.txt".into()).unwrap();
script_f.call_format = Some("qwertyuiop".to_string());
let script: Script = into_script(script_f);
let _output = script.run().unwrap();
let output = script.run().unwrap();
}
#[test]
@@ -403,7 +407,7 @@ mod tests {
ScriptFile::new("fixtures/.rustscan_scripts/test_script.txt".into()).unwrap();
script_f.call_format = None;
let script: Script = into_script(script_f);
let _output = script.run().unwrap();
let output = script.run().unwrap();
}
#[test]
-1
View File
@@ -72,7 +72,6 @@ macro_rules! funny_opening {
"Real hackers hack time ⌛",
"Please contribute more quotes to our GitHub https://github.com/rustscan/rustscan",
"😵 https://admin.tryhackme.com",
"0day was here ♥",
];
let random_quote = quotes.choose(&mut rand::thread_rng()).unwrap();