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

linkname: remove usage of net.lookupStaticHost #899

Merged
merged 3 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ require (
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kevinburke/hostsfile v0.0.0-20220522040509-e5e984885321 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T
github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kevinburke/hostsfile v0.0.0-20220522040509-e5e984885321 h1:zfI6ImDFFLxvWztL5C7pigHTGyjfI3EtS/UDaDKk7dg=
github.com/kevinburke/hostsfile v0.0.0-20220522040509-e5e984885321/go.mod h1:jxc0FMWcuW3a+dQiKqEesZGT5abRU8gFVbdJaykah/g=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
Expand Down
46 changes: 46 additions & 0 deletions hostsfile/hostsfile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2022-2024 Sauce Labs Inc., all rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

package hostsfile

import (
"io"
"os"
"sort"

hostsfile "github.com/kevinburke/hostsfile/lib"
"golang.org/x/exp/maps"
)

func LocalhostAliases() ([]string, error) {
f, err := os.Open(hostsfile.Location)
if err != nil {
return nil, err
}
defer f.Close()

return readLocalhostAliases(f)
}

func readLocalhostAliases(r io.Reader) ([]string, error) {
hf, err := hostsfile.Decode(r)
if err != nil {
return nil, err
}

aliases := make(map[string]struct{})
for _, r := range hf.Records() {
if r.IpAddress.IP.IsLoopback() {
for a := range r.Hostnames {
aliases[a] = struct{}{}
}
}
}

v := maps.Keys(aliases)
sort.Strings(v)
return v, nil
}
42 changes: 42 additions & 0 deletions hostsfile/hostsfile_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2022-2024 Sauce Labs Inc., all rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

package hostsfile

import (
"strings"
"testing"

"github.com/google/go-cmp/cmp"
)

func TestReadLocalhostAliases(t *testing.T) {
data := `
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
127.0.0.1 kubernetes.docker.internal
# End of section

127.0.0.1 SL-666

192.168.0.60 fedora
`
l, err := readLocalhostAliases(strings.NewReader(data))
if err != nil {
t.Fatal(err)
}

golden := []string{
"SL-666",
"kubernetes.docker.internal",
"localhost",
}

if diff := cmp.Diff(l, golden); diff != "" {
t.Errorf("unexpected result (-want +got):\n%s", diff)
}
}
25 changes: 21 additions & 4 deletions http_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ import (
"net"
"net/http"
"net/url"
"slices"
"sync"
"time"

"github.com/saucelabs/forwarder/hostsfile"
"github.com/saucelabs/forwarder/httplog"
"github.com/saucelabs/forwarder/internal/martian"
"github.com/saucelabs/forwarder/internal/martian/fifo"
Expand Down Expand Up @@ -145,6 +147,7 @@ type HTTPProxy struct {
proxy *martian.Proxy
mitmCACert *x509.Certificate
proxyFunc ProxyFunc
localhost []string

tlsConfig *tls.Config
listener net.Listener
Expand All @@ -164,6 +167,12 @@ func NewHTTPProxy(cfg *HTTPProxyConfig, pr PACResolver, cm *CredentialsMatcher,
}
}

lh, err := hostsfile.LocalhostAliases()
if err != nil {
return nil, fmt.Errorf("read localhost aliases: %w", err)
}
hp.localhost = append(hp.localhost, lh...)

l, err := hp.listen()
if err != nil {
return nil, err
Expand Down Expand Up @@ -209,6 +218,7 @@ func newHTTPProxy(cfg *HTTPProxyConfig, pr PACResolver, cm *CredentialsMatcher,
transport: rt,
log: log,
metrics: newHTTPProxyMetrics(cfg.PromRegistry, cfg.PromNamespace),
localhost: []string{"localhost", "0.0.0.0", "::"},
}

if err := hp.configureProxy(); err != nil {
Expand Down Expand Up @@ -405,7 +415,7 @@ func (hp *HTTPProxy) basicAuth(u *url.Userinfo) martian.RequestModifier {

func (hp *HTTPProxy) denyLocalhost() martian.RequestModifier {
return martian.RequestModifierFunc(func(req *http.Request) error {
if hp.isLocalhost(req) {
if hp.isLocalhost(req.URL.Hostname()) {
return ErrProxyLocalhost
}
return nil
Expand Down Expand Up @@ -440,15 +450,22 @@ func (hp *HTTPProxy) directLocalhost(fn ProxyFunc) ProxyFunc {
}

return func(req *http.Request) (*url.URL, error) {
if hp.isLocalhost(req) {
if hp.isLocalhost(req.URL.Hostname()) {
return nil, nil
}
return fn(req)
}
}

func (hp *HTTPProxy) isLocalhost(req *http.Request) bool {
return isLocalhost(req.URL.Hostname())
func (hp *HTTPProxy) isLocalhost(host string) bool {
if slices.Contains(hp.localhost, host) {
return true
}
if ip := net.ParseIP(host); ip != nil && ip.IsLoopback() {
return true
}

return false
}

func (hp *HTTPProxy) setBasicAuth(req *http.Request) error {
Expand Down
34 changes: 34 additions & 0 deletions http_proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,37 @@ func TestNopDialer(t *testing.T) {
t.Fatalf("expected %v, got %v", nopDialerErr, err)
}
}

func TestIsLocalhost(t *testing.T) {
cfg := DefaultHTTPProxyConfig()
p, err := NewHTTPProxy(cfg, nil, nil, nil, stdlog.Default())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May we have a test for a handler mode too (newHTTPProxy)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That suite should work without reading hosts file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do that in a separate issue. It uses convention in this file.

if err != nil {
t.Fatal(err)
}

tests := []struct {
host string
localhost bool
}{
{"127.0.0.1", true},
{"127.10.20.30", true},
{"localhost", true},
{"0.0.0.0", true},

{"notlocalhost", false},
{"broadcasthost", false},

{"::1", true},
{"::", true},

{"::10", false},
{"2001:0db8:85a3:0000:0000:8a2e:0370:7334", false},
}

for i := range tests {
tc := tests[i]
if lh := p.isLocalhost(tc.host); lh != tc.localhost {
t.Errorf("isLocalhost(%q) = %v; want %v", tc.host, lh, tc.localhost)
}
}
}
2 changes: 1 addition & 1 deletion net_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func addr2Host(addr string) string {
return "unknown"
}

if isLocalhost(host) {
if ip := net.ParseIP(host); ip != nil && ip.IsLoopback() {
return "localhost"
}

Expand Down
37 changes: 0 additions & 37 deletions resolver.go

This file was deleted.

39 changes: 0 additions & 39 deletions resolver_test.go

This file was deleted.