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

net: propagate custom dns hosts to gvproxy #543

Merged
merged 1 commit into from
Dec 27, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.idea/
.fleet/
.vscode/
_output/
_build/
Expand Down
14 changes: 9 additions & 5 deletions cmd/daemon/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ var startCmd = &cobra.Command{
if daemonArgs.vmnet {
processes = append(processes, vmnet.New())
}
if daemonArgs.gvproxy {
processes = append(processes, gvproxy.New())
if daemonArgs.gvproxy.enabled {
processes = append(processes, gvproxy.New(daemonArgs.gvproxy.dnsHosts))
}

return start(ctx, processes)
Expand Down Expand Up @@ -70,8 +70,11 @@ var statusCmd = &cobra.Command{
}

var daemonArgs struct {
vmnet bool
gvproxy bool
vmnet bool
gvproxy struct {
enabled bool
dnsHosts map[string]string
}
fsnotify bool

verbose bool
Expand All @@ -85,6 +88,7 @@ func init() {
daemonCmd.AddCommand(statusCmd)

startCmd.Flags().BoolVar(&daemonArgs.vmnet, "vmnet", false, "start vmnet")
startCmd.Flags().BoolVar(&daemonArgs.gvproxy, "gvproxy", false, "start gvproxy")
startCmd.Flags().BoolVar(&daemonArgs.gvproxy.enabled, "gvproxy", false, "start gvproxy")
startCmd.Flags().StringToStringVar(&daemonArgs.gvproxy.dnsHosts, "gvproxy-hosts", nil, "start gvproxy")
startCmd.Flags().BoolVar(&daemonArgs.fsnotify, "fsnotify", false, "start fsnotify")
}
2 changes: 1 addition & 1 deletion cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ const (
defaultMemory = 2
defaultDisk = 60
defaultKubernetesVersion = kubernetes.DefaultVersion
defaultNetworkDriver = "slirp"
defaultNetworkDriver = "gvproxy"
)

var defaultKubernetesDisable = []string{"traefik"}
Expand Down
29 changes: 21 additions & 8 deletions daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,13 @@ func (l processManager) Start(ctx context.Context) error {
if opts.Vmnet {
args = append(args, "--vmnet")
}
if opts.GVProxy {
if opts.GVProxy.Enabled {
args = append(args, "--gvproxy")
if len(opts.GVProxy.Hosts) > 0 {
for host, ip := range opts.GVProxy.Hosts {
args = append(args, "--gvproxy-hosts", host+"="+ip)
}
}
}

if cli.Settings.Verbose {
Expand All @@ -110,17 +115,25 @@ func (l processManager) Stop(ctx context.Context) error {
}

func optsFromCtx(ctx context.Context) struct {
Vmnet bool
GVProxy bool
Vmnet bool
GVProxy struct {
Enabled bool
Hosts map[string]string
}
FSNotify bool
} {
var opts = struct {
Vmnet bool
GVProxy bool
Vmnet bool
GVProxy struct {
Enabled bool
Hosts map[string]string
}

FSNotify bool
}{}
opts.Vmnet, _ = ctx.Value(CtxKey(vmnet.Name)).(bool)
opts.GVProxy, _ = ctx.Value(CtxKey(gvproxy.Name)).(bool)
opts.GVProxy.Enabled, _ = ctx.Value(CtxKey(gvproxy.Name)).(bool)
opts.GVProxy.Hosts, _ = ctx.Value(CtxKey(gvproxy.CtxKeyHosts)).(map[string]string)

return opts
}
Expand All @@ -132,8 +145,8 @@ func processesFromCtx(ctx context.Context) []process.Process {
if opts.Vmnet {
processes = append(processes, vmnet.New())
}
if opts.GVProxy {
processes = append(processes, gvproxy.New())
if opts.GVProxy.Enabled {
processes = append(processes, gvproxy.New(opts.GVProxy.Hosts))
}

return processes
Expand Down
82 changes: 82 additions & 0 deletions daemon/process/gvproxy/dnshosts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package gvproxy

import (
"net"
"strings"

"github.com/containers/gvisor-tap-vsock/pkg/types"
)

func extractZones(hosts hostMap) (zones []types.Zone) {
list := make(map[string]types.Zone)

for host := range hosts {
h := zoneHost(host)

zone := types.Zone{Name: h.name()}
if existingZone, ok := list[h.name()]; ok {
zone = existingZone
}

if h.recordName() == "" {
if zone.DefaultIP == nil {
zone.DefaultIP = hosts.hostIP(host)
}
} else {
zone.Records = append(zone.Records, types.Record{
Name: h.recordName(),
IP: hosts.hostIP(host),
})
}

list[h.name()] = zone
}

for _, zone := range list {
zones = append(zones, zone)
}
return
}

type hostMap map[string]string

func (z hostMap) hostIP(host string) net.IP {
for {
// check if host entry exists
h, ok := z[host]
if !ok || h == "" {
return nil
}

// if it's a valid ip, return
if ip := net.ParseIP(h); ip != nil {
return ip
}

// otherwise, a string i.e. another host
// loop through the process again.
host = h
}
}

type zoneHost string

func (z zoneHost) name() string {
i := z.dotIndex()
if i < 0 {
return string(z)
}
return string(z)[i+1:] + "."
}

func (z zoneHost) recordName() string {
i := z.dotIndex()
if i < 0 {
return ""
}
return string(z)[:i]
}

func (z zoneHost) dotIndex() int {
return strings.LastIndex(string(z), ".")
}
163 changes: 163 additions & 0 deletions daemon/process/gvproxy/dnshosts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package gvproxy

import (
"fmt"
"net"
"testing"

"github.com/containers/gvisor-tap-vsock/pkg/types"
)

func Test_hostsMapIP(t *testing.T) {
hosts := hostMap{}
hosts["sample"] = "1.1.1.1"
hosts["another.sample"] = "1.2.2.1"
hosts["google.com"] = "8.8.8.8"
hosts["google.ae"] = "google.com"
hosts["google.ie"] = "google.ae"

tests := []struct {
host string
want net.IP
}{
{host: "sample", want: net.ParseIP("1.1.1.1")},
{host: "another.sample", want: net.ParseIP("1.2.2.1")},
{host: "google.com", want: net.ParseIP("8.8.8.8")},
{host: "google.ae", want: net.ParseIP("8.8.8.8")},
{host: "google.ie", want: net.ParseIP("8.8.8.8")},
{host: "google.sample", want: nil},
}
for i, tt := range tests {
t.Run(fmt.Sprint(i), func(t *testing.T) {
got := hosts.hostIP(tt.host)
if !got.Equal(tt.want) {
t.Errorf("hostsMapIP() = %v, want %v", got, tt.want)
return
}
})
}
}

func Test_zoneHost(t *testing.T) {
type val struct {
name string
recordName string
}
tests := []struct {
host zoneHost
want val
}{
{}, // test for empty value as well
{host: "sample", want: val{name: "sample"}},
{host: "another.sample", want: val{name: "sample.", recordName: "another"}},
{host: "another.sample.com", want: val{name: "com.", recordName: "another.sample"}},
{host: "a.c", want: val{name: "c.", recordName: "a"}},
{host: "a.b.c.d", want: val{name: "d.", recordName: "a.b.c"}},
}
for i, tt := range tests {
t.Run(fmt.Sprint(i), func(t *testing.T) {
got := val{
name: tt.host.name(),
recordName: tt.host.recordName(),
}
if got != tt.want {
t.Errorf("host = %+v, want %+v", got, tt.want)
return
}
})
}
}

func Test_extractZones(t *testing.T) {
equalZones := func(za, zb []types.Zone) bool {
find := func(list []types.Zone, name string) (types.Zone, bool) {
for _, z := range list {
if z.Name == name {
return z, true
}
}
return types.Zone{}, false
}
equal := func(a, b types.Zone) bool {
if a.Name != b.Name {
return false
}
if !a.DefaultIP.Equal(b.DefaultIP) {
return false
}
for i := range a.Records {
a, b := a.Records[i], b.Records[i]
if !a.IP.Equal(b.IP) {
return false
}
if a.Name != b.Name {
return false
}
}

return true
}

for _, a := range za {
b, ok := find(zb, a.Name)
if !ok {
return false
}
if !equal(a, b) {
return false
}
}
return true
}

hosts := hostMap{
"google.com": "8.8.4.4",
"local.google.com": "8.8.8.8",
"google.ae": "google.com",
"localhost": "127.0.0.1",
"host.lima.internal": "192.168.5.2",
"host.docker.internal": "host.lima.internal",
}

tests := []struct {
wantZones []types.Zone
}{
{
wantZones: []types.Zone{
{
Name: "com.",
Records: []types.Record{
{Name: "google", IP: net.ParseIP("8.8.4.4")},
{Name: "local.google", IP: net.ParseIP("8.8.8.8")},
{Name: "local.google", IP: net.ParseIP("8.8.8.8")},
},
},
{
Name: "ae.",
Records: []types.Record{
{Name: "google", IP: net.ParseIP("8.8.4.4")},
},
},
{
Name: "localhost",
DefaultIP: net.ParseIP("127.0.0.1"),
},
{
Name: "internal.",
Records: []types.Record{
{Name: "host.lima", IP: net.ParseIP("192.168.5.2")},
{Name: "host.docker", IP: net.ParseIP("192.168.5.2")},
},
},
},
},
}

for i, tt := range tests {
t.Run(fmt.Sprint(i), func(t *testing.T) {
if gotZones := extractZones(hosts); !equalZones(gotZones, tt.wantZones) {
t.Errorf("extractZones() = %+v, want %+v", gotZones, tt.wantZones)
}
})
}
}