Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pingora In Front Of HTTP/HTTPS Proxies #200

Open
ArielLahiany opened this issue Apr 12, 2024 · 4 comments
Open

Pingora In Front Of HTTP/HTTPS Proxies #200

ArielLahiany opened this issue Apr 12, 2024 · 4 comments
Assignees
Labels
enhancement New feature or request

Comments

@ArielLahiany
Copy link

Trying to setup a Pingora-based logic in front of an HTTP/HTTPS proxy (Squid etc) without luck.
When creating an HTTP request over cURL, the logic works as expected.
When creating an HTTPS request, the following error is shown:

cURL

curl: (56) CONNECT tunnel failed, response 502

Pingora

[ERROR pingora_proxy] Fail to proxy: Upstream ConnectError context: Fail to establish CONNECT proxy: addr: 127.0.0.1:3128, scheme: HTTP,proxy: next_hop: 127.0.0.1:3128, host: 127.0.0.1, port: 3128, cause:  context: CONNECT proxy connect() error to "127.0.0.1:3128" cause:  context: Fail to connect to 127.0.0.1:3128 cause: No such file or directory (os error 2), status: 502, tries: 1, retry: false, CONNECT google.com:443, Host: google.com:443

I know it related to the fact the HTTPS proxy are working over tunnels and the CONNECT method, and I'm not trying to create an SSL MITM proxy to read the content of the request. Just to be able to use the request_filter method of the ProxyHttp trait of Pingora.

Pingora

use async_trait::async_trait;

use pingora::proxy::{http_proxy_service, ProxyHttp, Session};
use pingora::server::Server;
use pingora::upstreams::peer::HttpPeer;
use pingora::Result;

pub struct Gateway {}

#[async_trait]
impl ProxyHttp for Gateway {
    type CTX = ();
    fn new_ctx(&self) -> Self::CTX {}

    async fn upstream_peer(
        &self,
        _session: &mut Session,
        _ctx: &mut Self::CTX,
    ) -> Result<Box<HttpPeer>> {
        Ok(Box::new(HttpPeer::new(
            ("127.0.0.1", 3128),
            false,
            "".to_string(),
        )))
    }
}

fn main() {
    env_logger::init();
    let mut server = Server::new(None).unwrap();
    server.bootstrap();
    let mut service = http_proxy_service(&server.configuration, Gateway {});
    service.add_tcp("0.0.0.0:8080");
    server.add_service(service);
    server.run_forever();
}

Squid

acl SSL_ports port 443
acl Safe_ports port 80
acl Safe_ports port 443
acl CONNECT method CONNECT

http_access allow localhost manager
http_access allow localhost
http_access allow localnet
http_access deny manager
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access deny all

cache deny all

coredump_dir /var/spool/squid

logfile_rotate 10

cURL

curl -x http://localhost:8080 https://google.com
curl: (56) CONNECT tunnel failed, response 502

Would really appropriate a push in the right direction.

@ArielLahiany ArielLahiany changed the title Pingora Infront Of HTTP/HTTPS Proxies Pingora In front Of HTTP/HTTPS Proxies Apr 12, 2024
@ArielLahiany ArielLahiany changed the title Pingora In front Of HTTP/HTTPS Proxies Pingora In Front Of HTTP/HTTPS Proxies Apr 12, 2024
@andrewhavck
Copy link
Contributor

Is the example you provided here complete? We shouldn't be invoking proxy_connect unless new_proxy is called or proxy is set on HttpPeer.

If I try your example code I see:

2024-04-12T22:21:26Z ERROR pingora_proxy] Fail to proxy: Upstream ConnectRefused context: Fail to connect to addr: 127.0.0.1:3128, scheme: HTTP, cause:  context: Fail to connect to 127.0.0.1:3128 cause: Connection refused (os error 61), status: 502, tries: 1, retry: false, CONNECT google.com:443, Host: google.com:443

The error log you provided is happening because right now proxy_connect expects a UDS.

@ArielLahiany
Copy link
Author

The code snippets I've added are full. I'm using it on an MacOS Intel machine if that make any diffrence.
I'm attaching here the full Pingora service logs:

