//go:build linux package bridge import ( "context" "fmt" "net" "github.com/containerd/log" "github.com/docker/docker/libnetwork/iptables" "github.com/docker/docker/libnetwork/types" ) type link struct { parentIP net.IP childIP net.IP ports []types.TransportPort bridge string } func (l *link) String() string { return fmt.Sprintf("%s <-> %s [%v] on %s", l.parentIP, l.childIP, l.ports, l.bridge) } func newLink(parentIP, childIP net.IP, ports []types.TransportPort, bridge string) (*link, error) { if parentIP == nil { return nil, fmt.Errorf("cannot link to a container with an empty parent IP address") } if childIP == nil { return nil, fmt.Errorf("cannot link to a container with an empty child IP address") } return &link{ childIP: childIP, parentIP: parentIP, ports: ports, bridge: bridge, }, nil } func (l *link) Enable() error { linkFunction := func() error { return linkContainers(iptables.Append, l.parentIP, l.childIP, l.ports, l.bridge, false) } if err := linkFunction(); err != nil { return err } iptables.OnReloaded(func() { _ = linkFunction() }) return nil } func (l *link) Disable() { if err := linkContainers(iptables.Delete, l.parentIP, l.childIP, l.ports, l.bridge, true); err != nil { // @TODO: Return error once we have the iptables package return typed errors. log.G(context.TODO()).WithError(err).Errorf("Error removing IPTables rules for link: %s", l.String()) } } func linkContainers(action iptables.Action, parentIP, childIP net.IP, ports []types.TransportPort, bridge string, ignoreErrors bool) error { if parentIP == nil { return fmt.Errorf("cannot link to a container with an empty parent IP address") } if childIP == nil { return fmt.Errorf("cannot link to a container with an empty child IP address") } chain := iptables.ChainInfo{Name: DockerChain} for _, port := range ports { err := chain.Link(action, parentIP, childIP, int(port.Port), port.Proto.String(), bridge) if !ignoreErrors && err != nil { return err } } return nil }