Repository: lima-vm/lima
Pull request #1112 (2022-10-17 08:49:21)

Fix the regexp for the localhost proxy match
Fix issue #1111 

jandubois: > Please also look at the lint failures (you can run `make lint` locally before pushing the commits),

Sorry, just realized the lint/test failures are unrelated to your PR and have been fixed by #1116. Please rebase your PR (or create a new one, as it will be pretty much all different code anyways) based on the latest `master`.

Patch:
diff --git a/pkg/cidata/cidata.go b/pkg/cidata/cidata.go
index 5d253770..b1b3d41c 100644
--- a/pkg/cidata/cidata.go
+++ b/pkg/cidata/cidata.go
@@ -4,9 +4,10 @@ import (
 	"errors"
 	"fmt"
 	"io"
+	"net"
+	"net/url"
 	"os"
 	"path/filepath"
-	"regexp"
 	"strconv"
 	"strings"
 	"time"
@@ -23,6 +24,16 @@ import (
 	"github.com/sirupsen/logrus"
 )
 
+var netLookupIP = func(host string) []net.IP {
+	ips, err := net.LookupIP(host)
+	if err != nil {
+		logrus.Debugf("net.LookupIP %s: %s", host, err)
+		return nil
+	}
+
+	return ips
+}
+
 func setupEnv(y *limayaml.LimaYAML) (map[string]string, error) {
 	// Start with the proxy variables from the system settings.
 	env, err := osutil.ProxySettings()
@@ -50,16 +61,25 @@ func setupEnv(y *limayaml.LimaYAML) (map[string]string, error) {
 			}
 		}
 	}
-	// Replace "localhost" in proxy settings with the gateway address
-	localhostRegexes := []*regexp.Regexp{
-		regexp.MustCompile(`\blocalhost\b`),
-		regexp.MustCompile(`\b127.0.0.1\b`),
-	}
+	// Replace IP that IsLoopback in proxy settings with the gateway address
 	for _, name := range append(lowerVars, upperVars...) {
 		value, ok := env[name]
 		if ok && !strings.EqualFold(name, "no_proxy") {
-			for _, re := range localhostRegexes {
-				value = re.ReplaceAllString(value, qemu.SlirpGateway)
+			u, err := url.Parse(value)
+			if err != nil {
+				logrus.Warnf("Ignoring invalid proxy %q=%v: %s", name, value, err)
+				continue
+			}
+
+			for _, ip := range netLookupIP(u.Hostname()) {
+				if ip.IsLoopback() {
+					newHost := qemu.SlirpGateway
+					if u.Port() != "" {
+						newHost = net.JoinHostPort(newHost, u.Port())
+					}
+					u.Host = newHost
+					value = u.String()
+				}
 			}
 			if value != env[name] {
 				logrus.Infof("Replacing %q value %q with %q", name, env[name], value)


Test patch:
diff --git a/pkg/cidata/cidata_test.go b/pkg/cidata/cidata_test.go
new file mode 100644
index 00000000..51d2391d
--- /dev/null
+++ b/pkg/cidata/cidata_test.go
@@ -0,0 +1,63 @@
+package cidata
+
+import (
+	"net"
+	"net/url"
+	"strings"
+	"testing"
+
+	"github.com/lima-vm/lima/pkg/limayaml"
+	qemu "github.com/lima-vm/lima/pkg/qemu/const"
+	"github.com/xorcare/pointer"
+	"gotest.tools/v3/assert"
+)
+
+func fakeLookupIP(host string) []net.IP {
+	return []net.IP{net.IPv4(127, 0, 0, 0)}
+}
+
+func TestSetupEnv(t *testing.T) {
+	netLookupIP = fakeLookupIP
+	urlMustParse := func(urlStr string) *url.URL {
+		u, err := url.Parse(urlStr)
+		if err != nil {
+			panic(err)
+		}
+
+		return u
+	}
+
+	httpProxyCases := []*url.URL{
+		urlMustParse("http://127.0.0.1"),
+		urlMustParse("http://127.0.0.1:8080"),
+		urlMustParse("https://127.0.0.1:8080"),
+		urlMustParse("sock4://127.0.0.1:8080"),
+		urlMustParse("sock5://127.0.0.1:8080"),
+		urlMustParse("http://127.0.0.1:8080/"),
+		urlMustParse("http://127.0.0.1:8080/path"),
+		urlMustParse("http://localhost:8080"),
+		urlMustParse("http://localhost:8080/"),
+		urlMustParse("http://localhost:8080/path"),
+		urlMustParse("http://docker.for.mac.localhost:8080"),
+		urlMustParse("http://docker.for.mac.localhost:8080/"),
+		urlMustParse("http://docker.for.mac.localhost:8080/path"),
+	}
+
+	for _, httpProxy := range httpProxyCases {
+		t.Run(httpProxy.Host, func(t *testing.T) {
+			envKey := "http_proxy"
+			envValue := httpProxy.String()
+			envs, err := setupEnv(&limayaml.LimaYAML{PropagateProxyEnv: pointer.Bool(false), Env: map[string]string{envKey: envValue}})
+			assert.NilError(t, err)
+			assert.Equal(t, envs[envKey], strings.ReplaceAll(envValue, httpProxy.Hostname(), qemu.SlirpGateway))
+		})
+	}
+}
+
+func TestSetupInvalidEnv(t *testing.T) {
+	envKey := "http_proxy"
+	envValue := "://localhost:8080"
+	envs, err := setupEnv(&limayaml.LimaYAML{PropagateProxyEnv: pointer.Bool(false), Env: map[string]string{envKey: envValue}})
+	assert.NilError(t, err)
+	assert.Equal(t, envs[envKey], envValue)
+}