From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <d.whyte@proxmox.com>
Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256)
 (No client certificate requested)
 by lists.proxmox.com (Postfix) with ESMTPS id 5BAA36CA12
 for <pbs-devel@lists.proxmox.com>; Tue, 30 Mar 2021 16:48:13 +0200 (CEST)
Received: from firstgate.proxmox.com (localhost [127.0.0.1])
 by firstgate.proxmox.com (Proxmox) with ESMTP id 465712C390
 for <pbs-devel@lists.proxmox.com>; Tue, 30 Mar 2021 16:47:43 +0200 (CEST)
Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com
 [212.186.127.180])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256)
 (No client certificate requested)
 by firstgate.proxmox.com (Proxmox) with ESMTPS id EC82C2C385
 for <pbs-devel@lists.proxmox.com>; Tue, 30 Mar 2021 16:47:41 +0200 (CEST)
Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1])
 by proxmox-new.maurer-it.com (Proxmox) with ESMTP id B2E1F4596D
 for <pbs-devel@lists.proxmox.com>; Tue, 30 Mar 2021 16:47:41 +0200 (CEST)
From: Dylan Whyte <d.whyte@proxmox.com>
To: pbs-devel@lists.proxmox.com
Date: Tue, 30 Mar 2021 16:47:24 +0200
Message-Id: <20210330144725.7892-1-d.whyte@proxmox.com>
X-Mailer: git-send-email 2.20.1
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-SPAM-LEVEL: Spam detection results:  0
 AWL 0.016 Adjusted score from AWL reputation of From: address
 KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment
 RCVD_IN_DNSWL_MED        -2.3 Sender listed at https://www.dnswl.org/,
 medium trust
 SPF_HELO_NONE           0.001 SPF: HELO does not publish an SPF Record
 SPF_PASS               -0.001 SPF: sender matches SPF record
 URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See
 http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more
 information. [lib.rs, subscription.rs, http.rs, maurer-it.com]
Subject: [pbs-devel] [PATCH v2 proxmox-backup 1/2] fix #3296: allow set
 subscription through proxy
X-BeenThere: pbs-devel@lists.proxmox.com
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: Proxmox Backup Server development discussion
 <pbs-devel.lists.proxmox.com>
List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pbs-devel>, 
 <mailto:pbs-devel-request@lists.proxmox.com?subject=unsubscribe>
List-Archive: <http://lists.proxmox.com/pipermail/pbs-devel/>
List-Post: <mailto:pbs-devel@lists.proxmox.com>
List-Help: <mailto:pbs-devel-request@lists.proxmox.com?subject=help>
List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel>, 
 <mailto:pbs-devel-request@lists.proxmox.com?subject=subscribe>
X-List-Received-Date: Tue, 30 Mar 2021 14:48:13 -0000

when setting a subscription key from the cli, use http(s)_proxy as tunnel if
evironment variable is set.

Note: adds hyper-proxy crate and bumps bumps base64 to v0.13, due to a
dependency of hyper-proxy.

Signed-off-by: Dylan Whyte <d.whyte@proxmox.com>
---
Changes v1 -> v2:
- Accept proxy as optional argument to post function
- Create proxy client in separate function
- Read proxy env variable in register_subscription(..)
    - Include fixme note to change to config file later
- Code cleanup

Notes:
v2:
- This is currently just for the command line. To do this over the API,
  it would be better to have a config file.
- I am also leaving the apt configuration until the plan for this config
  file is confirmed.

v1:
* required packages can be found in nasi/iso/packages/hyper-proxy

Note that proxy authorization/authentication is not implemented yet.
hyper-proxy implements it using the 'headers' crate, which we do
not have as a direct dependency. I figured i'd leave it for a
follow up patch, just in case we decide not to use hyper-proxy afterall.


 Cargo.toml                |  3 ++-
 src/tools/http.rs         | 29 ++++++++++++++++++++++++++---
 src/tools/subscription.rs |  6 +++++-
 3 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index b0ef56bd..044bcd48 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,7 +24,7 @@ path = "src/lib.rs"
 
 [dependencies]
 apt-pkg-native = "0.3.2"
-base64 = "0.12"
+base64 = "0.13"
 bitflags = "1.2.1"
 bytes = "1.0"
 crc32fast = "1"
@@ -74,6 +74,7 @@ xdg = "2.2"
 zstd = { version = "0.4", features = [ "bindgen" ] }
 nom = "5.1"
 crossbeam-channel = "0.5"
+hyper-proxy = { version = "0.9", default-features = false, features = ["openssl-tls"] }
 
 [features]
 default = []
diff --git a/src/tools/http.rs b/src/tools/http.rs
index d08ce451..8d940d01 100644
--- a/src/tools/http.rs
+++ b/src/tools/http.rs
@@ -7,6 +7,7 @@ use std::pin::Pin;
 
 use hyper::{Uri, Body};
 use hyper::client::{Client, HttpConnector};
+use hyper_proxy::{Proxy, ProxyConnector, Intercept};
 use http::{Request, Response};
 use openssl::ssl::{SslConnector, SslMethod};
 use futures::*;
@@ -62,6 +63,7 @@ pub async fn post(
     uri: &str,
     body: Option<String>,
     content_type: Option<&str>,
+    proxy: Option<String>
 ) -> Result<Response<Body>, Error> {
     let body = if let Some(body) = body {
         Body::from(body)
@@ -77,10 +79,31 @@ pub async fn post(
         .header(hyper::header::CONTENT_TYPE, content_type)
         .body(body)?;
 
+    if let Some(proxy) = proxy {
+        let client = proxy_connector(proxy)?;
+        client.request(request)
+            .map_err(Error::from)
+            .await
+    } else {
+        HTTP_CLIENT.request(request)
+            .map_err(Error::from)
+            .await
+    }
+}
+
+fn proxy_connector(proxy_addr: String) -> Result<Client<ProxyConnector<HttpConnector>, Body>, Error> {
+    let proxy = format!("http://{}/", proxy_addr);
+    let proxy = {
+        let proxy_uri = proxy.parse()?;
+        let proxy = Proxy::new(Intercept::All, proxy_uri);
+        let connector = HttpConnector::new();
+        let proxy_connector = ProxyConnector::from_proxy(connector, proxy)?;
+        proxy_connector
+    };
+
+    let client = Client::builder().build(proxy);
 
-    HTTP_CLIENT.request(request)
-        .map_err(Error::from)
-        .await
+    Ok(client)
 }
 
 #[derive(Clone)]
diff --git a/src/tools/subscription.rs b/src/tools/subscription.rs
index 9b9534ac..d7ff6eeb 100644
--- a/src/tools/subscription.rs
+++ b/src/tools/subscription.rs
@@ -104,7 +104,11 @@ async fn register_subscription(
     });
     let uri = "https://shop.maurer-it.com/modules/servers/licensing/verify.php";
     let query = tools::json_object_to_query(params)?;
-    let response = http::post(uri, Some(query), Some("application/x-www-form-urlencoded")).await?;
+
+    // FIXME: get proxy from config file rather than environment variable
+    let http_proxy = std::env::var("https_proxy").or(std::env::var("http_proxy")).ok();
+
+    let response = http::post(uri, Some(query), Some("application/x-www-form-urlencoded"), http_proxy).await?;
     let body = http::response_body_string(response).await?;
 
     Ok((body, challenge))
-- 
2.20.1