Skip to content

Commit

Permalink
client, health/client: set dummy host header on unix:// local communi…
Browse files Browse the repository at this point in the history
…cation

Go 1.20.6 added a security fix [1] which leads to stricter sanitization
of the HTTP host header in the net/http client. Cilium's pkg/client
currently sets the Host header to the UDS path (e.g.
/var/run/cilium/cilium.sock), however the slashes in that Host header
now lead net/http to reject it.

RFC 7230, Section 5.4 states [2]:

> If the authority component is missing or undefined for the target URI,
> then a client MUST send a Host header field with an empty field-value.

The authority component is undefined for the unix:// scheme. Thus, the
correct value to use would be the empty string. However, this does not
work due to OpenAPI runtime using the same value for the URL's host and
the http client's host header. Thus, use a dummy value "localhost".

[1] https://go.dev/issue/60374
[2] https://datatracker.ietf.org/doc/html/rfc7230#section-5.4

Signed-off-by: Tobias Klauser <tobias@cilium.io>
  • Loading branch information
tklauser committed Jul 13, 2023
1 parent fc819dc commit b9ec2aa
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 2 deletions.
8 changes: 7 additions & 1 deletion pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ func NewRuntime(host string) (*runtime_client.Runtime, error) {
return nil, fmt.Errorf("invalid host format '%s'", host)
}

hostHeader := tmp[1]

switch tmp[0] {
case "tcp":
if _, err := url.Parse("tcp://" + tmp[1]); err != nil {
Expand All @@ -128,11 +130,15 @@ func NewRuntime(host string) (*runtime_client.Runtime, error) {
host = "http://" + tmp[1]
case "unix":
host = tmp[1]
// For local communication (unix domain sockets), the hostname is not used. Leave
// Host header empty because otherwise it would be rejected by net/http client-side
// sanitization, see https://go.dev/issue/60374.
hostHeader = "localhost"
}

transport := configureTransport(nil, tmp[0], host)
httpClient := &http.Client{Transport: transport}
clientTrans := runtime_client.NewWithClient(tmp[1], clientapi.DefaultBasePath,
clientTrans := runtime_client.NewWithClient(hostHeader, clientapi.DefaultBasePath,
clientapi.DefaultSchemes, httpClient)
return clientTrans, nil
}
Expand Down
8 changes: 7 additions & 1 deletion pkg/health/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ func NewClient(host string) (*Client, error) {
return nil, fmt.Errorf("invalid host format '%s'", host)
}

hostHeader := tmp[1]

switch tmp[0] {
case "tcp":
if _, err := url.Parse("tcp://" + tmp[1]); err != nil {
Expand All @@ -96,11 +98,15 @@ func NewClient(host string) (*Client, error) {
host = "http://" + tmp[1]
case "unix":
host = tmp[1]
// For local communication (unix domain sockets), the hostname is not used. Leave
// Host header empty because otherwise it would be rejected by net/http client-side
// sanitization, see https://go.dev/issue/60374.
hostHeader = "localhost"
}

transport := configureTransport(nil, tmp[0], host)
httpClient := &http.Client{Transport: transport}
clientTrans := runtime_client.NewWithClient(tmp[1], clientapi.DefaultBasePath,
clientTrans := runtime_client.NewWithClient(hostHeader, clientapi.DefaultBasePath,
clientapi.DefaultSchemes, httpClient)
return &Client{*clientapi.New(clientTrans, strfmt.Default)}, nil
}
Expand Down

0 comments on commit b9ec2aa

Please sign in to comment.