diff --git a/libnetwork/etchosts/etchosts.go b/libnetwork/etchosts/etchosts.go index 256a89dfa8..5f68372b90 100644 --- a/libnetwork/etchosts/etchosts.go +++ b/libnetwork/etchosts/etchosts.go @@ -182,6 +182,6 @@ func Update(path, IP, hostname string) error { if err != nil { return err } - var re = regexp.MustCompile(fmt.Sprintf("(\\S*)(\\t%s)", regexp.QuoteMeta(hostname))) - return ioutil.WriteFile(path, re.ReplaceAll(old, []byte(IP+"$2")), 0644) + var re = regexp.MustCompile(fmt.Sprintf("(\\S*)(\\t%s)(\\s|\\.)", regexp.QuoteMeta(hostname))) + return ioutil.WriteFile(path, re.ReplaceAll(old, []byte(IP+"$2"+"$3")), 0644) } diff --git a/libnetwork/etchosts/etchosts_test.go b/libnetwork/etchosts/etchosts_test.go index a79b43b6b7..7bd623ddc9 100644 --- a/libnetwork/etchosts/etchosts_test.go +++ b/libnetwork/etchosts/etchosts_test.go @@ -137,6 +137,113 @@ func TestUpdate(t *testing.T) { } } +// This regression test ensures that when a host is given a new IP +// via the Update function that other hosts which start with the +// same name as the targeted host are not erroneously updated as well. +// In the test example, if updating a host called "prefix", unrelated +// hosts named "prefixAndMore" or "prefix2" or anything else starting +// with "prefix" should not be changed. For more information see +// GitHub issue #603. +func TestUpdateIgnoresPrefixedHostname(t *testing.T) { + file, err := ioutil.TempFile("", "") + if err != nil { + t.Fatal(err) + } + defer os.Remove(file.Name()) + + if err := Build(file.Name(), "10.11.12.13", "testhostname", "testdomainname", []Record{ + Record{ + Hosts: "prefix", + IP: "2.2.2.2", + }, + Record{ + Hosts: "prefixAndMore", + IP: "3.3.3.3", + }, + Record{ + Hosts: "unaffectedHost", + IP: "4.4.4.4", + }, + }); err != nil { + t.Fatal(err) + } + + content, err := ioutil.ReadFile(file.Name()) + if err != nil { + t.Fatal(err) + } + + if expected := "2.2.2.2\tprefix\n3.3.3.3\tprefixAndMore\n4.4.4.4\tunaffectedHost\n"; !bytes.Contains(content, []byte(expected)) { + t.Fatalf("Expected to find '%s' got '%s'", expected, content) + } + + if err := Update(file.Name(), "5.5.5.5", "prefix"); err != nil { + t.Fatal(err) + } + + content, err = ioutil.ReadFile(file.Name()) + if err != nil { + t.Fatal(err) + } + + if expected := "5.5.5.5\tprefix\n3.3.3.3\tprefixAndMore\n4.4.4.4\tunaffectedHost\n"; !bytes.Contains(content, []byte(expected)) { + t.Fatalf("Expected to find '%s' got '%s'", expected, content) + } + +} + +// This regression test covers the host prefix issue for the +// Delete function. In the test example, if deleting a host called +// "prefix", an unrelated host called "prefixAndMore" should not +// be deleted. For more information see GitHub issue #603. +func TestDeleteIgnoresPrefixedHostname(t *testing.T) { + file, err := ioutil.TempFile("", "") + if err != nil { + t.Fatal(err) + } + defer os.Remove(file.Name()) + + err = Build(file.Name(), "", "", "", nil) + if err != nil { + t.Fatal(err) + } + + if err := Add(file.Name(), []Record{ + Record{ + Hosts: "prefix", + IP: "1.1.1.1", + }, + Record{ + Hosts: "prefixAndMore", + IP: "2.2.2.2", + }, + }); err != nil { + t.Fatal(err) + } + + if err := Delete(file.Name(), []Record{ + Record{ + Hosts: "prefix", + IP: "1.1.1.1", + }, + }); err != nil { + t.Fatal(err) + } + + content, err := ioutil.ReadFile(file.Name()) + if err != nil { + t.Fatal(err) + } + + if expected := "2.2.2.2\tprefixAndMore\n"; !bytes.Contains(content, []byte(expected)) { + t.Fatalf("Expected to find '%s' got '%s'", expected, content) + } + + if expected := "1.1.1.1\tprefix\n"; bytes.Contains(content, []byte(expected)) { + t.Fatalf("Did not expect to find '%s' got '%s'", expected, content) + } +} + func TestAddEmpty(t *testing.T) { file, err := ioutil.TempFile("", "") if err != nil {