Skip to content

Commit

Permalink
Handle files and interfaces uniformly.
Browse files Browse the repository at this point in the history
Add command-line parsing to allow the specification of an interface name or a filename. Once opened, treat these cap sources in the same way.

Made possible by pcap improvements as discussed in rust-pcap/pcap#16.
  • Loading branch information
trombonehero committed Sep 17, 2015
1 parent 0ef9fc4 commit 9f11500
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 22 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ authors = ["Jonathan Anderson <[email protected]>"]

[dependencies]
byteorder = "0.3.11"
pcap = "0.3.2"
docopt = "0.6.70"
pcap = "0.4.2"
rustc-serialize="*"

[[bin]]
doc = false
Expand Down
140 changes: 119 additions & 21 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,131 @@
extern crate docopt;
extern crate rshark;
extern crate rustc_serialize;
extern crate pcap;

use pcap::Device;
use docopt::Docopt;


fn process(p: &pcap::Packet) {
print!("received {}-B packet:", p.data.len());
// TODO: use docopt_macros once rust-lang/rust#28089 is resolved
const USAGE: &'static str = "
Usage: rshark [options] <source>
rshark (--help | --version)
match rshark::ethernet::dissect(p.data) {
Err(e) => println!["Error: {}", e],
Ok(p) => print!["{}", p.pretty_print(1)],
}
Options:
-f, --filter BFP filter (see http://biot.com/capstats/bpf.html)
-h, --help Show this message
-p, --promiscuous Listen to all packets
-s, --snaplen=<len> Bytes to capture from each packet [default: 5000]
-t, --timeout=<ms> Packet read timeout, in ms [default: 10]
-v, --version Show the version of rshark
";

const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");


#[derive(RustcDecodable)]
struct Args {
arg_source: String,
flag_filter: String,
flag_snaplen: i32,
flag_timeout: i32,
flag_promiscuous: bool,
flag_version: bool,
}

type PcapResult = Result<pcap::Capture<pcap::Activated>, pcap::Error>;


fn main() {
let dev = Device::lookup().unwrap();
println!("Device name: {}", dev.name);

let mut cap = pcap::Capture::from_device(dev).unwrap()
.promisc(true)
.snaplen(5000)
.timeout(10)
.open().unwrap();

loop {
match cap.next() {
Some(ref packet) => { process(packet); },
None => {},
}
let args: Args = Docopt::new(USAGE)
.and_then(|d| d.argv(std::env::args()).decode())
.unwrap_or_else(|e| e.exit())
;

if args.flag_version {
println!["rshark v{}", VERSION.unwrap_or("<unknown>")];
return;
}

let result = open_capture(&args)
.map(|mut c| {
let mut count = 0;

while let Some(packet) = c.next() {
println!("received {}-B packet:", packet.data.len());

match rshark::ethernet::dissect(packet.data) {
Ok(dissected) => print!["{}", dissected.pretty_print(1)],
Err(e) => println!["Error: {}", e],
}

count += 1;
}

count
})
;


match result {
Ok(packet_count) => println!["Processed {} packets", packet_count],
Err(e) => {
println!["{}", e];
std::process::exit(1);
},
}
}


fn open_capture(args: &Args) -> PcapResult {
let device = try![open_device(args)];

let capture = match device {
Some(d) => Ok(d),
None => open_file(&args.arg_source),
};

capture.and_then(|mut c| {
try![c.filter(&args.flag_filter)];
Ok(c)
})
}

fn open_device(args: &Args)
-> Result<Option<pcap::Capture<pcap::Activated>>, pcap::Error> {

match pcap::Device::list() {
Ok(devices) => {
for d in devices {
if d.name == args.arg_source {
return pcap::Capture::from_device(d)
.map(|d| d.promisc(args.flag_promiscuous)
.rfmon(args.flag_promiscuous)
.snaplen(args.flag_snaplen)
.timeout(args.flag_timeout))
.and_then(|d| d.open())
.map(|c| c.into())
.map(Some)
;
}
};

Ok(None)
},
Err(e) => Err(e),
}
}

fn open_file(filename: &str) -> PcapResult {
std::fs::metadata(filename)
.map_err(|e| pcap::Error::PcapError(format!["{}", e]))
.and_then(|f|
if f.is_file() {
pcap::Capture::from_file(filename)
.map(|c| c.into())
} else {
Err(pcap::Error::PcapError(
format!["{} is not a file or interface", filename]))
}
)
}

0 comments on commit 9f11500

Please sign in to comment.