[2024-04-13T14:46:16Z INFO  pingora_core::server] Bootstrap starting
[2024-04-13T14:46:16Z DEBUG pingora_core::server] None
[2024-04-13T14:46:16Z INFO  pingora_core::server] Bootstrap done
[2024-04-13T14:46:16Z INFO  pingora_core::server] Server starting
[2024-04-13T14:47:12Z DEBUG pingora_core::services::listening] new event!
[2024-04-13T14:47:12Z DEBUG pingora_proxy] Successfully get a new request
[2024-04-13T14:47:12Z DEBUG pingora_core::connectors] No reusable connection found for addr: 127.0.0.1:3128, scheme: HTTP,
[2024-04-13T14:47:12Z DEBUG pingora_core::connectors::l4] connected to new server: 127.0.0.1:3128
[2024-04-13T14:47:12Z DEBUG pingora_proxy::proxy_h1] Sending header to upstream RequestHeader { base: Parts { method: CONNECT, uri: google.com:443, version: HTTP/1.1, headers: {"host": "google.com:443", "user-agent": "curl/8.4.0", "proxy-connection": "Keep-Alive"} }, header_name_map: Some({"host": CaseHeaderName(b"Host"), "user-agent": CaseHeaderName(b"User-Agent"), "proxy-connection": CaseHeaderName(b"Proxy-Connection")}), raw_path_fallback: [] }
[2024-04-13T14:47:12Z DEBUG pingora_proxy::proxy_h1] finish sending body to upstream
[2024-04-13T14:47:12Z DEBUG pingora_core::protocols::http::v1::client] Response header: ResponseHeader { base: Parts { status: 200, version: HTTP/1.1, headers: {} }, header_name_map: Some({}) }
[2024-04-13T14:47:12Z DEBUG pingora_proxy::proxy_h1] upstream event: Some(Header(ResponseHeader { base: Parts { status: 200, version: HTTP/1.1, headers: {} }, header_name_map: Some({}) }, false))
[2024-04-13T14:47:12Z DEBUG pingora_proxy::proxy_h1] downstream event
[2024-04-13T14:47:12Z DEBUG pingora_core::protocols::l4::stream] Dropping socket BufStream { inner: BufReader { reader: BufWriter { writer: Tcp(PollEvented { io: Some(TcpStream { addr: 127.0.0.1:49747, peer: 127.0.0.1:3128, fd: 16 }) }), buffer: 0/1460, written: 0 }, buffer: 0/65536 } }
[2024-04-13T14:47:12Z WARN  pingora_core::protocols::http::v1::server] Respond header is already sent, cannot send again
[2024-04-13T14:47:12Z ERROR pingora_proxy] Fail to proxy: Downstream ConnectError context: Peer: addr: 127.0.0.1:3128, scheme: HTTP, cause:  context: Sent data after end of body, status: 400, tries: 1, retry: false, CONNECT google.com:443, Host: google.com:443
[2024-04-13T14:47:12Z DEBUG pingora_core::protocols::l4::stream] Dropping socket BufStream { inner: BufReader { reader: BufWriter { writer: Tcp(PollEvented { io: Some(TcpStream { addr: 127.0.0.1:8080, peer: 127.0.0.1:49746, fd: 15 }) }), buffer: 0/1460, written: 0 }, buffer: 319/65536 } }

And the cURL command resulted in:

curl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to google.com:443

Should I configure Pingora differently?
I was manage to make it with in duplex mode with the example from here but then I can't use the request_filter method.

@vicanso
Copy link

vicanso commented Apr 25, 2024

I try to proxy http://localhost:6018/ to https://www.baidu.com/, set HttpPeer::new(("120.232.145.185", 443), true, "www.baidu.com").

image

@andrewhavck
Copy link
Contributor

Circling back to this it looks like there's an issue handling CONNECT responses.

[2024-04-13T14:47:12Z WARN  pingora_core::protocols::http::v1::server] Respond header is already sent, cannot send again

@andrewhavck andrewhavck added the enhancement New feature or request label Apr 26, 2024
@andrewhavck andrewhavck self-assigned this Apr 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants