Parse Host field

We stopped parsing hostname from Host field, this fixes it back.
Implicit port 80 is good not only for GET, so I changed the logic to try
port 80 on all non-connects.
While testing, I also realized that switchy omega doesn't actually presend credentials,
(somehow I thought it did), so I removed a link to it from the README.md to avoid
confusion.
Fixes #36
This commit is contained in:
Sergey Frolov 2018-07-03 11:23:13 -04:00
parent 7791846e12
commit 3e8b65c3af
2 changed files with 28 additions and 21 deletions

View file

@ -48,7 +48,7 @@ Proxy will no longer respond with "407 Proxy Authentication Required" if credent
and will attempt to mimic a generic Caddy web server as if the forward proxy is not enabled.
Probing resistance works (and makes sense) only if basicauth is set up.
To use your proxy with probe resistance, supply your basicauth credentials to your client configuration.
If your proxy client(browser, operating system, [browser extension](https://chrome.google.com/webstore/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif), etc.)
If your proxy client(browser, operating system, browser extension, etc)
allows you to preconfigure credentials, and sends credentials preemptively, you do not need secret link.
If your proxy client does not preemptively send credentials, you will have to visit your secret link in your browser to trigger the authentication.
Make sure that specified domain name is visitable, does not contain uppercase characters, does not start with dot, etc.

View file

@ -235,50 +235,57 @@ func (fp *ForwardProxy) servePacFile(w http.ResponseWriter) (int, error) {
}
// bool indicates whether it was rejected as "Forbidden"
// TODO: after custom errors are implemented package-wide, remove the bool
// TODO: after custom status code-based errors are implemented package-wide, remove the bool
func (fp *ForwardProxy) dialRequestedAddress(r *http.Request) (net.Conn, error, bool) {
var err error
var conn net.Conn
if fp.upstream != "" {
// if upstreaming -- do not resolve locally nor check acl
conn, err = fp.dial("tcp", r.URL.Host)
return conn, err, false
hostPort := r.URL.Host
if hostPort == "" {
hostPort = r.Host
}
port := r.URL.Port()
if port == "" {
switch r.Method {
case http.MethodGet:
port = "80" // implicit port for GET requests
case http.MethodConnect:
return nil, errors.New("port is required for CONNECT " + r.URL.String()), true
default:
return nil, errors.New("Method " + r.Method + " is not allowed"), true
host, port, err := net.SplitHostPort(hostPort)
if err != nil {
if r.Method == http.MethodConnect {
return nil, err, false
}
// for other methods, try implicit port 80
hostPort = net.JoinHostPort(hostPort, "80")
host, port, err = net.SplitHostPort(hostPort)
if err != nil {
return nil, err, false
}
}
if fp.upstream != "" {
// if upstreaming -- do not resolve locally nor check acl
conn, err = fp.dial("tcp", hostPort)
return conn, err, false
}
if !fp.portIsAllowed(port) {
return nil, errors.New("port " + r.URL.Hostname() + " is not allowed"), true
return nil, errors.New("port " + port + " is not allowed"), true
}
// in case IP was provided, net.LookupIP will simply return it
IPs, err := net.LookupIP(r.URL.Hostname())
IPs, err := net.LookupIP(host)
if err != nil {
return nil, errors.New(fmt.Sprintf("Lookup of %s failed: %v",
r.URL.Hostname(), err)), false
host, err)), false
}
// This is net.Dial's default behavior: if the host resolves to multiple IP addresses,
// Dial will try each IP address in order until one succeeds
for _, ip := range IPs {
if !fp.hostIsAllowed(r.URL.Hostname(), ip) {
if !fp.hostIsAllowed(host, ip) {
continue
}
conn, err = fp.dial("tcp", net.JoinHostPort(ip.String(), port))
conn, err = fp.dial("tcp", hostPort)
if err == nil {
return conn, err, false
}
}
return nil, errors.New("No allowed IP addresses for " + r.URL.Hostname()), true
return nil, errors.New("No allowed IP addresses for " + host), true
}
func (fp *ForwardProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {