Only delete /etc/hosts entries for disconnected network

When a container is connected to a network, it gets /etc/hosts
entries for its addresses on that network. So, when it's connected
to two networks, it has a hosts entry for each. For example, if
the hostname is the default short-id and it's connected to two
networks (172.19.0.0/16 and 172.20.0.0/17, plus IPv6 address for
each), the hosts file might include:

  172.19.0.2	4b92a573912d
  fd8c:c894:d68::2	4b92a573912d
  172.20.0.2	4b92a573912d
  fd8c:c894:d68:1::2	4b92a573912d

If the container is disconnected from 172.19.0.2, only remove
the hosts entries with addresses on that network.

Signed-off-by: Rob Murray <rob.murray@docker.com>
This commit is contained in:
Rob Murray
2024-11-07 11:44:04 +00:00
parent a95a6788b5
commit 8a81a97af5
2 changed files with 24 additions and 7 deletions

View File

@@ -908,7 +908,22 @@ func (ep *Endpoint) sbLeave(ctx context.Context, sb *Sandbox, force bool) error
log.G(ctx).WithError(e).Error("Failed to delete endpoint state for endpoint from cluster")
}
// When a container is connected to a network, it gets /etc/hosts
// entries for its addresses on that network. So, when it's connected
// to two networks, it has a hosts entry for each. For example, if
// the hostname is the default short-id, and it's connected to two
// networks (172.19.0.0/16 and 172.20.0.0/17, plus IPv6 address for
// each), the hosts file might include:
//
// 172.19.0.2 4b92a573912d
// fd8c:c894:d68::2 4b92a573912d
// 172.20.0.2 4b92a573912d
// fd8c:c894:d68:1::2 4b92a573912d
//
// If the container is disconnected from 172.19.0.2, only remove
// the hosts entries with addresses on that network.
sb.deleteHostsEntries(n.getSvcRecords(ep))
if !sb.inDelete && sb.needDefaultGW() && sb.getEndpointInGWNetwork() == nil {
return sb.setupDefaultGW()
}

View File

@@ -8,6 +8,7 @@ import (
"net/netip"
"os"
"regexp"
"strings"
"sync"
)
@@ -127,11 +128,10 @@ func Add(path string, recs []Record) error {
return err
}
// Delete deletes an arbitrary number of Records already existing in /etc/hosts file
//
// FIXME(robmry) - this only matches on hostname, not address. So, if a container
// is connected to two networks then disconnected from one of them, the hosts
// entries for both networks are deleted.
// Delete deletes Records from /etc/hosts.
// The hostnames must be an exact match (if the user has modified the record,
// it won't be deleted). The address, parsed as a netip.Addr must also match
// the value in recs.
func Delete(path string, recs []Record) error {
if len(recs) == 0 {
return nil
@@ -160,8 +160,10 @@ loop:
continue
}
for _, r := range recs {
if bytes.HasSuffix(b, []byte("\t"+r.Hosts)) {
continue loop
if before, found := strings.CutSuffix(string(b), "\t"+r.Hosts); found {
if addr, err := netip.ParseAddr(strings.TrimSpace(before)); err == nil && addr == r.IP {
continue loop
}
}
}
buf.Write(b)