Skip to content

Commit

Permalink
Merge pull request #650 from rancher-sandbox/hosts
Browse files Browse the repository at this point in the history
Allow adding static names to hostresolver
  • Loading branch information
AkihiroSuda authored Feb 18, 2022
2 parents 41087bf + 014fbc3 commit 7397425
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 10 deletions.
2 changes: 1 addition & 1 deletion cmd/limactl/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func debugDNSAction(cmd *cobra.Command, args []string) error {
return err
}
}
srv, err := dns.Start(udpLocalPort, tcpLocalPort, ipv6)
srv, err := dns.Start(udpLocalPort, tcpLocalPort, ipv6, map[string]string{})
if err != nil {
return err
}
Expand Down
9 changes: 9 additions & 0 deletions examples/docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ containerd:
user: false
provision:
- mode: system
# This script defines the host.docker.internal hostname when hostResolver is disabled.
# It is also needed for lima 0.8.2 and earlier, which does not support hostResolver.hosts.
# Names defined in /etc/hosts inside the VM are not resolved inside containers when
# using the hostResolver; use hostResolver.hosts instead (requires lima 0.8.3 or later).
script: |
#!/bin/sh
sed -i 's/host.lima.internal.*/host.lima.internal host.docker.internal/' /etc/hosts
Expand Down Expand Up @@ -56,6 +60,11 @@ probes:
exit 1
fi
hint: See "/var/log/cloud-init-output.log". in the guest
hostResolver:
# hostResolver.hosts requires lima 0.8.3 or later. Names defined here will also
# resolve inside containers, and not just inside the VM itself.
hosts:
host.docker.internal: host.lima.internal
portForwards:
- guestSocket: "/run/user/{{.UID}}/docker.sock"
hostSocket: "{{.Dir}}/sock/docker.sock"
Expand Down
3 changes: 3 additions & 0 deletions pkg/cidata/cidata.TEMPLATE.d/boot/06-etc-hosts.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#!/bin/bash
set -eux -o pipefail

# Define host.lima.internal in case the hostResolver is disabled. When using
# the hostResolver, the name is provided by the lima resolver itself because
# it doesn't have access to /etc/hosts inside the VM.
sed -i '/host.lima.internal/d' /etc/hosts
echo -e "${LIMA_CIDATA_SLIRP_GATEWAY}\thost.lima.internal" >>/etc/hosts
48 changes: 42 additions & 6 deletions pkg/hostagent/dns/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net"
"strings"

"github.com/lima-vm/lima/pkg/limayaml"
"github.com/miekg/dns"
"github.com/sirupsen/logrus"
)
Expand All @@ -19,6 +20,8 @@ type Handler struct {
clientConfig *dns.ClientConfig
clients []*dns.Client
IPv6 bool
cname map[string]string
ip map[string]net.IP
}

