caddyserver / forwardproxy

Forward proxy plugin for the Caddy web server
Apache License 2.0
599 stars 228 forks source link

Can not access web site on itself host via forwardproxy #12

Open jim3ma opened 6 years ago

jim3ma commented 6 years ago

e.g: We have a forwardproxy for https://proxy.plus on host A, and a web site https://web.plus ( different from proxy.plus ) on the same host with caddy. P.S. enable tls always.

When browse the https://web.plus via https://proxy.plus proxy, chrome says "ERR_TUNNEL_CONNECTION_FAILED".

Other web sites work okay via https://proxy.plus.

jim3ma commented 6 years ago

When browse https://web.plus, caddy gives the vhost web.plus which should be proxy.plus. The code: https://github.com/mholt/caddy/blob/master/caddyhttp/httpserver/server.go#L385

sergeyfrolov commented 6 years ago

Thanks for the report! I am not sure when I'll be able to dive into this issue, and PRs are always welcome.

When browse https://web.plus, caddy gives the vhost web.plus which should be proxy.plus. IIRC, vhost is determined by Host header, which is web.plus.

The problem is most likely that Caddy receives:

CONNECT web.plus HTTP/1.1
Host: web.plus 

which is proxying request that should have internally went to proxy.plus, but Caddy matches it to web.plus and sends it there for processing. Then the standard web.plus chain of middleware won't know what to do with this wierd request. The fix will probably involve changes to the Caddy itself, I am not quite sure what would be an elegant solution. /cc @mholt

P.S. as a temporary workaround you can try using PAC files, to make browser use DIRECT connection to web.plus and not send CONNECT requests to Caddy.

bemasc commented 6 years ago

@jim3ma, what client software are you using?

jim3ma commented 6 years ago

@bemasc just Chrome with SwitchyOmega. @mholt can you consider to extend some config for caddy to match host customize ?

mholt commented 6 years ago

I think I know why this is happening. Caddy is programmed to handle requests by Host header, to choose the middleware chain it follows. For any Host that doesn't match one defined in the Caddyfile, it routes to a forwardproxy chain, if configured. But in this case, Caddy has a site defined for the Host name you're trying to access via a proxy.

How would Caddy know which middleware chain to use?

sergeyfrolov commented 6 years ago

We could send all CONNECT requests into middleware chain with forwardproxy, but that doesn't integrate very well into current host matching logic of Caddy.

As an aside, here's another temporary workaround: add forwardproxy to all your chains.

jim3ma commented 6 years ago

@mholt When chrome uses forwardproxy, chrome dials proxy.plus with tls. The tls connection knows the right host is proxy.plus with SNI, so when match vhost, Caddy should consider the SNI hostname.

jim3ma commented 6 years ago

BTW, each vhost has the supported methods like POST, GET, DELETE. When match vhost, the supported methods should be considered.

jim3ma commented 6 years ago

@sergeyfrolov add forwardproxy to all chains seems not work for proxy directive.

sergeyfrolov commented 6 years ago

Caddy should consider the SNI hostname

Webservers generally don't do this, and there are setups that rely on this not being the case. Among other more general network configurations, the fact that webservers don't prioritize SNI in vhost matching is how Domain Fronting censorship circumvention technique works.

BTW each vhost has the supported methods like POST, GET, DELETE. supported methods should be considered

If supported methods are known for each vhost, then this might work. Currently, when forwardproxy loads, it sets the chain it's in to be a fallback for unmatched hosts. We can disable CONNECTs on all vhosts but forwardproxying one and allow CONNECT requests to be handled by fallback. As an added advantage, we would be able use FallbackHost only for unmatched CONNECT requests, as opposed to current state of things in which all and every unmatched request goes into forwardproxying chain.

mholt commented 6 years ago

How about a flag like -sni-first that tells Caddy to try matching a site based on the SNI name and then, if there are no matches, to use the Host header instead?

jim3ma commented 6 years ago

The sni-first option is okay. So we did not hack the match method which always move traffic to forwardproxy.