Browse Source

Validate proxy urls better.

Use the url crate to handle proxies to make sure they conform to a
proper format.
Johan Anderholm 6 years ago
parent
commit
3a14e9a6be
8 changed files with 35 additions and 24 deletions
  1. 1 1
      Cargo.toml
  2. 1 0
      core/Cargo.toml
  3. 6 5
      core/src/apresolve.rs
  4. 2 1
      core/src/config.rs
  5. 4 15
      core/src/connection/mod.rs
  6. 1 0
      core/src/lib.rs
  7. 1 1
      core/src/proxytunnel.rs
  8. 19 1
      src/main.rs

+ 1 - 1
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"

+ 1 - 0
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]

+ 6 - 5
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<String>,
 }
 
-fn apresolve(handle: &Handle, proxy: &Option<String>) -> Box<Future<Item = String, Error = Error>> {
+fn apresolve(handle: &Handle, proxy: &Option<Url>) -> Box<Future<Item = String, Error = Error>> {
     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<String>) -> Box<Future<Item = Strin
 
 pub(crate) fn apresolve_or_fallback<E>(
     handle: &Handle,
-    proxy: &Option<String>,
+    proxy: &Option<Url>,
 ) -> Box<Future<Item = String, Error = E>>
 where
     E: 'static,

+ 2 - 1
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<String>,
+    pub proxy: Option<Url>,
 }
 
 impl Default for SessionConfig {

+ 4 - 15
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<TcpStream, APCodec>;
 pub fn connect(
     addr: String,
     handle: &Handle,
-    proxy: &Option<String>,
+    proxy: &Option<Url>,
 ) -> Box<Future<Item = Transport, Error = io::Error>> {
     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),
     };

+ 1 - 0
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;

+ 1 - 1
core/src/proxytunnel.rs

@@ -96,7 +96,7 @@ impl<T: AsyncRead + AsyncWrite> Future for ProxyTunnel<T> {
 }
 
 fn proxy_connect<T: AsyncWrite>(connection: T, connect_url: &str) -> WriteAll<T, Vec<u8>> {
-    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",

+ 19 - 1
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)
+            }
+                },
+            ),
         }
     };