Skip to content

Commit

Permalink
Merge pull request #9 from guillaumerose/security1
Browse files Browse the repository at this point in the history
Refuse to change hosts with suffixes not in the allowed list
  • Loading branch information
cfergeau authored Mar 15, 2021
2 parents 377f6a8 + 1cce8dc commit b3a9dc0
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 2 deletions.
49 changes: 47 additions & 2 deletions pkg/hosts/hosts.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,51 @@ package hosts

import (
"fmt"
"regexp"
"sort"
"strings"

"github.com/goodhosts/hostsfile"
)

const (
// source https://github.com/kubernetes/apimachinery/blob/603e04655e9f537eb01238cdbce4891f832a4f27/pkg/util/validation/validation.go#L208
dns1123SubdomainRegexp = `[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*`
clusterDomain = ".crc.testing"
appsDomain = ".apps-crc.testing"
)

var (
clusterRegexp = regexp.MustCompile("^" + dns1123SubdomainRegexp + regexp.QuoteMeta(clusterDomain) + "$")
appRegexp = regexp.MustCompile("^" + dns1123SubdomainRegexp + regexp.QuoteMeta(appsDomain) + "$")
)

type Hosts struct {
File *hostsfile.Hosts
File *hostsfile.Hosts
HostFilter func(string) bool
}

func New() (*Hosts, error) {
file, err := hostsfile.NewHosts()
if err != nil {
return nil, err
}

return &Hosts{
File: &file,
File: &file,
HostFilter: defaultFilter,
}, nil
}

func defaultFilter(s string) bool {
return clusterRegexp.MatchString(s) || appRegexp.MatchString(s)
}

func (h *Hosts) Add(ip string, hosts []string) error {
if err := h.verifyHosts(hosts); err != nil {
return err
}

if err := h.checkIsWritable(); err != nil {
return err
}
Expand All @@ -46,6 +70,10 @@ func (h *Hosts) Add(ip string, hosts []string) error {
}

func (h *Hosts) Remove(hosts []string) error {
if err := h.verifyHosts(hosts); err != nil {
return err
}

if err := h.checkIsWritable(); err != nil {
return err
}
Expand All @@ -69,6 +97,10 @@ func (h *Hosts) Remove(hosts []string) error {
}

func (h *Hosts) Clean(rawSuffixes []string) error {
if err := h.verifyHosts(rawSuffixes); err != nil {
return err
}

if err := h.checkIsWritable(); err != nil {
return err
}
Expand Down Expand Up @@ -109,5 +141,18 @@ func (h *Hosts) checkIsWritable() error {
}

func (h *Hosts) Contains(ip, host string) bool {
if err := h.verifyHosts([]string{host}); err != nil {
return false
}

return h.File.Has(ip, host)
}

func (h *Hosts) verifyHosts(hosts []string) error {
for _, host := range hosts {
if !h.HostFilter(host) {
return fmt.Errorf("input %s rejected", host)
}
}
return nil
}
26 changes: 26 additions & 0 deletions pkg/hosts/hosts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,37 @@ func TestContains(t *testing.T) {
assert.False(t, host.Contains("127.0.0.1", "entry1.suffix2"))
}

func TestSuffixFilter(t *testing.T) {
dir, err := ioutil.TempDir("", "hosts")
assert.NoError(t, err)
defer os.RemoveAll(dir)

hostsFile := filepath.Join(dir, "hosts")
assert.NoError(t, ioutil.WriteFile(hostsFile, []byte(`127.0.0.1 localhost`), 0600))

file, err := hostsfile.NewCustomHosts(hostsFile)
assert.NoError(t, err)
host := Hosts{
File: &file,
HostFilter: defaultFilter,
}

assert.NoError(t, host.Add("127.0.0.1", []string{"entry1.crc.testing"}))
assert.NoError(t, host.Add("127.0.0.1", []string{"entry2.nested.crc.testing"}))
assert.Error(t, host.Add("127.0.0.1", []string{"evildomain #apps.crc.testing"}))
assert.Error(t, host.Add("127.0.0.1", []string{"host.poison"}))
assert.Error(t, host.Add("127.0.0.1", []string{"CAPITAL.crc.testing"}))
assert.Error(t, host.Remove([]string{"localhost"}))
}

func hosts(t *testing.T, hostsFile string) Hosts {
file, err := hostsfile.NewCustomHosts(hostsFile)
assert.NoError(t, err)
return Hosts{
File: &file,
HostFilter: func(s string) bool {
return true
},
}
}

Expand Down

0 comments on commit b3a9dc0

Please sign in to comment.