Skip to content

Commit e4cd536

Browse files
committed
Add sniffer demo
1 parent f5e0072 commit e4cd536

File tree

3 files changed

+125
-0
lines changed

3 files changed

+125
-0
lines changed

intro-to-rust-lang/p16-sniffer/Cargo.lock

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "p16-sniffer"
3+
version = "0.1.0"
4+
authors = ["ShuLiang <[email protected]>"]
5+
edition = "2018"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]
+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
use std::env;
2+
use std::io::{self, Write};
3+
use std::net::{IpAddr, TcpStream};
4+
use std::process;
5+
use std::str::FromStr;
6+
use std::sync::mpsc::{channel, Sender};
7+
use std::thread;
8+
9+
const MAX: u16 = 65535;
10+
11+
struct Arguments {
12+
flag: String,
13+
ipaddr: IpAddr,
14+
threads: u16,
15+
}
16+
17+
impl Arguments {
18+
fn new(args: &[String]) -> Result<Arguments, &'static str> {
19+
if args.len() < 2 {
20+
return Err("not enough arguments");
21+
} else if args.len() > 4 {
22+
return Err("too many arguments");
23+
}
24+
let f = args[1].clone();
25+
if let Ok(ipaddr) = IpAddr::from_str(&f) {
26+
return Ok(Arguments {
27+
flag: String::from(""),
28+
ipaddr,
29+
threads: 4,
30+
});
31+
} else {
32+
let flag = args[1].clone();
33+
if flag.contains("-h") || flag.contains("-help") && args.len() == 2 {
34+
println!("Usage: -j to select how many threads you want \r\n -h or --help to show this help message");
35+
return Err("help");
36+
} else if flag.contains("-h") || flag.contains("-help") {
37+
return Err("too many arguments");
38+
} else if flag.contains("-j") {
39+
let ipaddr = match IpAddr::from_str(&args[3]) {
40+
Ok(s) => s,
41+
Err(_) => return Err("not a valid IPADDR; must be IPv4 or IPv6"),
42+
};
43+
let threads = match args[2].parse::<u16>() {
44+
Ok(s) => s,
45+
Err(_) => return Err("failed to parse thread number"),
46+
};
47+
return Ok(Arguments {
48+
threads,
49+
flag,
50+
ipaddr,
51+
});
52+
} else {
53+
return Err("invalid syntax");
54+
}
55+
}
56+
}
57+
}
58+
59+
fn scan(tx: Sender<u16>, start_port: u16, addr: IpAddr, num_threads: u16) {
60+
let mut port: u16 = start_port + 1;
61+
loop {
62+
match TcpStream::connect((addr, port)) {
63+
Ok(_) => {
64+
print!(".");
65+
io::stdout().flush().unwrap();
66+
tx.send(port).unwrap();
67+
}
68+
Err(_) => {}
69+
}
70+
if (MAX - port) <= num_threads {
71+
break;
72+
}
73+
port += num_threads;
74+
}
75+
}
76+
77+
fn main() {
78+
let args: Vec<String> = env::args().collect();
79+
let program = args[0].clone();
80+
let arguments = Arguments::new(&args).unwrap_or_else(|err| {
81+
if err.contains("help") {
82+
process::exit(0);
83+
} else {
84+
eprintln!("{} problem parsing arguments: {}", program, err);
85+
process::exit(0);
86+
}
87+
});
88+
89+
let num_threads = arguments.threads;
90+
let addr = arguments.ipaddr;
91+
let (tx, rx) = channel();
92+
for i in 0..num_threads {
93+
let tx = tx.clone();
94+
95+
thread::spawn(move || {
96+
scan(tx, i, addr, num_threads);
97+
});
98+
}
99+
100+
let mut out = vec![];
101+
drop(tx);
102+
for p in rx {
103+
out.push(p);
104+
}
105+
106+
println!("");
107+
out.sort();
108+
for v in out {
109+
println!("{} is open", v);
110+
}
111+
}

0 commit comments

Comments
 (0)