1- extern crate clap ;
1+ extern crate hex ;
22extern crate hexplay;
33extern crate pnet;
44
5- use clap:: { value_t, App , Arg } ;
6-
5+ use hex:: FromHex ;
76use pnet:: datalink:: Channel :: Ethernet ;
87use pnet:: datalink:: { self , Config , NetworkInterface } ;
8+ use structopt:: StructOpt ;
99
1010use std:: io;
1111use std:: time:: { Duration , Instant } ;
@@ -21,82 +21,66 @@ fn print_interfaces() {
2121 }
2222}
2323
24+ /// A small utility for reading / writing directly to a network interface
25+ #[ derive( StructOpt , Debug ) ]
26+ #[ structopt(
27+ name = "NetHex" ,
28+ raw( setting = "structopt::clap::AppSettings::ColoredHelp" )
29+ ) ]
30+ struct Opt {
31+ /// Number of packet to receive before exiting
32+ #[ structopt( short = "c" , long = "count" , default_value = "-1" ) ]
33+ count : i64 ,
34+
35+ /// Number of packet to receive before exiting
36+ #[ structopt( short = "t" , long = "timeout" ) ]
37+ timeout : Option < u64 > ,
38+
39+ /// The network interface to listen on
40+ #[ structopt( name = "interface" ) ]
41+ interface : Option < String > ,
42+
43+ /// The hex bytes to send over the network
44+ #[ structopt( name = "bytes" ) ]
45+ bytes : Option < String > ,
46+ }
47+
2448// Invoke as echo <interface name>
2549fn main ( ) {
26- let matches = App :: new ( "NetHex" )
27- . version ( "0.1.0" )
28- . author ( "Jack Newman" )
29- . about ( "A small utility for reading / writing directly to a network interface" )
30- . arg (
31- Arg :: with_name ( "timeout" )
32- . short ( "t" )
33- . long ( "timeout" )
34- . takes_value ( true )
35- . help ( "Time before exiting the program" ) ,
36- )
37- . arg (
38- Arg :: with_name ( "count" )
39- . short ( "c" )
40- . long ( "count" )
41- . takes_value ( true )
42- . help ( "Number of packet to receive before exiting" )
43- . default_value ( "-1" ) ,
44- )
45- . arg (
46- Arg :: with_name ( "list" )
47- . short ( "l" )
48- . long ( "list" )
49- . help ( "List network interfaces" ) ,
50- )
51- . arg (
52- Arg :: with_name ( "interface" )
53- . help ( "The network interface to send/read from" )
54- . required_unless ( "list" ) ,
55- )
56- . arg (
57- Arg :: with_name ( "bytes" )
58- . help ( "A hex string of raw bytes to send to the interface e.g. 11EE22FF" ) ,
59- )
60- . get_matches ( ) ;
50+ let opt = Opt :: from_args ( ) ;
51+ // println!("{:?}", opt);
6152
62- // println!("{:?}", matches);
63- if matches . is_present ( "list" ) {
53+ // If the user did not specify any interface. List some to be helpful
54+ if let None = opt . interface {
6455 print_interfaces ( ) ;
6556 std:: process:: exit ( 0 ) ;
6657 } ;
6758
68- let rx_timeout = value_t ! ( matches, "timeout" , u64 )
69- . ok ( )
70- . map ( |time| Duration :: from_secs ( time) ) ;
71- let mut rx_countlimit = value_t ! ( matches, "count" , i64 ) . unwrap ( ) ;
72-
73- // Grab the input interface. No error checking as clap will exit if it does not exist
74- let interface_name = matches. value_of ( "interface" ) . unwrap ( ) ;
59+ let rx_timeout = opt. timeout . map ( |time| Duration :: from_secs ( time) ) ;
60+ let mut rx_countlimit = opt. count ;
7561
7662 // Find the network interface with the provided name
77- let interface_names_match = |iface : & NetworkInterface | iface. name == interface_name;
7863 let interfaces = datalink:: interfaces ( ) ;
7964 let interface = interfaces
8065 . into_iter ( )
81- . filter ( interface_names_match)
66+ // Safe to unwrap since print_interfaces will exit above
67+ . filter ( |iface : & NetworkInterface | iface. name == * opt. interface . as_ref ( ) . unwrap ( ) )
8268 . next ( )
8369 . expect ( "Could not find the network interface" ) ;
8470
85- // Create a new channel, dealing with layer 2 packets
86- let mut datalink_config = Config :: default ( ) ;
8771 // Set the timeout of the socket read to 10ms
88- datalink_config. read_timeout = Some ( std:: time:: Duration :: new ( 0 , 1e7 as u32 ) ) ;
72+ let mut datalink_config = Config :: default ( ) ;
73+ datalink_config. read_timeout = Some ( std:: time:: Duration :: new ( 0 , 1e7 as u32 ) ) ;
8974
75+ // Create a new channel, dealing with layer 2 packets
9076 let ( mut tx, mut rx) = match datalink:: channel ( & interface, datalink_config) {
9177 Ok ( Ethernet ( tx, rx) ) => ( tx, rx) ,
9278 Ok ( _) => panic ! ( "Unhandled channel type" ) ,
9379 Err ( e) => panic ! ( "Error while creating datalink channel: {:?}" , e) ,
9480 } ;
9581
9682 // Decode the hex input if the user specified one
97- if let Some ( arg) = matches. value_of ( "bytes" ) {
98- extern crate hex;
99- use hex:: FromHex ;
83+ if let Some ( arg) = opt. bytes {
10084 let bytes = match Vec :: from_hex ( arg) {
10185 Ok ( bytes) => bytes,
10286 Err ( e) => {
@@ -106,11 +90,11 @@ fn main() {
10690 } ;
10791 // Transmit those bytes
10892 println ! ( "Sending bytes: {:X?}" , bytes) ;
109- let res = tx. send_to ( & bytes, None ) . unwrap ( ) ;
93+ let res = tx. send_to ( & bytes, None ) . unwrap ( ) ;
11094 if let Err ( error) = res {
111- println ! ( "{:?}" , error) ;
112- std:: process:: exit ( 1 ) ;
113- } ;
95+ println ! ( "{:?}" , error) ;
96+ std:: process:: exit ( 1 ) ;
97+ } ;
11498 }
11599
116100 // Now do the Rx part
0 commit comments