Add proper argument parsing to s_client

This commit is contained in:
Joseph Birr-Pixton 2016-06-01 00:15:45 +01:00
parent 940cd7dd45
commit 5f165fb5b1
8 changed files with 76 additions and 233 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
Cargo.lock

209
Cargo.lock generated
View File

@ -1,209 +0,0 @@
[root]
name = "rustls"
version = "0.1.0"
dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ring 0.1.0 (git+https://github.com/briansmith/ring)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"webpki 0.1.0 (git+https://github.com/ctz/webpki)",
]
[[package]]
name = "bitflags"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bytes"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "log"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "mio"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "miow"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "net2"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nix"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-bigint 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-bigint"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-iter"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ring"
version = "0.1.0"
source = "git+https://github.com/briansmith/ring#04a92e6b64a3bb52b7dff7a5000b4bc925519c55"
dependencies = [
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-serialize"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "slab"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "time"
version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "webpki"
version = "0.1.0"
source = "git+https://github.com/ctz/webpki#b5b5f7a0b87ebe9c7aa4fd767bd4236b39ad3c7d"
dependencies = [
"ring 0.1.0 (git+https://github.com/briansmith/ring)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

View File

@ -9,7 +9,10 @@ ring = { version = "0.1.0", git = "https://github.com/briansmith/ring" }
# pointed at my fork for the moment
webpki = { version = "0.1.0", git = "https://github.com/ctz/webpki" }
mio = "0.5.1"
time = "0.1.35"
rustc-serialize = "0.3"
log = "0.3.6"
[dev-dependencies]
mio = "0.5.1"
docopt = "0.6"

View File

@ -8,6 +8,10 @@ use std::str;
use std::io;
use std::io::{Read, Write, BufReader};
extern crate rustc_serialize;
extern crate docopt;
use docopt::Docopt;
extern crate rustls;
const CLIENT: mio::Token = mio::Token(0);
@ -37,7 +41,7 @@ impl mio::Handler for TlsClient {
}
if self.is_closed() {
println!("closing connection");
println!("Connection closed");
process::exit(1);
}
@ -69,9 +73,9 @@ impl io::Read for TlsClient {
}
impl TlsClient {
fn new(sock: TcpStream, hostname: &str) -> TlsClient {
fn new(sock: TcpStream, hostname: &str, cafile: &str) -> TlsClient {
let mut config = rustls::client::ClientConfig::default();
let certfile = std::fs::File::open("/etc/ssl/certs/ca-certificates.crt")
let certfile = std::fs::File::open(cafile)
.unwrap();
let mut reader = BufReader::new(certfile);
config.root_store.add_pem_file(&mut reader)
@ -86,23 +90,30 @@ impl TlsClient {
}
}
fn read_source_to_end(&mut self, rd: &mut io::Read) -> io::Result<usize> {
let mut buf = Vec::new();
let len = try!(rd.read_to_end(&mut buf));
self.tls_session.write(&buf).unwrap();
Ok(len)
}
fn do_read(&mut self) {
let rc = self.tls_session.read_tls(&mut self.socket);
if rc.is_err() {
println!("read error {:?}", rc);
println!("TLS read error: {:?}", rc);
self.closing = true;
return;
}
if rc.unwrap() == 0 {
println!("eof");
println!("EOF");
self.closing = true;
return;
}
let processed = self.tls_session.process_new_packets();
if processed.is_err() {
println!("cannot process packet: {:?}", processed);
println!("TLS error: {:?}", processed.unwrap_err());
self.closing = true;
return;
}
@ -111,19 +122,18 @@ impl TlsClient {
let mut plaintext = Vec::new();
let rc = self.tls_session.read_to_end(&mut plaintext);
if plaintext.len() > 0 {
println!("got {}", str::from_utf8(&plaintext).unwrap());
io::stdout().write(&plaintext).unwrap();
}
if rc.is_err() {
println!("plaintext read error {:?}", rc.unwrap_err());
println!("Plaintext read error: {:?}", rc.unwrap_err());
self.closing = true;
return;
}
}
fn do_write(&mut self) {
let rc = self.tls_session.write_tls(&mut self.socket);
println!("write rc={:?}", rc);
self.tls_session.write_tls(&mut self.socket).unwrap();
}
fn register(&self, event_loop: &mut mio::EventLoop<TlsClient>) {
@ -160,27 +170,65 @@ impl TlsClient {
}
}
const USAGE: &'static str = "
Connects to the TLS server at hostname:PORT. The default PORT
is 443. By default, this reads a request from stdin (to EOF)
before making the connection. --http replaces this with a
basic HTTP GET request for /.
Usage:
tlsclient [-p PORT] [--http] [--cafile CAFILE] <hostname>
tlsclient --version
tlsclient --help
Options:
-p, --port PORT Connect to PORT. Default is 443.
--http Send a basic HTTP GET request for /.
--cafile CAFILE Read root certificates from CAFILE.
--version Show tool version.
--help Show this screen.
";
#[derive(Debug, RustcDecodable)]
struct Args {
flag_port: Option<u16>,
flag_http: bool,
flag_cafile: Option<String>,
arg_hostname: String
}
fn main() {
use std::net::ToSocketAddrs;
use std::env;
use std::process;
let args: Vec<String> = env::args().collect();
let version = env!("CARGO_PKG_NAME").to_string() + ", version: " + env!("CARGO_PKG_VERSION");
if args.len() != 2 {
println!("usage: {} hostname", args[0]);
println!("connects to <hostname> port 443, and sends a trivial HTTP request");
process::exit(1);
}
let args: Args = Docopt::new(USAGE)
.and_then(|d| Ok(d.help(true)))
.and_then(|d| Ok(d.version(Some(version))))
.and_then(|d| d.decode())
.unwrap_or_else(|e| e.exit());
let hostname = &args[1];
let port = 443;
let port = args.flag_port.unwrap_or(443);
let addr = (args.arg_hostname.as_str(), port).to_socket_addrs()
.unwrap()
.next()
.unwrap();
let cafile = args.flag_cafile.unwrap_or("/etc/ssl/certs/ca-certificates.crt".to_string());
let addr = (hostname.as_str(), port).to_socket_addrs().unwrap().next().unwrap();
let sock = TcpStream::connect(&addr).unwrap();
let mut tlsclient = TlsClient::new(sock, &args.arg_hostname, &cafile);
if args.flag_http {
let httpreq = format!("GET / HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n", args.arg_hostname);
tlsclient.write(httpreq.as_bytes()).unwrap();
} else {
let mut stdin = io::stdin();
tlsclient.read_source_to_end(&mut stdin).unwrap();
}
let mut event_loop = mio::EventLoop::new().unwrap();
let mut tlsclient = TlsClient::new(sock, &hostname);
tlsclient.write(format!("GET / HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n", hostname).as_bytes()).unwrap();
tlsclient.register(&mut event_loop);
event_loop.run(&mut tlsclient).unwrap();
}