From 893c0d179c29fe24aafb51ad2d71fb0e7da9332d Mon Sep 17 00:00:00 2001 From: Guilherme Pereira Date: Sun, 19 Oct 2025 18:39:00 +0100 Subject: [PATCH 1/4] net: add possibility of changing gateway Signed-off-by: Guilherme Pereira --- cmd/start.go | 7 +++++ config/config.go | 1 + embedded/defaults/colima.yaml | 9 ++++++ environment/vm/lima/dns.go | 25 +++++++++++----- environment/vm/lima/lima.go | 5 ++-- environment/vm/lima/limautil/network.go | 39 +++++++++++++++++++++++++ environment/vm/lima/network.go | 24 ++++++++++++++- 7 files changed, 100 insertions(+), 10 deletions(-) diff --git a/cmd/start.go b/cmd/start.go index 5d2755e5..f6503000 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -45,6 +45,7 @@ Run 'colima template' to set the default configurations or 'colima start --edit' " colima start --arch aarch64\n" + " colima start --dns 1.1.1.1 --dns 8.8.8.8\n" + " colima start --dns-host example.com=1.2.3.4\n" + + " colima start --gateway-address 192.168.6.2\n" + " colima start --kubernetes --k3s-arg='\"--disable=coredns,servicelb,traefik,local-storage,metrics-server\"'", Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { @@ -210,6 +211,9 @@ func init() { } } + // Gateway Address + startCmd.Flags().StringVar(&startCmdArgs.Network.GatewayAddress, "gateway-address", "192.168.5.2", "gateway address") + // binfmt startCmd.Flags().BoolVar(&startCmdArgs.Flags.Binfmt, "binfmt", true, binfmtDesc) @@ -518,6 +522,9 @@ func prepareConfig(cmd *cobra.Command) { if !cmd.Flag("dns-host").Changed { startCmdArgs.Network.DNSHosts = current.Network.DNSHosts } + if !cmd.Flag("gateway-address").Changed { + startCmdArgs.Network.GatewayAddress = current.Network.GatewayAddress + } if !cmd.Flag("env").Changed { startCmdArgs.Env = current.Env } diff --git a/config/config.go b/config/config.go index dc3c82f7..f33e5af5 100644 --- a/config/config.go +++ b/config/config.go @@ -88,6 +88,7 @@ type Network struct { Mode string `yaml:"mode"` // shared, bridged BridgeInterface string `yaml:"interface"` PreferredRoute bool `yaml:"preferredRoute"` + GatewayAddress string `yaml:"gatewayAddress"` } // Mount is volume mount diff --git a/embedded/defaults/colima.yaml b/embedded/defaults/colima.yaml index b76d04d0..6861a9fd 100644 --- a/embedded/defaults/colima.yaml +++ b/embedded/defaults/colima.yaml @@ -107,6 +107,15 @@ network: # Default: false hostAddresses: false + # Custom gateway address for the virtual machine. + # The last octet will be converted to 2. Always. + # + # EXAMPLE + # gatewayAddress: 192.168.10.2 + # + # Default: 192.168.5.2 + gatewayAddress: 192.168.5.2 + # ===================================================================== # # ADVANCED CONFIGURATION # ===================================================================== # diff --git a/environment/vm/lima/dns.go b/environment/vm/lima/dns.go index 00a9f1f8..8ab7c05c 100644 --- a/environment/vm/lima/dns.go +++ b/environment/vm/lima/dns.go @@ -9,15 +9,10 @@ import ( ) const ( - localhostAddr = "127.0.0.1" - gatewayAddr = "192.168.5.2" + localhostAddr = "127.0.0.1" + defaultGatewayAddress = "192.168.5.2" ) -var dnsHosts = map[string]string{ - "host.docker.internal": gatewayAddr, - "host.lima.internal": gatewayAddr, -} - func hasDnsmasq(l *limaVM) bool { // check if dnsmasq is installed return l.RunQuiet("sh", "-c", `apt list | grep 'dnsmasq\/' | grep '\[installed'`) == nil @@ -30,6 +25,22 @@ func (l *limaVM) setupDNS(conf config.Config) error { return nil } + // use custom gateway address + var gatewayAddr = defaultGatewayAddress + customGatewayAddress := conf.Network.GatewayAddress + if len(customGatewayAddress) != 0 { + adjustedGateway, err := limautil.AdjustGateway(customGatewayAddress) + if err != nil { + return err + } + gatewayAddr = adjustedGateway + } + + var dnsHosts = map[string]string{ + "host.docker.internal": gatewayAddr, + "host.lima.internal": gatewayAddr, + } + internalIP := limautil.InternalIPAddress(config.CurrentProfile().ID) // extra dns entries diff --git a/environment/vm/lima/lima.go b/environment/vm/lima/lima.go index cc891786..639cd33f 100644 --- a/environment/vm/lima/lima.go +++ b/environment/vm/lima/lima.go @@ -111,7 +111,8 @@ func (l *limaVM) Start(ctx context.Context, conf config.Config) error { return yamlutil.WriteYAML(l.limaConf, confFile) }) - a.Add(l.writeNetworkFile) + a.Add(func() error { return l.writeNetworkFile(conf) }) + a.Add(func() error { return l.host.Run(limactl, "start", "--tty=false", confFile) }) @@ -166,7 +167,7 @@ func (l *limaVM) resume(ctx context.Context, conf config.Config) error { return err }) - a.Add(l.writeNetworkFile) + a.Add(func() error { return l.writeNetworkFile(conf) }) a.Stage("starting") a.Add(func() error { diff --git a/environment/vm/lima/limautil/network.go b/environment/vm/lima/limautil/network.go index c2ceefac..6d97a84d 100644 --- a/environment/vm/lima/limautil/network.go +++ b/environment/vm/lima/limautil/network.go @@ -2,6 +2,8 @@ package limautil import ( "bytes" + "fmt" + "net" "strings" ) @@ -51,3 +53,40 @@ func getIPAddress(profileID, interfaceName string) string { _ = cmd.Run() return strings.TrimSpace(buf.String()) } + +type LimaNetworkConfig struct { + Mode string `yaml:"mode"` + Gateway string `yaml:"gateway"` + Netmask string `yaml:"netmask"` +} + +type LimaNetwork struct { + Networks struct { + UserV2 LimaNetworkConfig `yaml:"user-v2"` + } `yaml:"networks"` +} + +// AdjustGateway ensures gateway is a valid IPv4 address and then ensures the last octet is “2”. +// If it’s valid IPv4 but last octet != 2, it changes the last octet to 2. +func AdjustGateway(gateway string) (string, error) { + ip := net.ParseIP(gateway) + if ip == nil { + return "", fmt.Errorf("gateway %q is not a valid IP address", gateway) + } + ip4 := ip.To4() + if ip4 == nil { + return "", fmt.Errorf("gateway %q is not IPv4", gateway) + } + + parts := strings.Split(gateway, ".") + if len(parts) != 4 { + return "", fmt.Errorf("gateway %q does not have 4 octets", gateway) + } + + if parts[3] != "2" { + parts[3] = "2" + gateway = strings.Join(parts, ".") + } + + return gateway, nil +} diff --git a/environment/vm/lima/network.go b/environment/vm/lima/network.go index df01f32d..334df5fb 100644 --- a/environment/vm/lima/network.go +++ b/environment/vm/lima/network.go @@ -11,15 +11,37 @@ import ( "github.com/abiosoft/colima/environment/vm/lima/limautil" "github.com/abiosoft/colima/util" "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" ) -func (l *limaVM) writeNetworkFile() error { +func (l *limaVM) writeNetworkFile(conf config.Config) error { networkFile := limautil.NetworkFile() embeddedFile, err := embedded.Read("network/networks.yaml") if err != nil { return fmt.Errorf("error reading embedded network config file: %w", err) } + // use custom gateway address + gatewayAddress := conf.Network.GatewayAddress + if len(gatewayAddress) != 0 { + var cfg limautil.LimaNetwork + if err := yaml.Unmarshal(embeddedFile, &cfg); err != nil { + return fmt.Errorf("error unmarshalling the `networks.yaml` file: %w", err) + } + + adjustedGateway, err := limautil.AdjustGateway(gatewayAddress) + if err != nil { + return err + } + cfg.Networks.UserV2.Gateway = adjustedGateway + + out, err := yaml.Marshal(&cfg) + if err != nil { + return fmt.Errorf("error marshalling the `networks.yaml` file: %w", err) + } + embeddedFile = out + } + // if there are no running instances, clear network directory if instances, err := limautil.RunningInstances(); err == nil && len(instances) == 0 { if err := os.RemoveAll(limautil.NetworkAssetsDirectory()); err != nil { From 2c7e33fa9c4666abde074eb9412f9baadc74651e Mon Sep 17 00:00:00 2001 From: Guilherme Pereira Date: Sun, 19 Oct 2025 19:23:11 +0100 Subject: [PATCH 2/4] net: validate gateway address inside validate config function Signed-off-by: Guilherme Pereira --- config/configmanager/configmanager.go | 31 +++++++++++++++++++++++++ environment/vm/lima/dns.go | 6 +---- environment/vm/lima/limautil/network.go | 27 --------------------- environment/vm/lima/network.go | 6 +---- 4 files changed, 33 insertions(+), 37 deletions(-) diff --git a/config/configmanager/configmanager.go b/config/configmanager/configmanager.go index 111a5715..9457936a 100644 --- a/config/configmanager/configmanager.go +++ b/config/configmanager/configmanager.go @@ -2,6 +2,7 @@ package configmanager import ( "fmt" + "net" "os" "strings" @@ -80,6 +81,12 @@ func ValidateConfig(c config.Config) error { return fmt.Errorf("invalid port forwarder: '%s'", c.PortForwarder) } + if c.Network.GatewayAddress != "" { + if err := validateGatewayAddress(c.Network.GatewayAddress); err != nil { + return err + } + } + return nil } @@ -108,3 +115,27 @@ func Teardown() error { } return nil } + +// Validates that gateway is a valid IPv4 address and that the last octet is “2”. +// Lima uses the last octet as 2 for gateways. +func validateGatewayAddress(gateway string) error { + ip := net.ParseIP(gateway) + if ip == nil { + return fmt.Errorf("gateway %q is not a valid IP address", gateway) + } + ip4 := ip.To4() + if ip4 == nil { + return fmt.Errorf("gateway %q is not IPv4", gateway) + } + + parts := strings.Split(gateway, ".") + if len(parts) != 4 { + return fmt.Errorf("gateway %q does not have 4 octets", gateway) + } + + if parts[3] != "2" { + return fmt.Errorf("the last octet of gateway %q is not 2", gateway) + } + + return nil +} diff --git a/environment/vm/lima/dns.go b/environment/vm/lima/dns.go index 8ab7c05c..8e1a12aa 100644 --- a/environment/vm/lima/dns.go +++ b/environment/vm/lima/dns.go @@ -29,11 +29,7 @@ func (l *limaVM) setupDNS(conf config.Config) error { var gatewayAddr = defaultGatewayAddress customGatewayAddress := conf.Network.GatewayAddress if len(customGatewayAddress) != 0 { - adjustedGateway, err := limautil.AdjustGateway(customGatewayAddress) - if err != nil { - return err - } - gatewayAddr = adjustedGateway + gatewayAddr = customGatewayAddress } var dnsHosts = map[string]string{ diff --git a/environment/vm/lima/limautil/network.go b/environment/vm/lima/limautil/network.go index 6d97a84d..10f63f26 100644 --- a/environment/vm/lima/limautil/network.go +++ b/environment/vm/lima/limautil/network.go @@ -2,8 +2,6 @@ package limautil import ( "bytes" - "fmt" - "net" "strings" ) @@ -65,28 +63,3 @@ type LimaNetwork struct { UserV2 LimaNetworkConfig `yaml:"user-v2"` } `yaml:"networks"` } - -// AdjustGateway ensures gateway is a valid IPv4 address and then ensures the last octet is “2”. -// If it’s valid IPv4 but last octet != 2, it changes the last octet to 2. -func AdjustGateway(gateway string) (string, error) { - ip := net.ParseIP(gateway) - if ip == nil { - return "", fmt.Errorf("gateway %q is not a valid IP address", gateway) - } - ip4 := ip.To4() - if ip4 == nil { - return "", fmt.Errorf("gateway %q is not IPv4", gateway) - } - - parts := strings.Split(gateway, ".") - if len(parts) != 4 { - return "", fmt.Errorf("gateway %q does not have 4 octets", gateway) - } - - if parts[3] != "2" { - parts[3] = "2" - gateway = strings.Join(parts, ".") - } - - return gateway, nil -} diff --git a/environment/vm/lima/network.go b/environment/vm/lima/network.go index 334df5fb..dd323a58 100644 --- a/environment/vm/lima/network.go +++ b/environment/vm/lima/network.go @@ -29,11 +29,7 @@ func (l *limaVM) writeNetworkFile(conf config.Config) error { return fmt.Errorf("error unmarshalling the `networks.yaml` file: %w", err) } - adjustedGateway, err := limautil.AdjustGateway(gatewayAddress) - if err != nil { - return err - } - cfg.Networks.UserV2.Gateway = adjustedGateway + cfg.Networks.UserV2.Gateway = gatewayAddress out, err := yaml.Marshal(&cfg) if err != nil { From 80b25712cc6c5c5da8319c9a8d1cba3ee9e6d049 Mon Sep 17 00:00:00 2001 From: Guilherme Pereira Date: Sun, 19 Oct 2025 19:31:01 +0100 Subject: [PATCH 3/4] net: improve comment on colima.yaml file Signed-off-by: Guilherme Pereira --- embedded/defaults/colima.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embedded/defaults/colima.yaml b/embedded/defaults/colima.yaml index 6861a9fd..d13dab49 100644 --- a/embedded/defaults/colima.yaml +++ b/embedded/defaults/colima.yaml @@ -108,7 +108,7 @@ network: hostAddresses: false # Custom gateway address for the virtual machine. - # The last octet will be converted to 2. Always. + # The last octet needs to be 2. # # EXAMPLE # gatewayAddress: 192.168.10.2 From 178603772019f2c6446cf195f7cd10ceacc8d3d4 Mon Sep 17 00:00:00 2001 From: Guilherme Pereira Date: Sun, 19 Oct 2025 19:36:01 +0100 Subject: [PATCH 4/4] net: check empty string directly Signed-off-by: Guilherme Pereira --- environment/vm/lima/dns.go | 2 +- environment/vm/lima/network.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/environment/vm/lima/dns.go b/environment/vm/lima/dns.go index 8e1a12aa..ca67b092 100644 --- a/environment/vm/lima/dns.go +++ b/environment/vm/lima/dns.go @@ -28,7 +28,7 @@ func (l *limaVM) setupDNS(conf config.Config) error { // use custom gateway address var gatewayAddr = defaultGatewayAddress customGatewayAddress := conf.Network.GatewayAddress - if len(customGatewayAddress) != 0 { + if customGatewayAddress != "" { gatewayAddr = customGatewayAddress } diff --git a/environment/vm/lima/network.go b/environment/vm/lima/network.go index dd323a58..ddd2dedc 100644 --- a/environment/vm/lima/network.go +++ b/environment/vm/lima/network.go @@ -23,7 +23,7 @@ func (l *limaVM) writeNetworkFile(conf config.Config) error { // use custom gateway address gatewayAddress := conf.Network.GatewayAddress - if len(gatewayAddress) != 0 { + if gatewayAddress != "" { var cfg limautil.LimaNetwork if err := yaml.Unmarshal(embeddedFile, &cfg); err != nil { return fmt.Errorf("error unmarshalling the `networks.yaml` file: %w", err)