-
Notifications
You must be signed in to change notification settings - Fork 729
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TUN-7628: Correct Host parsing for Access
Will no longer provide full hostname with path from provided `--hostname` flag for cloudflared access to the Host header field. This addresses certain issues caught from a security fix in go 1.19.11 and 1.20.6 in the net/http URL parsing.
- Loading branch information
Showing
85 changed files
with
22,869 additions
and
4,438 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package access | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
"net/url" | ||
"strings" | ||
|
||
"golang.org/x/net/http/httpguts" | ||
) | ||
|
||
// parseRequestHeaders will take user-provided header values as strings "Content-Type: application/json" and create | ||
// a http.Header object. | ||
func parseRequestHeaders(values []string) http.Header { | ||
headers := make(http.Header) | ||
for _, valuePair := range values { | ||
header, value, found := strings.Cut(valuePair, ":") | ||
if found { | ||
headers.Add(strings.TrimSpace(header), strings.TrimSpace(value)) | ||
} | ||
} | ||
return headers | ||
} | ||
|
||
// parseHostname will attempt to convert a user provided URL string into a string with some light error checking on | ||
// certain expectations from the URL. | ||
// Will convert all HTTP URLs to HTTPS | ||
func parseURL(input string) (*url.URL, error) { | ||
if input == "" { | ||
return nil, errors.New("no input provided") | ||
} | ||
if !strings.HasPrefix(input, "https://") && !strings.HasPrefix(input, "http://") { | ||
input = fmt.Sprintf("https://%s", input) | ||
} | ||
url, err := url.ParseRequestURI(input) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to parse as URL: %w", err) | ||
} | ||
if url.Scheme != "https" { | ||
url.Scheme = "https" | ||
} | ||
if url.Host == "" { | ||
return nil, errors.New("failed to parse Host") | ||
} | ||
host, err := httpguts.PunycodeHostPort(url.Host) | ||
if err != nil || host == "" { | ||
return nil, err | ||
} | ||
if !httpguts.ValidHostHeader(host) { | ||
return nil, errors.New("invalid Host provided") | ||
} | ||
url.Host = host | ||
return url, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package access | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestParseRequestHeaders(t *testing.T) { | ||
values := parseRequestHeaders([]string{"client: value", "secret: safe-value", "trash", "cf-trace-id: 000:000:0:1:asd"}) | ||
assert.Len(t, values, 3) | ||
assert.Equal(t, "value", values.Get("client")) | ||
assert.Equal(t, "safe-value", values.Get("secret")) | ||
assert.Equal(t, "000:000:0:1:asd", values.Get("cf-trace-id")) | ||
} | ||
|
||
func TestParseURL(t *testing.T) { | ||
schemes := []string{ | ||
"http://", | ||
"https://", | ||
"", | ||
} | ||
hosts := []struct { | ||
input string | ||
expected string | ||
}{ | ||
{"localhost", "localhost"}, | ||
{"127.0.0.1", "127.0.0.1"}, | ||
{"127.0.0.1:9090", "127.0.0.1:9090"}, | ||
{"::1", "::1"}, | ||
{"::1:8080", "::1:8080"}, | ||
{"[::1]", "[::1]"}, | ||
{"[::1]:8080", "[::1]:8080"}, | ||
{":8080", ":8080"}, | ||
{"example.com", "example.com"}, | ||
{"hello.example.com", "hello.example.com"}, | ||
{"bücher.example.com", "xn--bcher-kva.example.com"}, | ||
} | ||
paths := []string{ | ||
"", | ||
"/test", | ||
"/example.com?qwe=123", | ||
} | ||
for i, scheme := range schemes { | ||
for j, host := range hosts { | ||
for k, path := range paths { | ||
t.Run(fmt.Sprintf("%d_%d_%d", i, j, k), func(t *testing.T) { | ||
input := fmt.Sprintf("%s%s%s", scheme, host.input, path) | ||
expected := fmt.Sprintf("%s%s%s", "https://", host.expected, path) | ||
url, err := parseURL(input) | ||
assert.NoError(t, err, "input: %s\texpected: %s", input, expected) | ||
assert.Equal(t, expected, url.String()) | ||
assert.Equal(t, host.expected, url.Host) | ||
assert.Equal(t, "https", url.Scheme) | ||
}) | ||
} | ||
} | ||
} | ||
|
||
t.Run("no input", func(t *testing.T) { | ||
_, err := parseURL("") | ||
assert.ErrorContains(t, err, "no input provided") | ||
}) | ||
|
||
t.Run("missing host", func(t *testing.T) { | ||
_, err := parseURL("https:///host") | ||
assert.ErrorContains(t, err, "failed to parse Host") | ||
}) | ||
|
||
t.Run("invalid path only", func(t *testing.T) { | ||
_, err := parseURL("/host") | ||
assert.ErrorContains(t, err, "failed to parse Host") | ||
}) | ||
|
||
t.Run("invalid parse URL", func(t *testing.T) { | ||
_, err := parseURL("https://host\\host") | ||
assert.ErrorContains(t, err, "failed to parse as URL") | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.