From 3a14e9a6be778fb44df7e69b1586894639026f2a Mon Sep 17 00:00:00 2001 From: Johan Anderholm Date: Sat, 24 Mar 2018 08:00:38 +0000 Subject: [PATCH] Validate proxy urls better. Use the url crate to handle proxies to make sure they conform to a proper format. --- Cargo.toml | 2 +- core/Cargo.toml | 1 + core/src/apresolve.rs | 11 ++++++----- core/src/config.rs | 3 ++- core/src/connection/mod.rs | 19 ++++--------------- core/src/lib.rs | 1 + core/src/proxytunnel.rs | 2 +- src/main.rs | 20 +++++++++++++++++++- 8 files changed, 35 insertions(+), 24 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5e392695..3af02908 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ serde_json = "0.9.5" tokio-core = "0.1.2" tokio-io = "0.1" tokio-signal = "0.1.2" -url = "1.3" +url = "1.7.0" [build-dependencies] rand = "0.3.13" diff --git a/core/Cargo.toml b/core/Cargo.toml index c0bafbe1..ed1206aa 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -32,6 +32,7 @@ serde_json = "0.9.5" shannon = "0.2.0" tokio-core = "0.1.2" tokio-io = "0.1" +url = "1.7.0" uuid = { version = "0.4", features = ["v4"] } [build-dependencies] diff --git a/core/src/apresolve.rs b/core/src/apresolve.rs index db3b8d7a..9ff23cf3 100644 --- a/core/src/apresolve.rs +++ b/core/src/apresolve.rs @@ -8,6 +8,7 @@ use hyper_proxy::{Intercept, Proxy, ProxyConnector}; use serde_json; use std::str::FromStr; use tokio_core::reactor::Handle; +use url::Url; error_chain!{} @@ -16,14 +17,14 @@ pub struct APResolveData { ap_list: Vec, } -fn apresolve(handle: &Handle, proxy: &Option) -> Box> { +fn apresolve(handle: &Handle, proxy: &Option) -> Box> { let url = Uri::from_str(APRESOLVE_ENDPOINT).expect("invalid AP resolve URL"); let use_proxy = proxy.is_some(); let mut req = Request::new(Method::Get, url.clone()); - let response = match proxy { - &Some(ref val) => { - let proxy_url = Uri::from_str(&val).expect("invalid http proxy"); + let response = match *proxy { + Some(ref val) => { + let proxy_url = Uri::from_str(val.as_str()).expect("invalid http proxy"); let proxy = Proxy::new(Intercept::All, proxy_url); let connector = HttpConnector::new(4, handle); let proxy_connector = ProxyConnector::from_proxy_unsecured(connector, proxy); @@ -73,7 +74,7 @@ fn apresolve(handle: &Handle, proxy: &Option) -> Box( handle: &Handle, - proxy: &Option, + proxy: &Option, ) -> Box> where E: 'static, diff --git a/core/src/config.rs b/core/src/config.rs index 7afedcbd..3511ee3f 100644 --- a/core/src/config.rs +++ b/core/src/config.rs @@ -1,5 +1,6 @@ use std::fmt; use std::str::FromStr; +use url::Url; use uuid::Uuid; use version; @@ -8,7 +9,7 @@ use version; pub struct SessionConfig { pub user_agent: String, pub device_id: String, - pub proxy: Option, + pub proxy: Option, } impl Default for SessionConfig { diff --git a/core/src/connection/mod.rs b/core/src/connection/mod.rs index dec4daf6..7e527b20 100644 --- a/core/src/connection/mod.rs +++ b/core/src/connection/mod.rs @@ -5,14 +5,13 @@ pub use self::codec::APCodec; pub use self::handshake::handshake; use futures::{Future, Sink, Stream}; -use hyper::Uri; use protobuf::{self, Message}; use std::io; use std::net::ToSocketAddrs; -use std::str::FromStr; use tokio_core::net::TcpStream; use tokio_core::reactor::Handle; use tokio_io::codec::Framed; +use url::Url; use authentication::Credentials; use version; @@ -24,22 +23,12 @@ pub type Transport = Framed; pub fn connect( addr: String, handle: &Handle, - proxy: &Option, + proxy: &Option, ) -> Box> { let (addr, connect_url) = match *proxy { Some(ref url) => { - let url = Uri::from_str(url).expect("Malformed proxy address"); - let host = url.host().expect("Malformed proxy address: no host"); - let port = url.port().unwrap_or(3128); - - ( - format!("{}:{}", host, port) - .to_socket_addrs() - .unwrap() - .next() - .unwrap(), - Some(addr.clone()), - ) + info!("Using proxy \"{}\"", url); + (url.to_socket_addrs().unwrap().next().unwrap(), Some(addr)) } None => (addr.to_socket_addrs().unwrap().next().unwrap(), None), }; diff --git a/core/src/lib.rs b/core/src/lib.rs index e7b4b3c7..053e4191 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -30,6 +30,7 @@ extern crate serde_json; extern crate shannon; extern crate tokio_core; extern crate tokio_io; +extern crate url; extern crate uuid; extern crate librespot_protocol as protocol; diff --git a/core/src/proxytunnel.rs b/core/src/proxytunnel.rs index 3f1db053..5e07db99 100644 --- a/core/src/proxytunnel.rs +++ b/core/src/proxytunnel.rs @@ -96,7 +96,7 @@ impl Future for ProxyTunnel { } fn proxy_connect(connection: T, connect_url: &str) -> WriteAll> { - let uri = Uri::from_str(&connect_url).unwrap(); + let uri = Uri::from_str(connect_url).unwrap(); let buffer = format!( "CONNECT {0}:{1} HTTP/1.1\r\n\ \r\n", diff --git a/src/main.rs b/src/main.rs index b7654e1b..afca4c01 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ extern crate rpassword; extern crate tokio_core; extern crate tokio_io; extern crate tokio_signal; +extern crate url; use crypto::digest::Digest; use crypto::sha1::Sha1; @@ -23,6 +24,7 @@ use std::process::exit; use std::str::FromStr; use tokio_core::reactor::{Core, Handle}; use tokio_io::IoStream; +use url::Url; use librespot::core::authentication::{get_credentials, Credentials}; use librespot::core::cache::Cache; @@ -248,7 +250,23 @@ fn setup(args: &[String]) -> Setup { SessionConfig { user_agent: version::version_string(), device_id: device_id, - proxy: matches.opt_str("proxy").or(std::env::var("http_proxy").ok()), + proxy: matches.opt_str("proxy").or(std::env::var("http_proxy").ok()).map( + |s| { + match Url::parse(&s) { + Ok(url) => { + if url.host().is_none() || url.port().is_none() { + panic!("Invalid proxy url, only urls on the format \"http://host:port\" are allowed"); + } + + if url.scheme() != "http" { + panic!("Only unsecure http:// proxies are supported"); + } + url + }, + Err(err) => panic!("Invalid proxy url: {}, only urls on the format \"http://host:port\" are allowed", err) + } + }, + ), } };