type Server struct {
Expand All @@ -44,7 +47,7 @@ func newStaticClientConfig(ips []net.IP) (*dns.ClientConfig, error) {
return dns.ClientConfigFromReader(r)
}

func newHandler(IPv6 bool) (dns.Handler, error) {
func newHandler(IPv6 bool, hosts map[string]string) (dns.Handler, error) {
cc, err := dns.ClientConfigFromFile("/etc/resolv.conf")
if err != nil {
fallbackIPs := []net.IP{net.ParseIP("8.8.8.8"), net.ParseIP("1.1.1.1")}
Expand All @@ -62,6 +65,15 @@ func newHandler(IPv6 bool) (dns.Handler, error) {
clientConfig: cc,
clients: clients,
IPv6: IPv6,
cname: make(map[string]string),
ip: make(map[string]net.IP),
}
for host, address := range hosts {
if ip := net.ParseIP(address); ip != nil {
h.ip[host] = ip
} else {
h.cname[host] = limayaml.Cname(address)
}
}
return h, nil
}
Expand All @@ -82,14 +94,32 @@ func (h *Handler) handleQuery(w dns.ResponseWriter, req *dns.Msg) {
switch q.Qtype {
case dns.TypeAAAA:
if !h.IPv6 {
handled = true
break
}
fallthrough
case dns.TypeCNAME, dns.TypeA:
cname, err := net.LookupCNAME(q.Name)
if err != nil {
cname := q.Name
seen := make(map[string]bool)
for {
// break cyclic definition
if seen[cname] {
break
}
if _, ok := h.cname[cname]; ok {
seen[cname] = true
cname = h.cname[cname]
continue
}
break
}
var err error
if _, ok := h.ip[cname]; !ok {
cname, err = net.LookupCNAME(cname)
if err != nil {
break
}
}
if cname != "" && cname != q.Name {
hdr.Rrtype = dns.TypeCNAME
a := &dns.CNAME{
Expand All @@ -103,7 +133,13 @@ func (h *Handler) handleQuery(w dns.ResponseWriter, req *dns.Msg) {
break
}
hdr.Name = cname
addrs, err := net.LookupIP(q.Name)
var addrs []net.IP
if _, ok := h.ip[cname]; ok {
addrs = []net.IP{h.ip[cname]}
err = nil
} else {
addrs, err = net.LookupIP(cname)
}
if err == nil && len(addrs) > 0 {
for _, ip := range addrs {
var a dns.RR
Expand Down Expand Up @@ -219,8 +255,8 @@ func (h *Handler) ServeDNS(w dns.ResponseWriter, req *dns.Msg) {
}
}

func Start(udpLocalPort, tcpLocalPort int, IPv6 bool) (*Server, error) {
h, err := newHandler(IPv6)
func Start(udpLocalPort, tcpLocalPort int, IPv6 bool, hosts map[string]string) (*Server, error) {
h, err := newHandler(IPv6, hosts)
if err != nil {
return nil, err
}
Expand Down
8 changes: 7 additions & 1 deletion pkg/hostagent/hostagent.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/lima-vm/lima/pkg/hostagent/events"
"github.com/lima-vm/lima/pkg/limayaml"
"github.com/lima-vm/lima/pkg/qemu"
qemuconst "github.com/lima-vm/lima/pkg/qemu/const"
"github.com/lima-vm/lima/pkg/sshutil"
"github.com/lima-vm/lima/pkg/store"
"github.com/lima-vm/lima/pkg/store/filenames"
Expand All @@ -40,6 +41,7 @@ type HostAgent struct {
udpDNSLocalPort int
tcpDNSLocalPort int
instDir string
instName string
sshConfig *ssh.SSHConfig
portForwarder *portForwarder
onClose []func() error // LIFO
Expand Down Expand Up @@ -145,6 +147,7 @@ func New(instName string, stdout io.Writer, sigintCh chan os.Signal, opts ...Opt
udpDNSLocalPort: udpDNSLocalPort,
tcpDNSLocalPort: tcpDNSLocalPort,
instDir: inst.Dir,
instName: instName,
sshConfig: sshConfig,
portForwarder: newPortForwarder(sshConfig, sshLocalPort, rules),
qExe: qExe,
Expand Down Expand Up @@ -249,7 +252,10 @@ func (a *HostAgent) Run(ctx context.Context) error {
}()

if *a.y.HostResolver.Enabled {
dnsServer, err := dns.Start(a.udpDNSLocalPort, a.tcpDNSLocalPort, *a.y.HostResolver.IPv6)
hosts := a.y.HostResolver.Hosts
hosts["host.lima.internal."] = qemuconst.SlirpGateway
hosts[fmt.Sprintf("lima-%s.", a.instName)] = qemuconst.SlirpIPAddress
dnsServer, err := dns.Start(a.udpDNSLocalPort, a.tcpDNSLocalPort, *a.y.HostResolver.IPv6, hosts)
if err != nil {
return fmt.Errorf("cannot start DNS server: %w", err)
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/limayaml/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,12 @@ hostResolver:
enabled: null
# Default: false
ipv6: null
# Static names can be defined here as an alternative to adding them to the hosts /etc/hosts.
# Values can be either other hostnames, or IP addresses. The host.lima.internal name is
# predefined to specify the gateway address to the host.
hosts:
# guest.name: 127.1.1.1
# host.name: host.lima.internal

# If useHostResolver is false, then the following rules apply for configuring dns:
# Explicitly set DNS addresses for qemu user-mode networking. By default qemu picks *one*
Expand Down
22 changes: 22 additions & 0 deletions pkg/limayaml/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"path/filepath"
"runtime"
"strconv"
"strings"
"text/template"

"github.com/lima-vm/lima/pkg/guestagent/api"
Expand Down Expand Up @@ -188,6 +189,19 @@ func FillDefault(y, d, o *LimaYAML, filePath string) {
y.SSH.ForwardAgent = pointer.Bool(false)
}

hosts := make(map[string]string)
// Values can be either names or IP addresses. Name values are canonicalized in the hostResolver.
for k, v := range d.HostResolver.Hosts {
hosts[Cname(k)] = v
}
for k, v := range y.HostResolver.Hosts {
hosts[Cname(k)] = v
}
for k, v := range o.HostResolver.Hosts {
hosts[Cname(k)] = v
}
y.HostResolver.Hosts = hosts

y.Provision = append(append(o.Provision, y.Provision...), d.Provision...)
for i := range y.Provision {
provision := &y.Provision[i]
Expand Down Expand Up @@ -498,3 +512,11 @@ func IsNativeArch(arch Arch) bool {
nativeAARCH64 := arch == AARCH64 && runtime.GOARCH == "arm64"
return nativeX8664 || nativeAARCH64
}

func Cname(host string) string {
host = strings.ToLower(host)
if !strings.HasSuffix(host, ".") {
host += "."
}
return host
}
23 changes: 23 additions & 0 deletions pkg/limayaml/defaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ func TestFillDefault(t *testing.T) {
// All these slices and maps are empty in "builtin". Add minimal entries here to see that
// their values are retained and defaults for their fields are applied correctly.
y = LimaYAML{
HostResolver: HostResolver{
Hosts: map[string]string{
"MY.Host": "host.lima.internal",
},
},
Mounts: []Mount{
{Location: "/tmp"},
},
Expand Down Expand Up @@ -123,6 +128,10 @@ func TestFillDefault(t *testing.T) {
}

expect := builtin
expect.HostResolver.Hosts = map[string]string{
"my.host.": "host.lima.internal",
}

expect.Mounts = y.Mounts
expect.Mounts[0].Writable = pointer.Bool(false)
expect.Mounts[0].SSHFS.Cache = pointer.Bool(true)
Expand Down Expand Up @@ -202,6 +211,9 @@ func TestFillDefault(t *testing.T) {
HostResolver: HostResolver{
Enabled: pointer.Bool(false),
IPv6: pointer.Bool(true),
Hosts: map[string]string{
"default": "localhost",
},
},
PropagateProxyEnv: pointer.Bool(false),

Expand Down Expand Up @@ -255,6 +267,9 @@ func TestFillDefault(t *testing.T) {
expect.Containerd.Archives[0].Arch = *d.Arch
expect.Mounts[0].SSHFS.Cache = pointer.Bool(true)
expect.Mounts[0].SSHFS.FollowSymlinks = pointer.Bool(false)
expect.HostResolver.Hosts = map[string]string{
"default.": d.HostResolver.Hosts["default"],
}

y = LimaYAML{}
FillDefault(&y, &d, &LimaYAML{}, filePath)
Expand All @@ -277,6 +292,8 @@ func TestFillDefault(t *testing.T) {
expect.Mounts = append(d.Mounts, y.Mounts...)
expect.Networks = append(d.Networks, y.Networks...)

expect.HostResolver.Hosts["default."] = d.HostResolver.Hosts["default"]

// d.DNS will be ignored, and not appended to y.DNS

// "TWO" does not exist in filledDefaults.Env, so is set from d.Env
Expand Down Expand Up @@ -322,6 +339,9 @@ func TestFillDefault(t *testing.T) {
HostResolver: HostResolver{
Enabled: pointer.Bool(false),
IPv6: pointer.Bool(false),
Hosts: map[string]string{
"override.": "underflow",
},
},
PropagateProxyEnv: pointer.Bool(false),

Expand Down Expand Up @@ -386,6 +406,9 @@ func TestFillDefault(t *testing.T) {
expect.PortForwards = append(append(o.PortForwards, y.PortForwards...), d.PortForwards...)
expect.Containerd.Archives = append(append(o.Containerd.Archives, y.Containerd.Archives...), d.Containerd.Archives...)

expect.HostResolver.Hosts["default."] = d.HostResolver.Hosts["default"]
expect.HostResolver.Hosts["my.host."] = d.HostResolver.Hosts["host.lima.internal"]

// o.Mounts just makes d.Mounts[0] writable because the Location matches
expect.Mounts = append(d.Mounts, y.Mounts...)
expect.Mounts[0].Writable = pointer.Bool(true)
Expand Down
5 changes: 3 additions & 2 deletions pkg/limayaml/limayaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,9 @@ type Network struct {
}

type HostResolver struct {
Enabled *bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
IPv6 *bool `yaml:"ipv6,omitempty" json:"ipv6,omitempty"`
Enabled *bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
IPv6 *bool `yaml:"ipv6,omitempty" json:"ipv6,omitempty"`
Hosts map[string]string `yaml:"hosts,omitempty" json:"hosts,omitempty"`
}

// DEPRECATED types below
Expand Down

0 comments on commit 7397425

Please sign in to comment.