Implement NAT IPv6 to fix the issue https://github.com/moby/moby/issues/25407
Signed-off-by: Billy Ridgway <wrridgwa@us.ibm.com> Signed-off-by: Benjamin Böhmke <benjamin@boehmke.net>
This commit is contained in:
parent
c37654e9d3
commit
8dbb5b5a7d
18 changed files with 535 additions and 273 deletions
|
@ -58,6 +58,7 @@ type configuration struct {
|
||||||
EnableIPForwarding bool
|
EnableIPForwarding bool
|
||||||
EnableIPTables bool
|
EnableIPTables bool
|
||||||
EnableUserlandProxy bool
|
EnableUserlandProxy bool
|
||||||
|
EnableIPv6 bool
|
||||||
UserlandProxyPath string
|
UserlandProxyPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +134,7 @@ type bridgeNetwork struct {
|
||||||
config *networkConfiguration
|
config *networkConfiguration
|
||||||
endpoints map[string]*bridgeEndpoint // key: endpoint id
|
endpoints map[string]*bridgeEndpoint // key: endpoint id
|
||||||
portMapper *portmapper.PortMapper
|
portMapper *portmapper.PortMapper
|
||||||
|
portMapperV6 *portmapper.PortMapper
|
||||||
driver *driver // The network's driver
|
driver *driver // The network's driver
|
||||||
iptCleanFuncs iptablesCleanFuncs
|
iptCleanFuncs iptablesCleanFuncs
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
@ -145,6 +147,10 @@ type driver struct {
|
||||||
filterChain *iptables.ChainInfo
|
filterChain *iptables.ChainInfo
|
||||||
isolationChain1 *iptables.ChainInfo
|
isolationChain1 *iptables.ChainInfo
|
||||||
isolationChain2 *iptables.ChainInfo
|
isolationChain2 *iptables.ChainInfo
|
||||||
|
natChainV6 *iptables.ChainInfo
|
||||||
|
filterChainV6 *iptables.ChainInfo
|
||||||
|
isolationChain1V6 *iptables.ChainInfo
|
||||||
|
isolationChain2V6 *iptables.ChainInfo
|
||||||
networks map[string]*bridgeNetwork
|
networks map[string]*bridgeNetwork
|
||||||
store datastore.DataStore
|
store datastore.DataStore
|
||||||
nlh *netlink.Handle
|
nlh *netlink.Handle
|
||||||
|
@ -277,7 +283,7 @@ func (n *bridgeNetwork) registerIptCleanFunc(clean iptableCleanFunc) {
|
||||||
n.iptCleanFuncs = append(n.iptCleanFuncs, clean)
|
n.iptCleanFuncs = append(n.iptCleanFuncs, clean)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *bridgeNetwork) getDriverChains() (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) {
|
func (n *bridgeNetwork) getDriverChains(version iptables.IPVersion) (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) {
|
||||||
n.Lock()
|
n.Lock()
|
||||||
defer n.Unlock()
|
defer n.Unlock()
|
||||||
|
|
||||||
|
@ -285,6 +291,10 @@ func (n *bridgeNetwork) getDriverChains() (*iptables.ChainInfo, *iptables.ChainI
|
||||||
return nil, nil, nil, nil, types.BadRequestErrorf("no driver found")
|
return nil, nil, nil, nil, types.BadRequestErrorf("no driver found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if version == iptables.IPv6 {
|
||||||
|
return n.driver.natChainV6, n.driver.filterChainV6, n.driver.isolationChain1V6, n.driver.isolationChain2V6, nil
|
||||||
|
}
|
||||||
|
|
||||||
return n.driver.natChain, n.driver.filterChain, n.driver.isolationChain1, n.driver.isolationChain2, nil
|
return n.driver.natChain, n.driver.filterChain, n.driver.isolationChain1, n.driver.isolationChain2, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,7 +323,7 @@ func (n *bridgeNetwork) getEndpoint(eid string) (*bridgeEndpoint, error) {
|
||||||
|
|
||||||
// Install/Removes the iptables rules needed to isolate this network
|
// Install/Removes the iptables rules needed to isolate this network
|
||||||
// from each of the other networks
|
// from each of the other networks
|
||||||
func (n *bridgeNetwork) isolateNetwork(others []*bridgeNetwork, enable bool) error {
|
func (n *bridgeNetwork) isolateNetwork(version iptables.IPVersion, others []*bridgeNetwork, enable bool) error {
|
||||||
n.Lock()
|
n.Lock()
|
||||||
thisConfig := n.config
|
thisConfig := n.config
|
||||||
n.Unlock()
|
n.Unlock()
|
||||||
|
@ -323,7 +333,7 @@ func (n *bridgeNetwork) isolateNetwork(others []*bridgeNetwork, enable bool) err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install the rules to isolate this network against each of the other networks
|
// Install the rules to isolate this network against each of the other networks
|
||||||
return setINC(thisConfig.BridgeName, enable)
|
return setINC(version, thisConfig.BridgeName, enable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driver) configure(option map[string]interface{}) error {
|
func (d *driver) configure(option map[string]interface{}) error {
|
||||||
|
@ -334,6 +344,10 @@ func (d *driver) configure(option map[string]interface{}) error {
|
||||||
filterChain *iptables.ChainInfo
|
filterChain *iptables.ChainInfo
|
||||||
isolationChain1 *iptables.ChainInfo
|
isolationChain1 *iptables.ChainInfo
|
||||||
isolationChain2 *iptables.ChainInfo
|
isolationChain2 *iptables.ChainInfo
|
||||||
|
natChainV6 *iptables.ChainInfo
|
||||||
|
filterChainV6 *iptables.ChainInfo
|
||||||
|
isolationChain1V6 *iptables.ChainInfo
|
||||||
|
isolationChain2V6 *iptables.ChainInfo
|
||||||
)
|
)
|
||||||
|
|
||||||
genericData, ok := option[netlabel.GenericData]
|
genericData, ok := option[netlabel.GenericData]
|
||||||
|
@ -360,13 +374,32 @@ func (d *driver) configure(option map[string]interface{}) error {
|
||||||
logrus.Warnf("Running modprobe bridge br_netfilter failed with message: %s, error: %v", out, err)
|
logrus.Warnf("Running modprobe bridge br_netfilter failed with message: %s, error: %v", out, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
removeIPChains()
|
|
||||||
natChain, filterChain, isolationChain1, isolationChain2, err = setupIPChains(config)
|
removeIPChains(iptables.IPv4)
|
||||||
|
if config.EnableIPv6 {
|
||||||
|
removeIPChains(iptables.IPv6)
|
||||||
|
}
|
||||||
|
|
||||||
|
natChain, filterChain, isolationChain1, isolationChain2, err = setupIPChains(config, iptables.IPv4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if config.EnableIPv6 {
|
||||||
|
natChainV6, filterChainV6, isolationChain1V6, isolationChain2V6, err = setupIPChains(config, iptables.IPv6)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure on firewall reload, first thing being re-played is chains creation
|
// Make sure on firewall reload, first thing being re-played is chains creation
|
||||||
iptables.OnReloaded(func() { logrus.Debugf("Recreating iptables chains on firewall reload"); setupIPChains(config) })
|
iptables.OnReloaded(func() {
|
||||||
|
logrus.Debugf("Recreating iptables chains on firewall reload")
|
||||||
|
setupIPChains(config, iptables.IPv4)
|
||||||
|
})
|
||||||
|
iptables.OnReloaded(func() {
|
||||||
|
logrus.Debugf("Recreating ip6tables chains on firewall reload")
|
||||||
|
setupIPChains(config, iptables.IPv6)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.EnableIPForwarding {
|
if config.EnableIPForwarding {
|
||||||
|
@ -375,6 +408,12 @@ func (d *driver) configure(option map[string]interface{}) error {
|
||||||
logrus.Warn(err)
|
logrus.Warn(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if config.EnableIPv6 {
|
||||||
|
iptable := iptables.GetIptable(iptables.IPv6)
|
||||||
|
if err := iptable.SetDefaultPolicy(iptables.Filter, "FORWARD", iptables.Drop); err != nil {
|
||||||
|
logrus.Warnf("Setting the default DROP policy on firewall reload failed, %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Lock()
|
d.Lock()
|
||||||
|
@ -382,6 +421,10 @@ func (d *driver) configure(option map[string]interface{}) error {
|
||||||
d.filterChain = filterChain
|
d.filterChain = filterChain
|
||||||
d.isolationChain1 = isolationChain1
|
d.isolationChain1 = isolationChain1
|
||||||
d.isolationChain2 = isolationChain2
|
d.isolationChain2 = isolationChain2
|
||||||
|
d.natChainV6 = natChainV6
|
||||||
|
d.filterChainV6 = filterChainV6
|
||||||
|
d.isolationChain1V6 = isolationChain1V6
|
||||||
|
d.isolationChain2V6 = isolationChain2V6
|
||||||
d.config = config
|
d.config = config
|
||||||
d.Unlock()
|
d.Unlock()
|
||||||
|
|
||||||
|
@ -648,6 +691,7 @@ func (d *driver) createNetwork(config *networkConfiguration) (err error) {
|
||||||
endpoints: make(map[string]*bridgeEndpoint),
|
endpoints: make(map[string]*bridgeEndpoint),
|
||||||
config: config,
|
config: config,
|
||||||
portMapper: portmapper.New(d.config.UserlandProxyPath),
|
portMapper: portmapper.New(d.config.UserlandProxyPath),
|
||||||
|
portMapperV6: portmapper.New(d.config.UserlandProxyPath),
|
||||||
bridge: bridgeIface,
|
bridge: bridgeIface,
|
||||||
driver: d,
|
driver: d,
|
||||||
}
|
}
|
||||||
|
@ -667,8 +711,8 @@ func (d *driver) createNetwork(config *networkConfiguration) (err error) {
|
||||||
|
|
||||||
// Add inter-network communication rules.
|
// Add inter-network communication rules.
|
||||||
setupNetworkIsolationRules := func(config *networkConfiguration, i *bridgeInterface) error {
|
setupNetworkIsolationRules := func(config *networkConfiguration, i *bridgeInterface) error {
|
||||||
if err := network.isolateNetwork(networkList, true); err != nil {
|
if err := network.isolateNetwork(iptables.IPv4, networkList, true); err != nil {
|
||||||
if err = network.isolateNetwork(networkList, false); err != nil {
|
if err = network.isolateNetwork(iptables.IPv4, networkList, false); err != nil {
|
||||||
logrus.Warnf("Failed on removing the inter-network iptables rules on cleanup: %v", err)
|
logrus.Warnf("Failed on removing the inter-network iptables rules on cleanup: %v", err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
@ -676,7 +720,7 @@ func (d *driver) createNetwork(config *networkConfiguration) (err error) {
|
||||||
// register the cleanup function
|
// register the cleanup function
|
||||||
network.registerIptCleanFunc(func() error {
|
network.registerIptCleanFunc(func() error {
|
||||||
nwList := d.getNetworks()
|
nwList := d.getNetworks()
|
||||||
return network.isolateNetwork(nwList, false)
|
return network.isolateNetwork(iptables.IPv4, nwList, false)
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -468,11 +468,12 @@ func TestCreateMultipleNetworks(t *testing.T) {
|
||||||
|
|
||||||
// Verify the network isolation rules are installed for each network
|
// Verify the network isolation rules are installed for each network
|
||||||
func verifyV4INCEntries(networks map[string]*bridgeNetwork, t *testing.T) {
|
func verifyV4INCEntries(networks map[string]*bridgeNetwork, t *testing.T) {
|
||||||
out1, err := iptables.Raw("-S", IsolationChain1)
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
|
out1, err := iptable.Raw("-S", IsolationChain1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
out2, err := iptables.Raw("-S", IsolationChain2)
|
out2, err := iptable.Raw("-S", IsolationChain2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -715,6 +716,7 @@ func TestLinkContainers(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
d := newDriver()
|
d := newDriver()
|
||||||
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
|
|
||||||
config := &configuration{
|
config := &configuration{
|
||||||
EnableIPTables: true,
|
EnableIPTables: true,
|
||||||
|
@ -790,7 +792,7 @@ func TestLinkContainers(t *testing.T) {
|
||||||
t.Fatalf("Failed to program external connectivity: %v", err)
|
t.Fatalf("Failed to program external connectivity: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := iptables.Raw("-L", DockerChain)
|
out, err := iptable.Raw("-L", DockerChain)
|
||||||
for _, pm := range exposedPorts {
|
for _, pm := range exposedPorts {
|
||||||
regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port)
|
regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port)
|
||||||
re := regexp.MustCompile(regex)
|
re := regexp.MustCompile(regex)
|
||||||
|
@ -816,7 +818,7 @@ func TestLinkContainers(t *testing.T) {
|
||||||
t.Fatal("Failed to unlink ep1 and ep2")
|
t.Fatal("Failed to unlink ep1 and ep2")
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err = iptables.Raw("-L", DockerChain)
|
out, err = iptable.Raw("-L", DockerChain)
|
||||||
for _, pm := range exposedPorts {
|
for _, pm := range exposedPorts {
|
||||||
regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port)
|
regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port)
|
||||||
re := regexp.MustCompile(regex)
|
re := regexp.MustCompile(regex)
|
||||||
|
@ -844,7 +846,7 @@ func TestLinkContainers(t *testing.T) {
|
||||||
}
|
}
|
||||||
err = d.ProgramExternalConnectivity("net1", "ep2", sbOptions)
|
err = d.ProgramExternalConnectivity("net1", "ep2", sbOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
out, err = iptables.Raw("-L", DockerChain)
|
out, err = iptable.Raw("-L", DockerChain)
|
||||||
for _, pm := range exposedPorts {
|
for _, pm := range exposedPorts {
|
||||||
regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port)
|
regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port)
|
||||||
re := regexp.MustCompile(regex)
|
re := regexp.MustCompile(regex)
|
||||||
|
@ -998,18 +1000,25 @@ func TestCleanupIptableRules(t *testing.T) {
|
||||||
{Name: DockerChain, Table: iptables.Filter},
|
{Name: DockerChain, Table: iptables.Filter},
|
||||||
{Name: IsolationChain1, Table: iptables.Filter},
|
{Name: IsolationChain1, Table: iptables.Filter},
|
||||||
}
|
}
|
||||||
if _, _, _, _, err := setupIPChains(&configuration{EnableIPTables: true}); err != nil {
|
|
||||||
t.Fatalf("Error setting up ip chains: %v", err)
|
ipVersions := []iptables.IPVersion{iptables.IPv4, iptables.IPv6}
|
||||||
|
|
||||||
|
for _, version := range ipVersions {
|
||||||
|
if _, _, _, _, err := setupIPChains(&configuration{EnableIPTables: true}, version); err != nil {
|
||||||
|
t.Fatalf("Error setting up ip chains for %s: %v", version, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iptable := iptables.GetIptable(version)
|
||||||
for _, chainInfo := range bridgeChain {
|
for _, chainInfo := range bridgeChain {
|
||||||
if !iptables.ExistChain(chainInfo.Name, chainInfo.Table) {
|
if !iptable.ExistChain(chainInfo.Name, chainInfo.Table) {
|
||||||
t.Fatalf("iptables chain %s of %s table should have been created", chainInfo.Name, chainInfo.Table)
|
t.Fatalf("iptables version %s chain %s of %s table should have been created", version, chainInfo.Name, chainInfo.Table)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
removeIPChains()
|
removeIPChains(version)
|
||||||
for _, chainInfo := range bridgeChain {
|
for _, chainInfo := range bridgeChain {
|
||||||
if iptables.ExistChain(chainInfo.Name, chainInfo.Table) {
|
if iptable.ExistChain(chainInfo.Name, chainInfo.Table) {
|
||||||
t.Fatalf("iptables chain %s of %s table should have been deleted", chainInfo.Name, chainInfo.Table)
|
t.Fatalf("iptables version %s chain %s of %s table should have been deleted", version, chainInfo.Name, chainInfo.Table)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/libnetwork/types"
|
"github.com/docker/libnetwork/types"
|
||||||
"github.com/ishidawataru/sctp"
|
"github.com/ishidawataru/sctp"
|
||||||
|
@ -13,6 +14,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
defaultBindingIP = net.IPv4(0, 0, 0, 0)
|
defaultBindingIP = net.IPv4(0, 0, 0, 0)
|
||||||
|
defaultBindingIPV6 = net.ParseIP("::")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
|
func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
|
||||||
|
@ -25,11 +27,23 @@ func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, u
|
||||||
defHostIP = reqDefBindIP
|
defHostIP = reqDefBindIP
|
||||||
}
|
}
|
||||||
|
|
||||||
return n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, defHostIP, ulPxyEnabled)
|
var pb []types.PortBinding
|
||||||
|
|
||||||
|
if ep.addrv6 != nil {
|
||||||
|
pb, _ = n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addrv6.IP, defaultBindingIPV6, ulPxyEnabled, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, defHostIP, ulPxyEnabled, pb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool, existingPortBindings []types.PortBinding) ([]types.PortBinding, error) {
|
||||||
|
|
||||||
|
bs := existingPortBindings
|
||||||
|
|
||||||
|
if existingPortBindings == nil {
|
||||||
|
bs = make([]types.PortBinding, 0, len(bindings))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
|
|
||||||
bs := make([]types.PortBinding, 0, len(bindings))
|
|
||||||
for _, c := range bindings {
|
for _, c := range bindings {
|
||||||
b := c.GetCopy()
|
b := c.GetCopy()
|
||||||
if err := n.allocatePort(&b, containerIP, defHostIP, ulPxyEnabled); err != nil {
|
if err := n.allocatePort(&b, containerIP, defHostIP, ulPxyEnabled); err != nil {
|
||||||
|
@ -69,9 +83,15 @@ func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHos
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
portmapper := n.portMapper
|
||||||
|
|
||||||
|
if containerIP.To4() == nil {
|
||||||
|
portmapper = n.portMapperV6
|
||||||
|
}
|
||||||
|
|
||||||
// Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
|
// Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
|
||||||
for i := 0; i < maxAllocatePortAttempts; i++ {
|
for i := 0; i < maxAllocatePortAttempts; i++ {
|
||||||
if host, err = n.portMapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), ulPxyEnabled); err == nil {
|
if host, err = portmapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), ulPxyEnabled); err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// There is no point in immediately retrying to map an explicitly chosen port.
|
// There is no point in immediately retrying to map an explicitly chosen port.
|
||||||
|
@ -128,5 +148,12 @@ func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return n.portMapper.Unmap(host)
|
|
||||||
|
portmapper := n.portMapper
|
||||||
|
|
||||||
|
if strings.ContainsAny(host.String(), "]") == true {
|
||||||
|
portmapper = n.portMapperV6
|
||||||
|
}
|
||||||
|
|
||||||
|
return portmapper.Unmap(host)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,5 +16,9 @@ func (n *bridgeNetwork) setupFirewalld(config *networkConfiguration, i *bridgeIn
|
||||||
iptables.OnReloaded(func() { n.setupIPTables(config, i) })
|
iptables.OnReloaded(func() { n.setupIPTables(config, i) })
|
||||||
iptables.OnReloaded(n.portMapper.ReMapAll)
|
iptables.OnReloaded(n.portMapper.ReMapAll)
|
||||||
|
|
||||||
|
if driverConfig.EnableIPv6 == true {
|
||||||
|
iptables.OnReloaded(n.portMapperV6.ReMapAll)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,8 @@ func setupIPForwarding(enableIPTables bool) error {
|
||||||
if !enableIPTables {
|
if !enableIPTables {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err := iptables.SetDefaultPolicy(iptables.Filter, "FORWARD", iptables.Drop); err != nil {
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
|
if err := iptable.SetDefaultPolicy(iptables.Filter, "FORWARD", iptables.Drop); err != nil {
|
||||||
if err := configureIPForwarding(false); err != nil {
|
if err := configureIPForwarding(false); err != nil {
|
||||||
logrus.Errorf("Disabling IP forwarding failed, %v", err)
|
logrus.Errorf("Disabling IP forwarding failed, %v", err)
|
||||||
}
|
}
|
||||||
|
@ -47,7 +48,7 @@ func setupIPForwarding(enableIPTables bool) error {
|
||||||
}
|
}
|
||||||
iptables.OnReloaded(func() {
|
iptables.OnReloaded(func() {
|
||||||
logrus.Debug("Setting the default DROP policy on firewall reload")
|
logrus.Debug("Setting the default DROP policy on firewall reload")
|
||||||
if err := iptables.SetDefaultPolicy(iptables.Filter, "FORWARD", iptables.Drop); err != nil {
|
if err := iptable.SetDefaultPolicy(iptables.Filter, "FORWARD", iptables.Drop); err != nil {
|
||||||
logrus.Warnf("Setting the default DROP policy on firewall reload failed, %v", err)
|
logrus.Warnf("Setting the default DROP policy on firewall reload failed, %v", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/libnetwork/iptables"
|
"github.com/docker/libnetwork/iptables"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
@ -26,7 +27,7 @@ const (
|
||||||
IsolationChain2 = "DOCKER-ISOLATION-STAGE-2"
|
IsolationChain2 = "DOCKER-ISOLATION-STAGE-2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setupIPChains(config *configuration) (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) {
|
func setupIPChains(config *configuration, version iptables.IPVersion) (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) {
|
||||||
// Sanity check.
|
// Sanity check.
|
||||||
if config.EnableIPTables == false {
|
if config.EnableIPTables == false {
|
||||||
return nil, nil, nil, nil, errors.New("cannot create new chains, EnableIPTable is disabled")
|
return nil, nil, nil, nil, errors.New("cannot create new chains, EnableIPTable is disabled")
|
||||||
|
@ -34,59 +35,61 @@ func setupIPChains(config *configuration) (*iptables.ChainInfo, *iptables.ChainI
|
||||||
|
|
||||||
hairpinMode := !config.EnableUserlandProxy
|
hairpinMode := !config.EnableUserlandProxy
|
||||||
|
|
||||||
natChain, err := iptables.NewChain(DockerChain, iptables.Nat, hairpinMode)
|
iptable := iptables.GetIptable(version)
|
||||||
|
|
||||||
|
natChain, err := iptable.NewChain(DockerChain, iptables.Nat, hairpinMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, nil, fmt.Errorf("failed to create NAT chain %s: %v", DockerChain, err)
|
return nil, nil, nil, nil, fmt.Errorf("failed to create NAT chain %s: %v", DockerChain, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err := iptables.RemoveExistingChain(DockerChain, iptables.Nat); err != nil {
|
if err := iptable.RemoveExistingChain(DockerChain, iptables.Nat); err != nil {
|
||||||
logrus.Warnf("failed on removing iptables NAT chain %s on cleanup: %v", DockerChain, err)
|
logrus.Warnf("failed on removing iptables NAT chain %s on cleanup: %v", DockerChain, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
filterChain, err := iptables.NewChain(DockerChain, iptables.Filter, false)
|
filterChain, err := iptable.NewChain(DockerChain, iptables.Filter, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER chain %s: %v", DockerChain, err)
|
return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER chain %s: %v", DockerChain, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err := iptables.RemoveExistingChain(DockerChain, iptables.Filter); err != nil {
|
if err := iptable.RemoveExistingChain(DockerChain, iptables.Filter); err != nil {
|
||||||
logrus.Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", DockerChain, err)
|
logrus.Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", DockerChain, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
isolationChain1, err := iptables.NewChain(IsolationChain1, iptables.Filter, false)
|
isolationChain1, err := iptable.NewChain(IsolationChain1, iptables.Filter, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER isolation chain: %v", err)
|
return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER isolation chain: %v", err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err := iptables.RemoveExistingChain(IsolationChain1, iptables.Filter); err != nil {
|
if err := iptable.RemoveExistingChain(IsolationChain1, iptables.Filter); err != nil {
|
||||||
logrus.Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", IsolationChain1, err)
|
logrus.Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", IsolationChain1, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
isolationChain2, err := iptables.NewChain(IsolationChain2, iptables.Filter, false)
|
isolationChain2, err := iptable.NewChain(IsolationChain2, iptables.Filter, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER isolation chain: %v", err)
|
return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER isolation chain: %v", err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err := iptables.RemoveExistingChain(IsolationChain2, iptables.Filter); err != nil {
|
if err := iptable.RemoveExistingChain(IsolationChain2, iptables.Filter); err != nil {
|
||||||
logrus.Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", IsolationChain2, err)
|
logrus.Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", IsolationChain2, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err := iptables.AddReturnRule(IsolationChain1); err != nil {
|
if err := iptable.AddReturnRule(IsolationChain1); err != nil {
|
||||||
return nil, nil, nil, nil, err
|
return nil, nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := iptables.AddReturnRule(IsolationChain2); err != nil {
|
if err := iptable.AddReturnRule(IsolationChain2); err != nil {
|
||||||
return nil, nil, nil, nil, err
|
return nil, nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,6 +116,9 @@ func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInt
|
||||||
IP: i.bridgeIPv4.IP.Mask(i.bridgeIPv4.Mask),
|
IP: i.bridgeIPv4.IP.Mask(i.bridgeIPv4.Mask),
|
||||||
Mask: i.bridgeIPv4.Mask,
|
Mask: i.bridgeIPv4.Mask,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
|
|
||||||
if config.Internal {
|
if config.Internal {
|
||||||
if err = setupInternalNetworkRules(config.BridgeName, maskedAddrv4, config.EnableICC, true); err != nil {
|
if err = setupInternalNetworkRules(config.BridgeName, maskedAddrv4, config.EnableICC, true); err != nil {
|
||||||
return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
|
return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
|
||||||
|
@ -127,30 +133,84 @@ func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInt
|
||||||
n.registerIptCleanFunc(func() error {
|
n.registerIptCleanFunc(func() error {
|
||||||
return setupIPTablesInternal(config.HostIP, config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false)
|
return setupIPTablesInternal(config.HostIP, config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false)
|
||||||
})
|
})
|
||||||
natChain, filterChain, _, _, err := n.getDriverChains()
|
natChain, filterChain, _, _, err := n.getDriverChains(iptables.IPv4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error())
|
return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
err = iptables.ProgramChain(natChain, config.BridgeName, hairpinMode, true)
|
err = iptable.ProgramChain(natChain, config.BridgeName, hairpinMode, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to program NAT chain: %s", err.Error())
|
return fmt.Errorf("Failed to program NAT chain: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
err = iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, true)
|
err = iptable.ProgramChain(filterChain, config.BridgeName, hairpinMode, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to program FILTER chain: %s", err.Error())
|
return fmt.Errorf("Failed to program FILTER chain: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
n.registerIptCleanFunc(func() error {
|
n.registerIptCleanFunc(func() error {
|
||||||
return iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, false)
|
return iptable.ProgramChain(filterChain, config.BridgeName, hairpinMode, false)
|
||||||
})
|
})
|
||||||
|
|
||||||
n.portMapper.SetIptablesChain(natChain, n.getNetworkBridgeName())
|
n.portMapper.SetIptablesChain(natChain, n.getNetworkBridgeName())
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Lock()
|
d.Lock()
|
||||||
err = iptables.EnsureJumpRule("FORWARD", IsolationChain1)
|
err = iptable.EnsureJumpRule("FORWARD", IsolationChain1)
|
||||||
|
d.Unlock()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !driverConfig.EnableIPv6 || i.bridgeIPv6 == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
maskedAddrv6 := &net.IPNet{
|
||||||
|
IP: i.bridgeIPv6.IP.Mask(i.bridgeIPv6.Mask),
|
||||||
|
Mask: i.bridgeIPv6.Mask,
|
||||||
|
}
|
||||||
|
|
||||||
|
iptable = iptables.GetIptable(iptables.IPv6)
|
||||||
|
|
||||||
|
if config.Internal {
|
||||||
|
if err = setupInternalNetworkRules(config.BridgeName, maskedAddrv6, config.EnableICC, true); err != nil {
|
||||||
|
return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
|
||||||
|
}
|
||||||
|
n.registerIptCleanFunc(func() error {
|
||||||
|
return setupInternalNetworkRules(config.BridgeName, maskedAddrv6, config.EnableICC, false)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if err = setupIPTablesInternal(nil, config.BridgeName, maskedAddrv6, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil {
|
||||||
|
return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
|
||||||
|
}
|
||||||
|
n.registerIptCleanFunc(func() error {
|
||||||
|
return setupIPTablesInternal(nil, config.BridgeName, maskedAddrv6, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false)
|
||||||
|
})
|
||||||
|
natChainV6, filterChainV6, _, _, err := n.getDriverChains(iptables.IPv6)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = iptable.ProgramChain(natChainV6, config.BridgeName, hairpinMode, true)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to program NAT chain: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = iptable.ProgramChain(filterChainV6, config.BridgeName, hairpinMode, true)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to program FILTER chain: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
n.registerIptCleanFunc(func() error {
|
||||||
|
return iptable.ProgramChain(filterChainV6, config.BridgeName, hairpinMode, false)
|
||||||
|
})
|
||||||
|
|
||||||
|
n.portMapperV6.SetIptablesChain(natChainV6, n.getNetworkBridgeName())
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Lock()
|
||||||
|
err = iptable.EnsureJumpRule("FORWARD", IsolationChain1)
|
||||||
d.Unlock()
|
d.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -189,41 +249,50 @@ func setupIPTablesInternal(hostIP net.IP, bridgeIface string, addr net.Addr, icc
|
||||||
natRule := iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: natArgs}
|
natRule := iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: natArgs}
|
||||||
hpNatRule := iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: hpNatArgs}
|
hpNatRule := iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: hpNatArgs}
|
||||||
|
|
||||||
|
ipVersion := iptables.IPv4
|
||||||
|
|
||||||
|
if strings.Contains(address, ":") {
|
||||||
|
ipVersion = iptables.IPv6
|
||||||
|
}
|
||||||
|
|
||||||
// Set NAT.
|
// Set NAT.
|
||||||
if ipmasq {
|
if ipmasq {
|
||||||
if err := programChainRule(natRule, "NAT", enable); err != nil {
|
if err := programChainRule(ipVersion, natRule, "NAT", enable); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ipmasq && !hairpin {
|
if ipmasq && !hairpin {
|
||||||
if err := programChainRule(skipDNAT, "SKIP DNAT", enable); err != nil {
|
if err := programChainRule(ipVersion, skipDNAT, "SKIP DNAT", enable); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// In hairpin mode, masquerade traffic from localhost
|
// In hairpin mode, masquerade traffic from localhost
|
||||||
if hairpin {
|
if hairpin {
|
||||||
if err := programChainRule(hpNatRule, "MASQ LOCAL HOST", enable); err != nil {
|
if err := programChainRule(ipVersion, hpNatRule, "MASQ LOCAL HOST", enable); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set Inter Container Communication.
|
// Set Inter Container Communication.
|
||||||
if err := setIcc(bridgeIface, icc, enable); err != nil {
|
if err := setIcc(ipVersion, bridgeIface, icc, enable); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set Accept on all non-intercontainer outgoing packets.
|
// Set Accept on all non-intercontainer outgoing packets.
|
||||||
return programChainRule(outRule, "ACCEPT NON_ICC OUTGOING", enable)
|
return programChainRule(ipVersion, outRule, "ACCEPT NON_ICC OUTGOING", enable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func programChainRule(rule iptRule, ruleDescr string, insert bool) error {
|
func programChainRule(version iptables.IPVersion, rule iptRule, ruleDescr string, insert bool) error {
|
||||||
|
|
||||||
|
iptable := iptables.GetIptable(version)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
prefix []string
|
prefix []string
|
||||||
operation string
|
operation string
|
||||||
condition bool
|
condition bool
|
||||||
doesExist = iptables.Exists(rule.table, rule.chain, rule.args...)
|
doesExist = iptable.Exists(rule.table, rule.chain, rule.args...)
|
||||||
)
|
)
|
||||||
|
|
||||||
if insert {
|
if insert {
|
||||||
|
@ -240,7 +309,7 @@ func programChainRule(rule iptRule, ruleDescr string, insert bool) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if condition {
|
if condition {
|
||||||
if err := iptables.RawCombinedOutput(append(prefix, rule.args...)...); err != nil {
|
if err := iptable.RawCombinedOutput(append(prefix, rule.args...)...); err != nil {
|
||||||
return fmt.Errorf("Unable to %s %s rule: %s", operation, ruleDescr, err.Error())
|
return fmt.Errorf("Unable to %s %s rule: %s", operation, ruleDescr, err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,7 +317,8 @@ func programChainRule(rule iptRule, ruleDescr string, insert bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIcc(bridgeIface string, iccEnable, insert bool) error {
|
func setIcc(version iptables.IPVersion, bridgeIface string, iccEnable, insert bool) error {
|
||||||
|
iptable := iptables.GetIptable(version)
|
||||||
var (
|
var (
|
||||||
table = iptables.Filter
|
table = iptables.Filter
|
||||||
chain = "FORWARD"
|
chain = "FORWARD"
|
||||||
|
@ -259,18 +329,18 @@ func setIcc(bridgeIface string, iccEnable, insert bool) error {
|
||||||
|
|
||||||
if insert {
|
if insert {
|
||||||
if !iccEnable {
|
if !iccEnable {
|
||||||
iptables.Raw(append([]string{"-D", chain}, acceptArgs...)...)
|
iptable.Raw(append([]string{"-D", chain}, acceptArgs...)...)
|
||||||
|
|
||||||
if !iptables.Exists(table, chain, dropArgs...) {
|
if !iptable.Exists(table, chain, dropArgs...) {
|
||||||
if err := iptables.RawCombinedOutput(append([]string{"-A", chain}, dropArgs...)...); err != nil {
|
if err := iptable.RawCombinedOutput(append([]string{"-A", chain}, dropArgs...)...); err != nil {
|
||||||
return fmt.Errorf("Unable to prevent intercontainer communication: %s", err.Error())
|
return fmt.Errorf("Unable to prevent intercontainer communication: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
iptables.Raw(append([]string{"-D", chain}, dropArgs...)...)
|
iptable.Raw(append([]string{"-D", chain}, dropArgs...)...)
|
||||||
|
|
||||||
if !iptables.Exists(table, chain, acceptArgs...) {
|
if !iptable.Exists(table, chain, acceptArgs...) {
|
||||||
if err := iptables.RawCombinedOutput(append([]string{"-I", chain}, acceptArgs...)...); err != nil {
|
if err := iptable.RawCombinedOutput(append([]string{"-I", chain}, acceptArgs...)...); err != nil {
|
||||||
return fmt.Errorf("Unable to allow intercontainer communication: %s", err.Error())
|
return fmt.Errorf("Unable to allow intercontainer communication: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -278,12 +348,12 @@ func setIcc(bridgeIface string, iccEnable, insert bool) error {
|
||||||
} else {
|
} else {
|
||||||
// Remove any ICC rule.
|
// Remove any ICC rule.
|
||||||
if !iccEnable {
|
if !iccEnable {
|
||||||
if iptables.Exists(table, chain, dropArgs...) {
|
if iptable.Exists(table, chain, dropArgs...) {
|
||||||
iptables.Raw(append([]string{"-D", chain}, dropArgs...)...)
|
iptable.Raw(append([]string{"-D", chain}, dropArgs...)...)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if iptables.Exists(table, chain, acceptArgs...) {
|
if iptable.Exists(table, chain, acceptArgs...) {
|
||||||
iptables.Raw(append([]string{"-D", chain}, acceptArgs...)...)
|
iptable.Raw(append([]string{"-D", chain}, acceptArgs...)...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,7 +362,8 @@ func setIcc(bridgeIface string, iccEnable, insert bool) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Control Inter Network Communication. Install[Remove] only if it is [not] present.
|
// Control Inter Network Communication. Install[Remove] only if it is [not] present.
|
||||||
func setINC(iface string, enable bool) error {
|
func setINC(version iptables.IPVersion, iface string, enable bool) error {
|
||||||
|
iptable := iptables.GetIptable(version)
|
||||||
var (
|
var (
|
||||||
action = iptables.Insert
|
action = iptables.Insert
|
||||||
actionMsg = "add"
|
actionMsg = "add"
|
||||||
|
@ -309,12 +380,12 @@ func setINC(iface string, enable bool) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, chain := range chains {
|
for i, chain := range chains {
|
||||||
if err := iptables.ProgramRule(iptables.Filter, chain, action, rules[i]); err != nil {
|
if err := iptable.ProgramRule(iptables.Filter, chain, action, rules[i]); err != nil {
|
||||||
msg := fmt.Sprintf("unable to %s inter-network communication rule: %v", actionMsg, err)
|
msg := fmt.Sprintf("unable to %s inter-network communication rule: %v", actionMsg, err)
|
||||||
if enable {
|
if enable {
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
// Rollback the rule installed on first chain
|
// Rollback the rule installed on first chain
|
||||||
if err2 := iptables.ProgramRule(iptables.Filter, chains[0], iptables.Delete, rules[0]); err2 != nil {
|
if err2 := iptable.ProgramRule(iptables.Filter, chains[0], iptables.Delete, rules[0]); err2 != nil {
|
||||||
logrus.Warnf("Failed to rollback iptables rule after failure (%v): %v", err, err2)
|
logrus.Warnf("Failed to rollback iptables rule after failure (%v): %v", err, err2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -330,18 +401,21 @@ func setINC(iface string, enable bool) error {
|
||||||
// Obsolete chain from previous docker versions
|
// Obsolete chain from previous docker versions
|
||||||
const oldIsolationChain = "DOCKER-ISOLATION"
|
const oldIsolationChain = "DOCKER-ISOLATION"
|
||||||
|
|
||||||
func removeIPChains() {
|
func removeIPChains(version iptables.IPVersion) {
|
||||||
|
ipt := iptables.IPTable{Version: version}
|
||||||
|
|
||||||
// Remove obsolete rules from default chains
|
// Remove obsolete rules from default chains
|
||||||
iptables.ProgramRule(iptables.Filter, "FORWARD", iptables.Delete, []string{"-j", oldIsolationChain})
|
ipt.ProgramRule(iptables.Filter, "FORWARD", iptables.Delete, []string{"-j", oldIsolationChain})
|
||||||
|
|
||||||
// Remove chains
|
// Remove chains
|
||||||
for _, chainInfo := range []iptables.ChainInfo{
|
for _, chainInfo := range []iptables.ChainInfo{
|
||||||
{Name: DockerChain, Table: iptables.Nat},
|
{Name: DockerChain, Table: iptables.Nat, IPTable: ipt},
|
||||||
{Name: DockerChain, Table: iptables.Filter},
|
{Name: DockerChain, Table: iptables.Filter, IPTable: ipt},
|
||||||
{Name: IsolationChain1, Table: iptables.Filter},
|
{Name: IsolationChain1, Table: iptables.Filter, IPTable: ipt},
|
||||||
{Name: IsolationChain2, Table: iptables.Filter},
|
{Name: IsolationChain2, Table: iptables.Filter, IPTable: ipt},
|
||||||
{Name: oldIsolationChain, Table: iptables.Filter},
|
{Name: oldIsolationChain, Table: iptables.Filter, IPTable: ipt},
|
||||||
} {
|
} {
|
||||||
|
|
||||||
if err := chainInfo.Remove(); err != nil {
|
if err := chainInfo.Remove(); err != nil {
|
||||||
logrus.Warnf("Failed to remove existing iptables entries in table %s chain %s : %v", chainInfo.Table, chainInfo.Name, err)
|
logrus.Warnf("Failed to remove existing iptables entries in table %s chain %s : %v", chainInfo.Table, chainInfo.Name, err)
|
||||||
}
|
}
|
||||||
|
@ -353,14 +427,21 @@ func setupInternalNetworkRules(bridgeIface string, addr net.Addr, icc, insert bo
|
||||||
inDropRule = iptRule{table: iptables.Filter, chain: IsolationChain1, args: []string{"-i", bridgeIface, "!", "-d", addr.String(), "-j", "DROP"}}
|
inDropRule = iptRule{table: iptables.Filter, chain: IsolationChain1, args: []string{"-i", bridgeIface, "!", "-d", addr.String(), "-j", "DROP"}}
|
||||||
outDropRule = iptRule{table: iptables.Filter, chain: IsolationChain1, args: []string{"-o", bridgeIface, "!", "-s", addr.String(), "-j", "DROP"}}
|
outDropRule = iptRule{table: iptables.Filter, chain: IsolationChain1, args: []string{"-o", bridgeIface, "!", "-s", addr.String(), "-j", "DROP"}}
|
||||||
)
|
)
|
||||||
if err := programChainRule(inDropRule, "DROP INCOMING", insert); err != nil {
|
|
||||||
|
version := iptables.IPv4
|
||||||
|
|
||||||
|
if strings.Contains(addr.String(), ":") {
|
||||||
|
version = iptables.IPv6
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := programChainRule(version, inDropRule, "DROP INCOMING", insert); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := programChainRule(outDropRule, "DROP OUTGOING", insert); err != nil {
|
if err := programChainRule(version, outDropRule, "DROP OUTGOING", insert); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Set Inter Container Communication.
|
// Set Inter Container Communication.
|
||||||
return setIcc(bridgeIface, icc, insert)
|
return setIcc(version, bridgeIface, icc, insert)
|
||||||
}
|
}
|
||||||
|
|
||||||
func clearEndpointConnections(nlh *netlink.Handle, ep *bridgeEndpoint) {
|
func clearEndpointConnections(nlh *netlink.Handle, ep *bridgeEndpoint) {
|
||||||
|
|
|
@ -96,18 +96,20 @@ func createTestBridge(config *networkConfiguration, br *bridgeInterface, t *test
|
||||||
// Assert base function which pushes iptables chain rules on insertion and removal.
|
// Assert base function which pushes iptables chain rules on insertion and removal.
|
||||||
func assertIPTableChainProgramming(rule iptRule, descr string, t *testing.T) {
|
func assertIPTableChainProgramming(rule iptRule, descr string, t *testing.T) {
|
||||||
// Add
|
// Add
|
||||||
if err := programChainRule(rule, descr, true); err != nil {
|
if err := programChainRule(iptables.IPv4, rule, descr, true); err != nil {
|
||||||
t.Fatalf("Failed to program iptable rule %s: %s", descr, err.Error())
|
t.Fatalf("Failed to program iptable rule %s: %s", descr, err.Error())
|
||||||
}
|
}
|
||||||
if iptables.Exists(rule.table, rule.chain, rule.args...) == false {
|
|
||||||
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
|
if iptable.Exists(rule.table, rule.chain, rule.args...) == false {
|
||||||
t.Fatalf("Failed to effectively program iptable rule: %s", descr)
|
t.Fatalf("Failed to effectively program iptable rule: %s", descr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove
|
// Remove
|
||||||
if err := programChainRule(rule, descr, false); err != nil {
|
if err := programChainRule(iptables.IPv4, rule, descr, false); err != nil {
|
||||||
t.Fatalf("Failed to remove iptable rule %s: %s", descr, err.Error())
|
t.Fatalf("Failed to remove iptable rule %s: %s", descr, err.Error())
|
||||||
}
|
}
|
||||||
if iptables.Exists(rule.table, rule.chain, rule.args...) == true {
|
if iptable.Exists(rule.table, rule.chain, rule.args...) == true {
|
||||||
t.Fatalf("Failed to effectively remove iptable rule: %s", descr)
|
t.Fatalf("Failed to effectively remove iptable rule: %s", descr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,7 +118,7 @@ func assertIPTableChainProgramming(rule iptRule, descr string, t *testing.T) {
|
||||||
func assertChainConfig(d *driver, t *testing.T) {
|
func assertChainConfig(d *driver, t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
d.natChain, d.filterChain, d.isolationChain1, d.isolationChain2, err = setupIPChains(d.config)
|
d.natChain, d.filterChain, d.isolationChain1, d.isolationChain2, err = setupIPChains(d.config, iptables.IPv4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,7 +210,9 @@ func programMangle(vni uint32, add bool) (err error) {
|
||||||
action = "install"
|
action = "install"
|
||||||
)
|
)
|
||||||
|
|
||||||
if add == iptables.Exists(iptables.Mangle, chain, rule...) {
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
|
|
||||||
|
if add == iptable.Exists(iptables.Mangle, chain, rule...) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +221,7 @@ func programMangle(vni uint32, add bool) (err error) {
|
||||||
action = "remove"
|
action = "remove"
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = iptables.RawCombinedOutput(append([]string{"-t", string(iptables.Mangle), a, chain}, rule...)...); err != nil {
|
if err = iptable.RawCombinedOutput(append([]string{"-t", string(iptables.Mangle), a, chain}, rule...)...); err != nil {
|
||||||
logrus.Warnf("could not %s mangle rule: %v", action, err)
|
logrus.Warnf("could not %s mangle rule: %v", action, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,16 +241,18 @@ func programInput(vni uint32, add bool) (err error) {
|
||||||
msg = "add"
|
msg = "add"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
|
|
||||||
if !add {
|
if !add {
|
||||||
action = iptables.Delete
|
action = iptables.Delete
|
||||||
msg = "remove"
|
msg = "remove"
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := iptables.ProgramRule(iptables.Filter, chain, action, accept); err != nil {
|
if err := iptable.ProgramRule(iptables.Filter, chain, action, accept); err != nil {
|
||||||
logrus.Errorf("could not %s input rule: %v. Please do it manually.", msg, err)
|
logrus.Errorf("could not %s input rule: %v. Please do it manually.", msg, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := iptables.ProgramRule(iptables.Filter, chain, action, block); err != nil {
|
if err := iptable.ProgramRule(iptables.Filter, chain, action, block); err != nil {
|
||||||
logrus.Errorf("could not %s input rule: %v. Please do it manually.", msg, err)
|
logrus.Errorf("could not %s input rule: %v. Please do it manually.", msg, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,8 @@ func filterWait() func() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func chainExists(cname string) bool {
|
func chainExists(cname string) bool {
|
||||||
if _, err := iptables.Raw("-L", cname); err != nil {
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
|
if _, err := iptable.Raw("-L", cname); err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,22 +29,24 @@ func chainExists(cname string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupGlobalChain() {
|
func setupGlobalChain() {
|
||||||
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
// Because of an ungraceful shutdown, chain could already be present
|
// Because of an ungraceful shutdown, chain could already be present
|
||||||
if !chainExists(globalChain) {
|
if !chainExists(globalChain) {
|
||||||
if err := iptables.RawCombinedOutput("-N", globalChain); err != nil {
|
if err := iptable.RawCombinedOutput("-N", globalChain); err != nil {
|
||||||
logrus.Errorf("could not create global overlay chain: %v", err)
|
logrus.Errorf("could not create global overlay chain: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !iptables.Exists(iptables.Filter, globalChain, "-j", "RETURN") {
|
if !iptable.Exists(iptables.Filter, globalChain, "-j", "RETURN") {
|
||||||
if err := iptables.RawCombinedOutput("-A", globalChain, "-j", "RETURN"); err != nil {
|
if err := iptable.RawCombinedOutput("-A", globalChain, "-j", "RETURN"); err != nil {
|
||||||
logrus.Errorf("could not install default return chain in the overlay global chain: %v", err)
|
logrus.Errorf("could not install default return chain in the overlay global chain: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setNetworkChain(cname string, remove bool) error {
|
func setNetworkChain(cname string, remove bool) error {
|
||||||
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
// Initialize the onetime global overlay chain
|
// Initialize the onetime global overlay chain
|
||||||
filterOnce.Do(setupGlobalChain)
|
filterOnce.Do(setupGlobalChain)
|
||||||
|
|
||||||
|
@ -52,21 +55,21 @@ func setNetworkChain(cname string, remove bool) error {
|
||||||
opt := "-N"
|
opt := "-N"
|
||||||
// In case of remove, make sure to flush the rules in the chain
|
// In case of remove, make sure to flush the rules in the chain
|
||||||
if remove && exists {
|
if remove && exists {
|
||||||
if err := iptables.RawCombinedOutput("-F", cname); err != nil {
|
if err := iptable.RawCombinedOutput("-F", cname); err != nil {
|
||||||
return fmt.Errorf("failed to flush overlay network chain %s rules: %v", cname, err)
|
return fmt.Errorf("failed to flush overlay network chain %s rules: %v", cname, err)
|
||||||
}
|
}
|
||||||
opt = "-X"
|
opt = "-X"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!remove && !exists) || (remove && exists) {
|
if (!remove && !exists) || (remove && exists) {
|
||||||
if err := iptables.RawCombinedOutput(opt, cname); err != nil {
|
if err := iptable.RawCombinedOutput(opt, cname); err != nil {
|
||||||
return fmt.Errorf("failed network chain operation %q for chain %s: %v", opt, cname, err)
|
return fmt.Errorf("failed network chain operation %q for chain %s: %v", opt, cname, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !remove {
|
if !remove {
|
||||||
if !iptables.Exists(iptables.Filter, cname, "-j", "DROP") {
|
if !iptable.Exists(iptables.Filter, cname, "-j", "DROP") {
|
||||||
if err := iptables.RawCombinedOutput("-A", cname, "-j", "DROP"); err != nil {
|
if err := iptable.RawCombinedOutput("-A", cname, "-j", "DROP"); err != nil {
|
||||||
return fmt.Errorf("failed adding default drop rule to overlay network chain %s: %v", cname, err)
|
return fmt.Errorf("failed adding default drop rule to overlay network chain %s: %v", cname, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,37 +95,38 @@ func setFilters(cname, brName string, remove bool) error {
|
||||||
if remove {
|
if remove {
|
||||||
opt = "-D"
|
opt = "-D"
|
||||||
}
|
}
|
||||||
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
|
|
||||||
// Every time we set filters for a new subnet make sure to move the global overlay hook to the top of the both the OUTPUT and forward chains
|
// Every time we set filters for a new subnet make sure to move the global overlay hook to the top of the both the OUTPUT and forward chains
|
||||||
if !remove {
|
if !remove {
|
||||||
for _, chain := range []string{"OUTPUT", "FORWARD"} {
|
for _, chain := range []string{"OUTPUT", "FORWARD"} {
|
||||||
exists := iptables.Exists(iptables.Filter, chain, "-j", globalChain)
|
exists := iptable.Exists(iptables.Filter, chain, "-j", globalChain)
|
||||||
if exists {
|
if exists {
|
||||||
if err := iptables.RawCombinedOutput("-D", chain, "-j", globalChain); err != nil {
|
if err := iptable.RawCombinedOutput("-D", chain, "-j", globalChain); err != nil {
|
||||||
return fmt.Errorf("failed to delete overlay hook in chain %s while moving the hook: %v", chain, err)
|
return fmt.Errorf("failed to delete overlay hook in chain %s while moving the hook: %v", chain, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := iptables.RawCombinedOutput("-I", chain, "-j", globalChain); err != nil {
|
if err := iptable.RawCombinedOutput("-I", chain, "-j", globalChain); err != nil {
|
||||||
return fmt.Errorf("failed to insert overlay hook in chain %s: %v", chain, err)
|
return fmt.Errorf("failed to insert overlay hook in chain %s: %v", chain, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert/Delete the rule to jump to per-bridge chain
|
// Insert/Delete the rule to jump to per-bridge chain
|
||||||
exists := iptables.Exists(iptables.Filter, globalChain, "-o", brName, "-j", cname)
|
exists := iptable.Exists(iptables.Filter, globalChain, "-o", brName, "-j", cname)
|
||||||
if (!remove && !exists) || (remove && exists) {
|
if (!remove && !exists) || (remove && exists) {
|
||||||
if err := iptables.RawCombinedOutput(opt, globalChain, "-o", brName, "-j", cname); err != nil {
|
if err := iptable.RawCombinedOutput(opt, globalChain, "-o", brName, "-j", cname); err != nil {
|
||||||
return fmt.Errorf("failed to add per-bridge filter rule for bridge %s, network chain %s: %v", brName, cname, err)
|
return fmt.Errorf("failed to add per-bridge filter rule for bridge %s, network chain %s: %v", brName, cname, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exists = iptables.Exists(iptables.Filter, cname, "-i", brName, "-j", "ACCEPT")
|
exists = iptable.Exists(iptables.Filter, cname, "-i", brName, "-j", "ACCEPT")
|
||||||
if (!remove && exists) || (remove && !exists) {
|
if (!remove && exists) || (remove && !exists) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := iptables.RawCombinedOutput(opt, cname, "-i", brName, "-j", "ACCEPT"); err != nil {
|
if err := iptable.RawCombinedOutput(opt, cname, "-i", brName, "-j", "ACCEPT"); err != nil {
|
||||||
return fmt.Errorf("failed to add overlay filter rile for network chain %s, bridge %s: %v", cname, brName, err)
|
return fmt.Errorf("failed to add overlay filter rile for network chain %s, bridge %s: %v", cname, brName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,18 +26,19 @@ func arrangeUserFilterRule() {
|
||||||
if ctrl == nil || !ctrl.iptablesEnabled() {
|
if ctrl == nil || !ctrl.iptablesEnabled() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err := iptables.NewChain(userChain, iptables.Filter, false)
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
|
_, err := iptable.NewChain(userChain, iptables.Filter, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Warnf("Failed to create %s chain: %v", userChain, err)
|
logrus.Warnf("Failed to create %s chain: %v", userChain, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = iptables.AddReturnRule(userChain); err != nil {
|
if err = iptable.AddReturnRule(userChain); err != nil {
|
||||||
logrus.Warnf("Failed to add the RETURN rule for %s: %v", userChain, err)
|
logrus.Warnf("Failed to add the RETURN rule for %s: %v", userChain, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = iptables.EnsureJumpRule("FORWARD", userChain)
|
err = iptable.EnsureJumpRule("FORWARD", userChain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Warnf("Failed to ensure the jump rule for %s: %v", userChain, err)
|
logrus.Warnf("Failed to ensure the jump rule for %s: %v", userChain, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUserChain(t *testing.T) {
|
func TestUserChain(t *testing.T) {
|
||||||
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
|
|
||||||
nc, err := New()
|
nc, err := New()
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
@ -60,7 +62,7 @@ func TestUserChain(t *testing.T) {
|
||||||
assert.DeepEqual(t, getRules(t, fwdChainName), []string{"-P FORWARD ACCEPT"})
|
assert.DeepEqual(t, getRules(t, fwdChainName), []string{"-P FORWARD ACCEPT"})
|
||||||
|
|
||||||
if tc.insert {
|
if tc.insert {
|
||||||
_, err = iptables.Raw("-A", fwdChainName, "-j", "DROP")
|
_, err = iptable.Raw("-A", fwdChainName, "-j", "DROP")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
arrangeUserFilterRule()
|
arrangeUserFilterRule()
|
||||||
|
@ -69,7 +71,7 @@ func TestUserChain(t *testing.T) {
|
||||||
if tc.userChain != nil {
|
if tc.userChain != nil {
|
||||||
assert.DeepEqual(t, getRules(t, usrChainName), tc.userChain)
|
assert.DeepEqual(t, getRules(t, usrChainName), tc.userChain)
|
||||||
} else {
|
} else {
|
||||||
_, err := iptables.Raw("-S", usrChainName)
|
_, err := iptable.Raw("-S", usrChainName)
|
||||||
assert.Assert(t, err != nil, "chain %v: created unexpectedly", usrChainName)
|
assert.Assert(t, err != nil, "chain %v: created unexpectedly", usrChainName)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -78,8 +80,10 @@ func TestUserChain(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRules(t *testing.T, chain string) []string {
|
func getRules(t *testing.T, chain string) []string {
|
||||||
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
|
|
||||||
t.Helper()
|
t.Helper()
|
||||||
output, err := iptables.Raw("-S", chain)
|
output, err := iptable.Raw("-S", chain)
|
||||||
assert.NilError(t, err, "chain %s: failed to get rules", chain)
|
assert.NilError(t, err, "chain %s: failed to get rules", chain)
|
||||||
|
|
||||||
rules := strings.Split(string(output), "\n")
|
rules := strings.Split(string(output), "\n")
|
||||||
|
@ -90,8 +94,10 @@ func getRules(t *testing.T, chain string) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func resetIptables(t *testing.T) {
|
func resetIptables(t *testing.T) {
|
||||||
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
|
|
||||||
t.Helper()
|
t.Helper()
|
||||||
_, err := iptables.Raw("-F", fwdChainName)
|
_, err := iptable.Raw("-F", fwdChainName)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
_ = iptables.RemoveExistingChain(usrChainName, "")
|
_ = iptable.RemoveExistingChain(usrChainName, "")
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,14 @@ func TestReloaded(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
var fwdChain *ChainInfo
|
var fwdChain *ChainInfo
|
||||||
|
|
||||||
fwdChain, err = NewChain("FWD", Filter, false)
|
iptable := GetIptable(IPv4)
|
||||||
|
fwdChain, err = iptable.NewChain("FWD", Filter, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
bridgeName := "lo"
|
bridgeName := "lo"
|
||||||
|
|
||||||
err = ProgramChain(fwdChain, bridgeName, false, true)
|
err = iptable.ProgramChain(fwdChain, bridgeName, false, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -54,7 +55,7 @@ func TestReloaded(t *testing.T) {
|
||||||
"--dport", strconv.Itoa(port),
|
"--dport", strconv.Itoa(port),
|
||||||
"-j", "ACCEPT"}
|
"-j", "ACCEPT"}
|
||||||
|
|
||||||
if !Exists(fwdChain.Table, fwdChain.Name, rule1...) {
|
if !iptable.Exists(fwdChain.Table, fwdChain.Name, rule1...) {
|
||||||
t.Fatal("rule1 does not exist")
|
t.Fatal("rule1 does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ func TestReloaded(t *testing.T) {
|
||||||
reloaded()
|
reloaded()
|
||||||
|
|
||||||
// make sure the rules have been recreated
|
// make sure the rules have been recreated
|
||||||
if !Exists(fwdChain.Table, fwdChain.Name, rule1...) {
|
if !iptable.Exists(fwdChain.Table, fwdChain.Name, rule1...) {
|
||||||
t.Fatal("rule1 hasn't been recreated")
|
t.Fatal("rule1 hasn't been recreated")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,12 +77,13 @@ func TestPassthrough(t *testing.T) {
|
||||||
"--dport", "123",
|
"--dport", "123",
|
||||||
"-j", "ACCEPT"}
|
"-j", "ACCEPT"}
|
||||||
|
|
||||||
|
iptable := GetIptable(IPv4)
|
||||||
if firewalldRunning {
|
if firewalldRunning {
|
||||||
_, err := Passthrough(Iptables, append([]string{"-A"}, rule1...)...)
|
_, err := Passthrough(Iptables, append([]string{"-A"}, rule1...)...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !Exists(Filter, "INPUT", rule1...) {
|
if !iptable.Exists(Filter, "INPUT", rule1...) {
|
||||||
t.Fatal("rule1 does not exist")
|
t.Fatal("rule1 does not exist")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,9 @@ type Policy string
|
||||||
// Table refers to Nat, Filter or Mangle.
|
// Table refers to Nat, Filter or Mangle.
|
||||||
type Table string
|
type Table string
|
||||||
|
|
||||||
|
// IPVersion refers to IP version, v4 or v6
|
||||||
|
type IPVersion string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Append appends the rule at the end of the chain.
|
// Append appends the rule at the end of the chain.
|
||||||
Append Action = "-A"
|
Append Action = "-A"
|
||||||
|
@ -40,10 +43,15 @@ const (
|
||||||
Drop Policy = "DROP"
|
Drop Policy = "DROP"
|
||||||
// Accept is the default iptables ACCEPT policy
|
// Accept is the default iptables ACCEPT policy
|
||||||
Accept Policy = "ACCEPT"
|
Accept Policy = "ACCEPT"
|
||||||
|
// IPv4 is version 4
|
||||||
|
IPv4 IPVersion = "IPV4"
|
||||||
|
// IPv6 is version 6
|
||||||
|
IPv6 IPVersion = "IPV6"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
iptablesPath string
|
iptablesPath string
|
||||||
|
ip6tablesPath string
|
||||||
supportsXlock = false
|
supportsXlock = false
|
||||||
supportsCOpt = false
|
supportsCOpt = false
|
||||||
xLockWaitMsg = "Another app is currently holding the xtables lock"
|
xLockWaitMsg = "Another app is currently holding the xtables lock"
|
||||||
|
@ -54,11 +62,17 @@ var (
|
||||||
initOnce sync.Once
|
initOnce sync.Once
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// IPTable defines struct with IPVersion and few other members are added later
|
||||||
|
type IPTable struct {
|
||||||
|
Version IPVersion
|
||||||
|
}
|
||||||
|
|
||||||
// ChainInfo defines the iptables chain.
|
// ChainInfo defines the iptables chain.
|
||||||
type ChainInfo struct {
|
type ChainInfo struct {
|
||||||
Name string
|
Name string
|
||||||
Table Table
|
Table Table
|
||||||
HairpinMode bool
|
HairpinMode bool
|
||||||
|
IPTable IPTable
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChainError is returned to represent errors during ip table operation.
|
// ChainError is returned to represent errors during ip table operation.
|
||||||
|
@ -80,6 +94,11 @@ func probe() {
|
||||||
if out, err := exec.Command(path, "--wait", "-t", "nat", "-L", "-n").CombinedOutput(); err != nil {
|
if out, err := exec.Command(path, "--wait", "-t", "nat", "-L", "-n").CombinedOutput(); err != nil {
|
||||||
logrus.Warnf("Running iptables --wait -t nat -L -n failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
|
logrus.Warnf("Running iptables --wait -t nat -L -n failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
|
||||||
}
|
}
|
||||||
|
_, err = exec.LookPath("ip6tables")
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnf("Failed to find ip6tables: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initFirewalld() {
|
func initFirewalld() {
|
||||||
|
@ -94,6 +113,11 @@ func detectIptables() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
iptablesPath = path
|
iptablesPath = path
|
||||||
|
path, err = exec.LookPath("ip6tables")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ip6tablesPath = path
|
||||||
supportsXlock = exec.Command(iptablesPath, "--wait", "-L", "-n").Run() == nil
|
supportsXlock = exec.Command(iptablesPath, "--wait", "-L", "-n").Run() == nil
|
||||||
mj, mn, mc, err := GetVersion()
|
mj, mn, mc, err := GetVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -118,20 +142,26 @@ func initCheck() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetIptable returns an instance of IPTable with specified version
|
||||||
|
func GetIptable(version IPVersion) *IPTable {
|
||||||
|
return &IPTable{Version: version}
|
||||||
|
}
|
||||||
|
|
||||||
// NewChain adds a new chain to ip table.
|
// NewChain adds a new chain to ip table.
|
||||||
func NewChain(name string, table Table, hairpinMode bool) (*ChainInfo, error) {
|
func (iptable IPTable) NewChain(name string, table Table, hairpinMode bool) (*ChainInfo, error) {
|
||||||
c := &ChainInfo{
|
c := &ChainInfo{
|
||||||
Name: name,
|
Name: name,
|
||||||
Table: table,
|
Table: table,
|
||||||
HairpinMode: hairpinMode,
|
HairpinMode: hairpinMode,
|
||||||
|
IPTable: iptable,
|
||||||
}
|
}
|
||||||
if string(c.Table) == "" {
|
if string(c.Table) == "" {
|
||||||
c.Table = Filter
|
c.Table = Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add chain if it doesn't exist
|
// Add chain if it doesn't exist
|
||||||
if _, err := Raw("-t", string(c.Table), "-n", "-L", c.Name); err != nil {
|
if _, err := iptable.Raw("-t", string(c.Table), "-n", "-L", c.Name); err != nil {
|
||||||
if output, err := Raw("-t", string(c.Table), "-N", c.Name); err != nil {
|
if output, err := iptable.Raw("-t", string(c.Table), "-N", c.Name); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if len(output) != 0 {
|
} else if len(output) != 0 {
|
||||||
return nil, fmt.Errorf("Could not create %s/%s chain: %s", c.Table, c.Name, output)
|
return nil, fmt.Errorf("Could not create %s/%s chain: %s", c.Table, c.Name, output)
|
||||||
|
@ -140,8 +170,16 @@ func NewChain(name string, table Table, hairpinMode bool) (*ChainInfo, error) {
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoopbackByVersion returns loopback address by version
|
||||||
|
func (iptable IPTable) LoopbackByVersion() string {
|
||||||
|
if iptable.Version == IPv6 {
|
||||||
|
return "::1/128"
|
||||||
|
}
|
||||||
|
return "127.0.0.0/8"
|
||||||
|
}
|
||||||
|
|
||||||
// ProgramChain is used to add rules to a chain
|
// ProgramChain is used to add rules to a chain
|
||||||
func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) error {
|
func (iptable IPTable) ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) error {
|
||||||
if c.Name == "" {
|
if c.Name == "" {
|
||||||
return errors.New("Could not program chain, missing chain name")
|
return errors.New("Could not program chain, missing chain name")
|
||||||
}
|
}
|
||||||
|
@ -165,11 +203,11 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) err
|
||||||
"-m", "addrtype",
|
"-m", "addrtype",
|
||||||
"--dst-type", "LOCAL",
|
"--dst-type", "LOCAL",
|
||||||
"-j", c.Name}
|
"-j", c.Name}
|
||||||
if !Exists(Nat, "PREROUTING", preroute...) && enable {
|
if !iptable.Exists(Nat, "PREROUTING", preroute...) && enable {
|
||||||
if err := c.Prerouting(Append, preroute...); err != nil {
|
if err := c.Prerouting(Append, preroute...); err != nil {
|
||||||
return fmt.Errorf("Failed to inject %s in PREROUTING chain: %s", c.Name, err)
|
return fmt.Errorf("Failed to inject %s in PREROUTING chain: %s", c.Name, err)
|
||||||
}
|
}
|
||||||
} else if Exists(Nat, "PREROUTING", preroute...) && !enable {
|
} else if iptable.Exists(Nat, "PREROUTING", preroute...) && !enable {
|
||||||
if err := c.Prerouting(Delete, preroute...); err != nil {
|
if err := c.Prerouting(Delete, preroute...); err != nil {
|
||||||
return fmt.Errorf("Failed to remove %s in PREROUTING chain: %s", c.Name, err)
|
return fmt.Errorf("Failed to remove %s in PREROUTING chain: %s", c.Name, err)
|
||||||
}
|
}
|
||||||
|
@ -179,13 +217,13 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) err
|
||||||
"--dst-type", "LOCAL",
|
"--dst-type", "LOCAL",
|
||||||
"-j", c.Name}
|
"-j", c.Name}
|
||||||
if !hairpinMode {
|
if !hairpinMode {
|
||||||
output = append(output, "!", "--dst", "127.0.0.0/8")
|
output = append(output, "!", "--dst", iptable.LoopbackByVersion())
|
||||||
}
|
}
|
||||||
if !Exists(Nat, "OUTPUT", output...) && enable {
|
if !iptable.Exists(Nat, "OUTPUT", output...) && enable {
|
||||||
if err := c.Output(Append, output...); err != nil {
|
if err := c.Output(Append, output...); err != nil {
|
||||||
return fmt.Errorf("Failed to inject %s in OUTPUT chain: %s", c.Name, err)
|
return fmt.Errorf("Failed to inject %s in OUTPUT chain: %s", c.Name, err)
|
||||||
}
|
}
|
||||||
} else if Exists(Nat, "OUTPUT", output...) && !enable {
|
} else if iptable.Exists(Nat, "OUTPUT", output...) && !enable {
|
||||||
if err := c.Output(Delete, output...); err != nil {
|
if err := c.Output(Delete, output...); err != nil {
|
||||||
return fmt.Errorf("Failed to inject %s in OUTPUT chain: %s", c.Name, err)
|
return fmt.Errorf("Failed to inject %s in OUTPUT chain: %s", c.Name, err)
|
||||||
}
|
}
|
||||||
|
@ -198,16 +236,16 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) err
|
||||||
link := []string{
|
link := []string{
|
||||||
"-o", bridgeName,
|
"-o", bridgeName,
|
||||||
"-j", c.Name}
|
"-j", c.Name}
|
||||||
if !Exists(Filter, "FORWARD", link...) && enable {
|
if !iptable.Exists(Filter, "FORWARD", link...) && enable {
|
||||||
insert := append([]string{string(Insert), "FORWARD"}, link...)
|
insert := append([]string{string(Insert), "FORWARD"}, link...)
|
||||||
if output, err := Raw(insert...); err != nil {
|
if output, err := iptable.Raw(insert...); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if len(output) != 0 {
|
} else if len(output) != 0 {
|
||||||
return fmt.Errorf("Could not create linking rule to %s/%s: %s", c.Table, c.Name, output)
|
return fmt.Errorf("Could not create linking rule to %s/%s: %s", c.Table, c.Name, output)
|
||||||
}
|
}
|
||||||
} else if Exists(Filter, "FORWARD", link...) && !enable {
|
} else if iptable.Exists(Filter, "FORWARD", link...) && !enable {
|
||||||
del := append([]string{string(Delete), "FORWARD"}, link...)
|
del := append([]string{string(Delete), "FORWARD"}, link...)
|
||||||
if output, err := Raw(del...); err != nil {
|
if output, err := iptable.Raw(del...); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if len(output) != 0 {
|
} else if len(output) != 0 {
|
||||||
return fmt.Errorf("Could not delete linking rule from %s/%s: %s", c.Table, c.Name, output)
|
return fmt.Errorf("Could not delete linking rule from %s/%s: %s", c.Table, c.Name, output)
|
||||||
|
@ -219,16 +257,16 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) err
|
||||||
"-m", "conntrack",
|
"-m", "conntrack",
|
||||||
"--ctstate", "RELATED,ESTABLISHED",
|
"--ctstate", "RELATED,ESTABLISHED",
|
||||||
"-j", "ACCEPT"}
|
"-j", "ACCEPT"}
|
||||||
if !Exists(Filter, "FORWARD", establish...) && enable {
|
if !iptable.Exists(Filter, "FORWARD", establish...) && enable {
|
||||||
insert := append([]string{string(Insert), "FORWARD"}, establish...)
|
insert := append([]string{string(Insert), "FORWARD"}, establish...)
|
||||||
if output, err := Raw(insert...); err != nil {
|
if output, err := iptable.Raw(insert...); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if len(output) != 0 {
|
} else if len(output) != 0 {
|
||||||
return fmt.Errorf("Could not create establish rule to %s: %s", c.Table, output)
|
return fmt.Errorf("Could not create establish rule to %s: %s", c.Table, output)
|
||||||
}
|
}
|
||||||
} else if Exists(Filter, "FORWARD", establish...) && !enable {
|
} else if iptable.Exists(Filter, "FORWARD", establish...) && !enable {
|
||||||
del := append([]string{string(Delete), "FORWARD"}, establish...)
|
del := append([]string{string(Delete), "FORWARD"}, establish...)
|
||||||
if output, err := Raw(del...); err != nil {
|
if output, err := iptable.Raw(del...); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if len(output) != 0 {
|
} else if len(output) != 0 {
|
||||||
return fmt.Errorf("Could not delete establish rule from %s: %s", c.Table, output)
|
return fmt.Errorf("Could not delete establish rule from %s: %s", c.Table, output)
|
||||||
|
@ -239,10 +277,11 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveExistingChain removes existing chain from the table.
|
// RemoveExistingChain removes existing chain from the table.
|
||||||
func RemoveExistingChain(name string, table Table) error {
|
func (iptable IPTable) RemoveExistingChain(name string, table Table) error {
|
||||||
c := &ChainInfo{
|
c := &ChainInfo{
|
||||||
Name: name,
|
Name: name,
|
||||||
Table: table,
|
Table: table,
|
||||||
|
IPTable: iptable,
|
||||||
}
|
}
|
||||||
if string(c.Table) == "" {
|
if string(c.Table) == "" {
|
||||||
c.Table = Filter
|
c.Table = Filter
|
||||||
|
@ -252,6 +291,8 @@ func RemoveExistingChain(name string, table Table) error {
|
||||||
|
|
||||||
// Forward adds forwarding rule to 'filter' table and corresponding nat rule to 'nat' table.
|
// Forward adds forwarding rule to 'filter' table and corresponding nat rule to 'nat' table.
|
||||||
func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr string, destPort int, bridgeName string) error {
|
func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr string, destPort int, bridgeName string) error {
|
||||||
|
|
||||||
|
iptable := GetIptable(c.IPTable.Version)
|
||||||
daddr := ip.String()
|
daddr := ip.String()
|
||||||
if ip.IsUnspecified() {
|
if ip.IsUnspecified() {
|
||||||
// iptables interprets "0.0.0.0" as "0.0.0.0/32", whereas we
|
// iptables interprets "0.0.0.0" as "0.0.0.0/32", whereas we
|
||||||
|
@ -266,10 +307,11 @@ func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr
|
||||||
"--dport", strconv.Itoa(port),
|
"--dport", strconv.Itoa(port),
|
||||||
"-j", "DNAT",
|
"-j", "DNAT",
|
||||||
"--to-destination", net.JoinHostPort(destAddr, strconv.Itoa(destPort))}
|
"--to-destination", net.JoinHostPort(destAddr, strconv.Itoa(destPort))}
|
||||||
|
|
||||||
if !c.HairpinMode {
|
if !c.HairpinMode {
|
||||||
args = append(args, "!", "-i", bridgeName)
|
args = append(args, "!", "-i", bridgeName)
|
||||||
}
|
}
|
||||||
if err := ProgramRule(Nat, c.Name, action, args); err != nil {
|
if err := iptable.ProgramRule(Nat, c.Name, action, args); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,7 +323,7 @@ func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr
|
||||||
"--dport", strconv.Itoa(destPort),
|
"--dport", strconv.Itoa(destPort),
|
||||||
"-j", "ACCEPT",
|
"-j", "ACCEPT",
|
||||||
}
|
}
|
||||||
if err := ProgramRule(Filter, c.Name, action, args); err != nil {
|
if err := iptable.ProgramRule(Filter, c.Name, action, args); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +335,7 @@ func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr
|
||||||
"-j", "MASQUERADE",
|
"-j", "MASQUERADE",
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ProgramRule(Nat, "POSTROUTING", action, args); err != nil {
|
if err := iptable.ProgramRule(Nat, "POSTROUTING", action, args); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,7 +353,7 @@ func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr
|
||||||
"-j", "CHECKSUM",
|
"-j", "CHECKSUM",
|
||||||
"--checksum-fill",
|
"--checksum-fill",
|
||||||
}
|
}
|
||||||
if err := ProgramRule(Mangle, "POSTROUTING", action, args); err != nil {
|
if err := iptable.ProgramRule(Mangle, "POSTROUTING", action, args); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -322,6 +364,7 @@ func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr
|
||||||
// Link adds reciprocal ACCEPT rule for two supplied IP addresses.
|
// Link adds reciprocal ACCEPT rule for two supplied IP addresses.
|
||||||
// Traffic is allowed from ip1 to ip2 and vice-versa
|
// Traffic is allowed from ip1 to ip2 and vice-versa
|
||||||
func (c *ChainInfo) Link(action Action, ip1, ip2 net.IP, port int, proto string, bridgeName string) error {
|
func (c *ChainInfo) Link(action Action, ip1, ip2 net.IP, port int, proto string, bridgeName string) error {
|
||||||
|
iptable := GetIptable(c.IPTable.Version)
|
||||||
// forward
|
// forward
|
||||||
args := []string{
|
args := []string{
|
||||||
"-i", bridgeName, "-o", bridgeName,
|
"-i", bridgeName, "-o", bridgeName,
|
||||||
|
@ -331,32 +374,34 @@ func (c *ChainInfo) Link(action Action, ip1, ip2 net.IP, port int, proto string,
|
||||||
"--dport", strconv.Itoa(port),
|
"--dport", strconv.Itoa(port),
|
||||||
"-j", "ACCEPT",
|
"-j", "ACCEPT",
|
||||||
}
|
}
|
||||||
if err := ProgramRule(Filter, c.Name, action, args); err != nil {
|
|
||||||
|
if err := iptable.ProgramRule(Filter, c.Name, action, args); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// reverse
|
// reverse
|
||||||
args[7], args[9] = args[9], args[7]
|
args[7], args[9] = args[9], args[7]
|
||||||
args[10] = "--sport"
|
args[10] = "--sport"
|
||||||
return ProgramRule(Filter, c.Name, action, args)
|
return iptable.ProgramRule(Filter, c.Name, action, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProgramRule adds the rule specified by args only if the
|
// ProgramRule adds the rule specified by args only if the
|
||||||
// rule is not already present in the chain. Reciprocally,
|
// rule is not already present in the chain. Reciprocally,
|
||||||
// it removes the rule only if present.
|
// it removes the rule only if present.
|
||||||
func ProgramRule(table Table, chain string, action Action, args []string) error {
|
func (iptable IPTable) ProgramRule(table Table, chain string, action Action, args []string) error {
|
||||||
if Exists(table, chain, args...) != (action == Delete) {
|
if iptable.Exists(table, chain, args...) != (action == Delete) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return RawCombinedOutput(append([]string{"-t", string(table), string(action), chain}, args...)...)
|
return iptable.RawCombinedOutput(append([]string{"-t", string(table), string(action), chain}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prerouting adds linking rule to nat/PREROUTING chain.
|
// Prerouting adds linking rule to nat/PREROUTING chain.
|
||||||
func (c *ChainInfo) Prerouting(action Action, args ...string) error {
|
func (c *ChainInfo) Prerouting(action Action, args ...string) error {
|
||||||
|
iptable := GetIptable(c.IPTable.Version)
|
||||||
a := []string{"-t", string(Nat), string(action), "PREROUTING"}
|
a := []string{"-t", string(Nat), string(action), "PREROUTING"}
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
a = append(a, args...)
|
a = append(a, args...)
|
||||||
}
|
}
|
||||||
if output, err := Raw(a...); err != nil {
|
if output, err := iptable.Raw(a...); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if len(output) != 0 {
|
} else if len(output) != 0 {
|
||||||
return ChainError{Chain: "PREROUTING", Output: output}
|
return ChainError{Chain: "PREROUTING", Output: output}
|
||||||
|
@ -366,11 +411,12 @@ func (c *ChainInfo) Prerouting(action Action, args ...string) error {
|
||||||
|
|
||||||
// Output adds linking rule to an OUTPUT chain.
|
// Output adds linking rule to an OUTPUT chain.
|
||||||
func (c *ChainInfo) Output(action Action, args ...string) error {
|
func (c *ChainInfo) Output(action Action, args ...string) error {
|
||||||
|
iptable := GetIptable(c.IPTable.Version)
|
||||||
a := []string{"-t", string(c.Table), string(action), "OUTPUT"}
|
a := []string{"-t", string(c.Table), string(action), "OUTPUT"}
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
a = append(a, args...)
|
a = append(a, args...)
|
||||||
}
|
}
|
||||||
if output, err := Raw(a...); err != nil {
|
if output, err := iptable.Raw(a...); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if len(output) != 0 {
|
} else if len(output) != 0 {
|
||||||
return ChainError{Chain: "OUTPUT", Output: output}
|
return ChainError{Chain: "OUTPUT", Output: output}
|
||||||
|
@ -380,35 +426,36 @@ func (c *ChainInfo) Output(action Action, args ...string) error {
|
||||||
|
|
||||||
// Remove removes the chain.
|
// Remove removes the chain.
|
||||||
func (c *ChainInfo) Remove() error {
|
func (c *ChainInfo) Remove() error {
|
||||||
|
iptable := GetIptable(c.IPTable.Version)
|
||||||
// Ignore errors - This could mean the chains were never set up
|
// Ignore errors - This could mean the chains were never set up
|
||||||
if c.Table == Nat {
|
if c.Table == Nat {
|
||||||
c.Prerouting(Delete, "-m", "addrtype", "--dst-type", "LOCAL", "-j", c.Name)
|
c.Prerouting(Delete, "-m", "addrtype", "--dst-type", "LOCAL", "-j", c.Name)
|
||||||
c.Output(Delete, "-m", "addrtype", "--dst-type", "LOCAL", "!", "--dst", "127.0.0.0/8", "-j", c.Name)
|
c.Output(Delete, "-m", "addrtype", "--dst-type", "LOCAL", "!", "--dst", iptable.LoopbackByVersion(), "-j", c.Name)
|
||||||
c.Output(Delete, "-m", "addrtype", "--dst-type", "LOCAL", "-j", c.Name) // Created in versions <= 0.1.6
|
c.Output(Delete, "-m", "addrtype", "--dst-type", "LOCAL", "-j", c.Name) // Created in versions <= 0.1.6
|
||||||
|
|
||||||
c.Prerouting(Delete)
|
c.Prerouting(Delete)
|
||||||
c.Output(Delete)
|
c.Output(Delete)
|
||||||
}
|
}
|
||||||
Raw("-t", string(c.Table), "-F", c.Name)
|
iptable.Raw("-t", string(c.Table), "-F", c.Name)
|
||||||
Raw("-t", string(c.Table), "-X", c.Name)
|
iptable.Raw("-t", string(c.Table), "-X", c.Name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exists checks if a rule exists
|
// Exists checks if a rule exists
|
||||||
func Exists(table Table, chain string, rule ...string) bool {
|
func (iptable IPTable) Exists(table Table, chain string, rule ...string) bool {
|
||||||
return exists(false, table, chain, rule...)
|
return iptable.exists(false, table, chain, rule...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExistsNative behaves as Exists with the difference it
|
// ExistsNative behaves as Exists with the difference it
|
||||||
// will always invoke `iptables` binary.
|
// will always invoke `iptables` binary.
|
||||||
func ExistsNative(table Table, chain string, rule ...string) bool {
|
func (iptable IPTable) ExistsNative(table Table, chain string, rule ...string) bool {
|
||||||
return exists(true, table, chain, rule...)
|
return iptable.exists(true, table, chain, rule...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func exists(native bool, table Table, chain string, rule ...string) bool {
|
func (iptable IPTable) exists(native bool, table Table, chain string, rule ...string) bool {
|
||||||
f := Raw
|
f := iptable.Raw
|
||||||
if native {
|
if native {
|
||||||
f = raw
|
f = iptable.raw
|
||||||
}
|
}
|
||||||
|
|
||||||
if string(table) == "" {
|
if string(table) == "" {
|
||||||
|
@ -429,12 +476,16 @@ func exists(native bool, table Table, chain string, rule ...string) bool {
|
||||||
|
|
||||||
// parse "iptables -S" for the rule (it checks rules in a specific chain
|
// parse "iptables -S" for the rule (it checks rules in a specific chain
|
||||||
// in a specific table and it is very unreliable)
|
// in a specific table and it is very unreliable)
|
||||||
return existsRaw(table, chain, rule...)
|
return iptable.existsRaw(table, chain, rule...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func existsRaw(table Table, chain string, rule ...string) bool {
|
func (iptable IPTable) existsRaw(table Table, chain string, rule ...string) bool {
|
||||||
|
path := iptablesPath
|
||||||
|
if iptable.Version == IPv6 {
|
||||||
|
path = ip6tablesPath
|
||||||
|
}
|
||||||
ruleString := fmt.Sprintf("%s %s\n", chain, strings.Join(rule, " "))
|
ruleString := fmt.Sprintf("%s %s\n", chain, strings.Join(rule, " "))
|
||||||
existingRules, _ := exec.Command(iptablesPath, "-t", string(table), "-S", chain).Output()
|
existingRules, _ := exec.Command(path, "-t", string(table), "-S", chain).Output()
|
||||||
|
|
||||||
return strings.Contains(string(existingRules), ruleString)
|
return strings.Contains(string(existingRules), ruleString)
|
||||||
}
|
}
|
||||||
|
@ -459,7 +510,7 @@ func filterOutput(start time.Time, output []byte, args ...string) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raw calls 'iptables' system command, passing supplied arguments.
|
// Raw calls 'iptables' system command, passing supplied arguments.
|
||||||
func Raw(args ...string) ([]byte, error) {
|
func (iptable IPTable) Raw(args ...string) ([]byte, error) {
|
||||||
if firewalldRunning {
|
if firewalldRunning {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
output, err := Passthrough(Iptables, args...)
|
output, err := Passthrough(Iptables, args...)
|
||||||
|
@ -467,10 +518,10 @@ func Raw(args ...string) ([]byte, error) {
|
||||||
return filterOutput(startTime, output, args...), err
|
return filterOutput(startTime, output, args...), err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return raw(args...)
|
return iptable.raw(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func raw(args ...string) ([]byte, error) {
|
func (iptable IPTable) raw(args ...string) ([]byte, error) {
|
||||||
if err := initCheck(); err != nil {
|
if err := initCheck(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -481,10 +532,15 @@ func raw(args ...string) ([]byte, error) {
|
||||||
defer bestEffortLock.Unlock()
|
defer bestEffortLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debugf("%s, %v", iptablesPath, args)
|
path := iptablesPath
|
||||||
|
if iptable.Version == IPv6 {
|
||||||
|
path = ip6tablesPath
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf("%s, %v", path, args)
|
||||||
|
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
output, err := exec.Command(iptablesPath, args...).CombinedOutput()
|
output, err := exec.Command(path, args...).CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("iptables failed: iptables %v: %s (%s)", strings.Join(args, " "), output, err)
|
return nil, fmt.Errorf("iptables failed: iptables %v: %s (%s)", strings.Join(args, " "), output, err)
|
||||||
}
|
}
|
||||||
|
@ -494,8 +550,8 @@ func raw(args ...string) ([]byte, error) {
|
||||||
|
|
||||||
// RawCombinedOutput internally calls the Raw function and returns a non nil
|
// RawCombinedOutput internally calls the Raw function and returns a non nil
|
||||||
// error if Raw returned a non nil error or a non empty output
|
// error if Raw returned a non nil error or a non empty output
|
||||||
func RawCombinedOutput(args ...string) error {
|
func (iptable IPTable) RawCombinedOutput(args ...string) error {
|
||||||
if output, err := Raw(args...); err != nil || len(output) != 0 {
|
if output, err := iptable.Raw(args...); err != nil || len(output) != 0 {
|
||||||
return fmt.Errorf("%s (%v)", string(output), err)
|
return fmt.Errorf("%s (%v)", string(output), err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -503,16 +559,16 @@ func RawCombinedOutput(args ...string) error {
|
||||||
|
|
||||||
// RawCombinedOutputNative behave as RawCombinedOutput with the difference it
|
// RawCombinedOutputNative behave as RawCombinedOutput with the difference it
|
||||||
// will always invoke `iptables` binary
|
// will always invoke `iptables` binary
|
||||||
func RawCombinedOutputNative(args ...string) error {
|
func (iptable IPTable) RawCombinedOutputNative(args ...string) error {
|
||||||
if output, err := raw(args...); err != nil || len(output) != 0 {
|
if output, err := iptable.raw(args...); err != nil || len(output) != 0 {
|
||||||
return fmt.Errorf("%s (%v)", string(output), err)
|
return fmt.Errorf("%s (%v)", string(output), err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExistChain checks if a chain exists
|
// ExistChain checks if a chain exists
|
||||||
func ExistChain(chain string, table Table) bool {
|
func (iptable IPTable) ExistChain(chain string, table Table) bool {
|
||||||
if _, err := Raw("-t", string(table), "-nL", chain); err == nil {
|
if _, err := iptable.Raw("-t", string(table), "-nL", chain); err == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -528,8 +584,8 @@ func GetVersion() (major, minor, micro int, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDefaultPolicy sets the passed default policy for the table/chain
|
// SetDefaultPolicy sets the passed default policy for the table/chain
|
||||||
func SetDefaultPolicy(table Table, chain string, policy Policy) error {
|
func (iptable IPTable) SetDefaultPolicy(table Table, chain string, policy Policy) error {
|
||||||
if err := RawCombinedOutput("-t", string(table), "-P", chain, string(policy)); err != nil {
|
if err := iptable.RawCombinedOutput("-t", string(table), "-P", chain, string(policy)); err != nil {
|
||||||
return fmt.Errorf("setting default policy to %v in %v chain failed: %v", policy, chain, err)
|
return fmt.Errorf("setting default policy to %v in %v chain failed: %v", policy, chain, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -549,17 +605,17 @@ func supportsCOption(mj, mn, mc int) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddReturnRule adds a return rule for the chain in the filter table
|
// AddReturnRule adds a return rule for the chain in the filter table
|
||||||
func AddReturnRule(chain string) error {
|
func (iptable IPTable) AddReturnRule(chain string) error {
|
||||||
var (
|
var (
|
||||||
table = Filter
|
table = Filter
|
||||||
args = []string{"-j", "RETURN"}
|
args = []string{"-j", "RETURN"}
|
||||||
)
|
)
|
||||||
|
|
||||||
if Exists(table, chain, args...) {
|
if iptable.Exists(table, chain, args...) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err := RawCombinedOutput(append([]string{"-A", chain}, args...)...)
|
err := iptable.RawCombinedOutput(append([]string{"-A", chain}, args...)...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to add return rule in %s chain: %s", chain, err.Error())
|
return fmt.Errorf("unable to add return rule in %s chain: %s", chain, err.Error())
|
||||||
}
|
}
|
||||||
|
@ -568,20 +624,20 @@ func AddReturnRule(chain string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnsureJumpRule ensures the jump rule is on top
|
// EnsureJumpRule ensures the jump rule is on top
|
||||||
func EnsureJumpRule(fromChain, toChain string) error {
|
func (iptable IPTable) EnsureJumpRule(fromChain, toChain string) error {
|
||||||
var (
|
var (
|
||||||
table = Filter
|
table = Filter
|
||||||
args = []string{"-j", toChain}
|
args = []string{"-j", toChain}
|
||||||
)
|
)
|
||||||
|
|
||||||
if Exists(table, fromChain, args...) {
|
if iptable.Exists(table, fromChain, args...) {
|
||||||
err := RawCombinedOutput(append([]string{"-D", fromChain}, args...)...)
|
err := iptable.RawCombinedOutput(append([]string{"-D", fromChain}, args...)...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to remove jump to %s rule in %s chain: %s", toChain, fromChain, err.Error())
|
return fmt.Errorf("unable to remove jump to %s rule in %s chain: %s", toChain, fromChain, err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := RawCombinedOutput(append([]string{"-I", fromChain}, args...)...)
|
err := iptable.RawCombinedOutput(append([]string{"-I", fromChain}, args...)...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to insert jump to %s rule in %s chain: %s", toChain, fromChain, err.Error())
|
return fmt.Errorf("unable to insert jump to %s rule in %s chain: %s", toChain, fromChain, err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,20 +21,22 @@ func TestNewChain(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
bridgeName = "lo"
|
bridgeName = "lo"
|
||||||
natChain, err = NewChain(chainName, Nat, false)
|
iptable := GetIptable(IPv4)
|
||||||
|
|
||||||
|
natChain, err = iptable.NewChain(chainName, Nat, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = ProgramChain(natChain, bridgeName, false, true)
|
err = iptable.ProgramChain(natChain, bridgeName, false, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
filterChain, err = NewChain(chainName, Filter, false)
|
filterChain, err = iptable.NewChain(chainName, Filter, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = ProgramChain(filterChain, bridgeName, false, true)
|
err = iptable.ProgramChain(filterChain, bridgeName, false, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -48,6 +50,8 @@ func TestForward(t *testing.T) {
|
||||||
proto := "tcp"
|
proto := "tcp"
|
||||||
|
|
||||||
bridgeName := "lo"
|
bridgeName := "lo"
|
||||||
|
iptable := GetIptable(IPv4)
|
||||||
|
|
||||||
err := natChain.Forward(Insert, ip, port, proto, dstAddr, dstPort, bridgeName)
|
err := natChain.Forward(Insert, ip, port, proto, dstAddr, dstPort, bridgeName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -62,7 +66,7 @@ func TestForward(t *testing.T) {
|
||||||
"!", "-i", bridgeName,
|
"!", "-i", bridgeName,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Exists(natChain.Table, natChain.Name, dnatRule...) {
|
if !iptable.Exists(natChain.Table, natChain.Name, dnatRule...) {
|
||||||
t.Fatal("DNAT rule does not exist")
|
t.Fatal("DNAT rule does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +79,7 @@ func TestForward(t *testing.T) {
|
||||||
"-j", "ACCEPT",
|
"-j", "ACCEPT",
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Exists(filterChain.Table, filterChain.Name, filterRule...) {
|
if !iptable.Exists(filterChain.Table, filterChain.Name, filterRule...) {
|
||||||
t.Fatal("filter rule does not exist")
|
t.Fatal("filter rule does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +91,7 @@ func TestForward(t *testing.T) {
|
||||||
"-j", "MASQUERADE",
|
"-j", "MASQUERADE",
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Exists(natChain.Table, "POSTROUTING", masqRule...) {
|
if !iptable.Exists(natChain.Table, "POSTROUTING", masqRule...) {
|
||||||
t.Fatal("MASQUERADE rule does not exist")
|
t.Fatal("MASQUERADE rule does not exist")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,6 +100,7 @@ func TestLink(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
bridgeName := "lo"
|
bridgeName := "lo"
|
||||||
|
iptable := GetIptable(IPv4)
|
||||||
ip1 := net.ParseIP("192.168.1.1")
|
ip1 := net.ParseIP("192.168.1.1")
|
||||||
ip2 := net.ParseIP("192.168.1.2")
|
ip2 := net.ParseIP("192.168.1.2")
|
||||||
port := 1234
|
port := 1234
|
||||||
|
@ -115,7 +120,7 @@ func TestLink(t *testing.T) {
|
||||||
"--dport", strconv.Itoa(port),
|
"--dport", strconv.Itoa(port),
|
||||||
"-j", "ACCEPT"}
|
"-j", "ACCEPT"}
|
||||||
|
|
||||||
if !Exists(filterChain.Table, filterChain.Name, rule1...) {
|
if !iptable.Exists(filterChain.Table, filterChain.Name, rule1...) {
|
||||||
t.Fatal("rule1 does not exist")
|
t.Fatal("rule1 does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +133,7 @@ func TestLink(t *testing.T) {
|
||||||
"--sport", strconv.Itoa(port),
|
"--sport", strconv.Itoa(port),
|
||||||
"-j", "ACCEPT"}
|
"-j", "ACCEPT"}
|
||||||
|
|
||||||
if !Exists(filterChain.Table, filterChain.Name, rule2...) {
|
if !iptable.Exists(filterChain.Table, filterChain.Name, rule2...) {
|
||||||
t.Fatal("rule2 does not exist")
|
t.Fatal("rule2 does not exist")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,18 +142,19 @@ func TestPrerouting(t *testing.T) {
|
||||||
args := []string{
|
args := []string{
|
||||||
"-i", "lo",
|
"-i", "lo",
|
||||||
"-d", "192.168.1.1"}
|
"-d", "192.168.1.1"}
|
||||||
|
iptable := GetIptable(IPv4)
|
||||||
|
|
||||||
err := natChain.Prerouting(Insert, args...)
|
err := natChain.Prerouting(Insert, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Exists(natChain.Table, "PREROUTING", args...) {
|
if !iptable.Exists(natChain.Table, "PREROUTING", args...) {
|
||||||
t.Fatal("rule does not exist")
|
t.Fatal("rule does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
delRule := append([]string{"-D", "PREROUTING", "-t", string(Nat)}, args...)
|
delRule := append([]string{"-D", "PREROUTING", "-t", string(Nat)}, args...)
|
||||||
if _, err = Raw(delRule...); err != nil {
|
if _, err = iptable.Raw(delRule...); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,19 +163,20 @@ func TestOutput(t *testing.T) {
|
||||||
args := []string{
|
args := []string{
|
||||||
"-o", "lo",
|
"-o", "lo",
|
||||||
"-d", "192.168.1.1"}
|
"-d", "192.168.1.1"}
|
||||||
|
iptable := GetIptable(IPv4)
|
||||||
|
|
||||||
err := natChain.Output(Insert, args...)
|
err := natChain.Output(Insert, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Exists(natChain.Table, "OUTPUT", args...) {
|
if !iptable.Exists(natChain.Table, "OUTPUT", args...) {
|
||||||
t.Fatal("rule does not exist")
|
t.Fatal("rule does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
delRule := append([]string{"-D", "OUTPUT", "-t",
|
delRule := append([]string{"-D", "OUTPUT", "-t",
|
||||||
string(natChain.Table)}, args...)
|
string(natChain.Table)}, args...)
|
||||||
if _, err = Raw(delRule...); err != nil {
|
if _, err = iptable.Raw(delRule...); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,12 +229,14 @@ func TestCleanup(t *testing.T) {
|
||||||
string(Delete), "FORWARD",
|
string(Delete), "FORWARD",
|
||||||
"-o", bridgeName,
|
"-o", bridgeName,
|
||||||
"-j", filterChain.Name}
|
"-j", filterChain.Name}
|
||||||
if _, err = Raw(link...); err != nil {
|
iptable := GetIptable(IPv4)
|
||||||
|
|
||||||
|
if _, err = iptable.Raw(link...); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
filterChain.Remove()
|
filterChain.Remove()
|
||||||
|
|
||||||
err = RemoveExistingChain(chainName, Nat)
|
err = iptable.RemoveExistingChain(chainName, Nat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -245,20 +254,22 @@ func TestExistsRaw(t *testing.T) {
|
||||||
testChain1 := "ABCD"
|
testChain1 := "ABCD"
|
||||||
testChain2 := "EFGH"
|
testChain2 := "EFGH"
|
||||||
|
|
||||||
_, err := NewChain(testChain1, Filter, false)
|
iptable := GetIptable(IPv4)
|
||||||
|
|
||||||
|
_, err := iptable.NewChain(testChain1, Filter, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
RemoveExistingChain(testChain1, Filter)
|
iptable.RemoveExistingChain(testChain1, Filter)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
_, err = NewChain(testChain2, Filter, false)
|
_, err = iptable.NewChain(testChain2, Filter, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
RemoveExistingChain(testChain2, Filter)
|
iptable.RemoveExistingChain(testChain2, Filter)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Test detection over full and truncated rule string
|
// Test detection over full and truncated rule string
|
||||||
|
@ -271,18 +282,18 @@ func TestExistsRaw(t *testing.T) {
|
||||||
|
|
||||||
for i, r := range input {
|
for i, r := range input {
|
||||||
ruleAdd := append([]string{"-t", string(Filter), "-A", testChain1}, r.rule...)
|
ruleAdd := append([]string{"-t", string(Filter), "-A", testChain1}, r.rule...)
|
||||||
err = RawCombinedOutput(ruleAdd...)
|
err = iptable.RawCombinedOutput(ruleAdd...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("i=%d, err: %v", i, err)
|
t.Fatalf("i=%d, err: %v", i, err)
|
||||||
}
|
}
|
||||||
if !existsRaw(Filter, testChain1, r.rule...) {
|
if !iptable.existsRaw(Filter, testChain1, r.rule...) {
|
||||||
t.Fatalf("Failed to detect rule. i=%d", i)
|
t.Fatalf("Failed to detect rule. i=%d", i)
|
||||||
}
|
}
|
||||||
// Truncate the rule
|
// Truncate the rule
|
||||||
trg := r.rule[len(r.rule)-1]
|
trg := r.rule[len(r.rule)-1]
|
||||||
trg = trg[:len(trg)-2]
|
trg = trg[:len(trg)-2]
|
||||||
r.rule[len(r.rule)-1] = trg
|
r.rule[len(r.rule)-1] = trg
|
||||||
if existsRaw(Filter, testChain1, r.rule...) {
|
if iptable.existsRaw(Filter, testChain1, r.rule...) {
|
||||||
t.Fatalf("Invalid detection. i=%d", i)
|
t.Fatalf("Invalid detection. i=%d", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,7 +195,7 @@ func TestBridge(t *testing.T) {
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("Unexpected format for port mapping in endpoint operational data")
|
t.Fatalf("Unexpected format for port mapping in endpoint operational data")
|
||||||
}
|
}
|
||||||
if len(pm) != 5 {
|
if len(pm) != 10 {
|
||||||
t.Fatalf("Incomplete data for port mapping in endpoint operational data: %d", len(pm))
|
t.Fatalf("Incomplete data for port mapping in endpoint operational data: %d", len(pm))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,7 +151,7 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart,
|
||||||
}
|
}
|
||||||
|
|
||||||
containerIP, containerPort := getIPAndPort(m.container)
|
containerIP, containerPort := getIPAndPort(m.container)
|
||||||
if hostIP.To4() != nil {
|
if hostIP.To4() != nil || hostIP.To16() != nil {
|
||||||
if err := pm.AppendForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
|
if err := pm.AppendForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -170,12 +170,14 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if hostIP.To4() != nil {
|
||||||
if err := m.userlandProxy.Start(); err != nil {
|
if err := m.userlandProxy.Start(); err != nil {
|
||||||
if err := cleanup(); err != nil {
|
if err := cleanup(); err != nil {
|
||||||
return nil, fmt.Errorf("Error during port allocation cleanup: %v", err)
|
return nil, fmt.Errorf("Error during port allocation cleanup: %v", err)
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pm.currentMappings[key] = m
|
pm.currentMappings[key] = m
|
||||||
return m.host, nil
|
return m.host, nil
|
||||||
|
|
|
@ -57,25 +57,27 @@ func reexecSetupResolver() {
|
||||||
os.Exit(3)
|
os.Exit(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
|
|
||||||
// insert outputChain and postroutingchain
|
// insert outputChain and postroutingchain
|
||||||
err = iptables.RawCombinedOutputNative("-t", "nat", "-C", "OUTPUT", "-d", resolverIP, "-j", outputChain)
|
err = iptable.RawCombinedOutputNative("-t", "nat", "-C", "OUTPUT", "-d", resolverIP, "-j", outputChain)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
iptables.RawCombinedOutputNative("-t", "nat", "-F", outputChain)
|
iptable.RawCombinedOutputNative("-t", "nat", "-F", outputChain)
|
||||||
} else {
|
} else {
|
||||||
iptables.RawCombinedOutputNative("-t", "nat", "-N", outputChain)
|
iptable.RawCombinedOutputNative("-t", "nat", "-N", outputChain)
|
||||||
iptables.RawCombinedOutputNative("-t", "nat", "-I", "OUTPUT", "-d", resolverIP, "-j", outputChain)
|
iptable.RawCombinedOutputNative("-t", "nat", "-I", "OUTPUT", "-d", resolverIP, "-j", outputChain)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = iptables.RawCombinedOutputNative("-t", "nat", "-C", "POSTROUTING", "-d", resolverIP, "-j", postroutingchain)
|
err = iptable.RawCombinedOutputNative("-t", "nat", "-C", "POSTROUTING", "-d", resolverIP, "-j", postroutingchain)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
iptables.RawCombinedOutputNative("-t", "nat", "-F", postroutingchain)
|
iptable.RawCombinedOutputNative("-t", "nat", "-F", postroutingchain)
|
||||||
} else {
|
} else {
|
||||||
iptables.RawCombinedOutputNative("-t", "nat", "-N", postroutingchain)
|
iptable.RawCombinedOutputNative("-t", "nat", "-N", postroutingchain)
|
||||||
iptables.RawCombinedOutputNative("-t", "nat", "-I", "POSTROUTING", "-d", resolverIP, "-j", postroutingchain)
|
iptable.RawCombinedOutputNative("-t", "nat", "-I", "POSTROUTING", "-d", resolverIP, "-j", postroutingchain)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rule := range rules {
|
for _, rule := range rules {
|
||||||
if iptables.RawCombinedOutputNative(rule...) != nil {
|
if iptable.RawCombinedOutputNative(rule...) != nil {
|
||||||
logrus.Errorf("set up rule failed, %v", rule)
|
logrus.Errorf("set up rule failed, %v", rule)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -302,6 +302,9 @@ func filterPortConfigs(ingressPorts []*PortConfig, isDelete bool) []*PortConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) error {
|
func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) error {
|
||||||
|
|
||||||
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
|
|
||||||
addDelOpt := "-I"
|
addDelOpt := "-I"
|
||||||
rollbackAddDelOpt := "-D"
|
rollbackAddDelOpt := "-D"
|
||||||
if isDelete {
|
if isDelete {
|
||||||
|
@ -312,19 +315,19 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro
|
||||||
ingressMu.Lock()
|
ingressMu.Lock()
|
||||||
defer ingressMu.Unlock()
|
defer ingressMu.Unlock()
|
||||||
|
|
||||||
chainExists := iptables.ExistChain(ingressChain, iptables.Nat)
|
chainExists := iptable.ExistChain(ingressChain, iptables.Nat)
|
||||||
filterChainExists := iptables.ExistChain(ingressChain, iptables.Filter)
|
filterChainExists := iptable.ExistChain(ingressChain, iptables.Filter)
|
||||||
|
|
||||||
ingressOnce.Do(func() {
|
ingressOnce.Do(func() {
|
||||||
// Flush nat table and filter table ingress chain rules during init if it
|
// Flush nat table and filter table ingress chain rules during init if it
|
||||||
// exists. It might contain stale rules from previous life.
|
// exists. It might contain stale rules from previous life.
|
||||||
if chainExists {
|
if chainExists {
|
||||||
if err := iptables.RawCombinedOutput("-t", "nat", "-F", ingressChain); err != nil {
|
if err := iptable.RawCombinedOutput("-t", "nat", "-F", ingressChain); err != nil {
|
||||||
logrus.Errorf("Could not flush nat table ingress chain rules during init: %v", err)
|
logrus.Errorf("Could not flush nat table ingress chain rules during init: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if filterChainExists {
|
if filterChainExists {
|
||||||
if err := iptables.RawCombinedOutput("-F", ingressChain); err != nil {
|
if err := iptable.RawCombinedOutput("-F", ingressChain); err != nil {
|
||||||
logrus.Errorf("Could not flush filter table ingress chain rules during init: %v", err)
|
logrus.Errorf("Could not flush filter table ingress chain rules during init: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -332,38 +335,38 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro
|
||||||
|
|
||||||
if !isDelete {
|
if !isDelete {
|
||||||
if !chainExists {
|
if !chainExists {
|
||||||
if err := iptables.RawCombinedOutput("-t", "nat", "-N", ingressChain); err != nil {
|
if err := iptable.RawCombinedOutput("-t", "nat", "-N", ingressChain); err != nil {
|
||||||
return fmt.Errorf("failed to create ingress chain: %v", err)
|
return fmt.Errorf("failed to create ingress chain: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !filterChainExists {
|
if !filterChainExists {
|
||||||
if err := iptables.RawCombinedOutput("-N", ingressChain); err != nil {
|
if err := iptable.RawCombinedOutput("-N", ingressChain); err != nil {
|
||||||
return fmt.Errorf("failed to create filter table ingress chain: %v", err)
|
return fmt.Errorf("failed to create filter table ingress chain: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !iptables.Exists(iptables.Nat, ingressChain, "-j", "RETURN") {
|
if !iptable.Exists(iptables.Nat, ingressChain, "-j", "RETURN") {
|
||||||
if err := iptables.RawCombinedOutput("-t", "nat", "-A", ingressChain, "-j", "RETURN"); err != nil {
|
if err := iptable.RawCombinedOutput("-t", "nat", "-A", ingressChain, "-j", "RETURN"); err != nil {
|
||||||
return fmt.Errorf("failed to add return rule in nat table ingress chain: %v", err)
|
return fmt.Errorf("failed to add return rule in nat table ingress chain: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !iptables.Exists(iptables.Filter, ingressChain, "-j", "RETURN") {
|
if !iptable.Exists(iptables.Filter, ingressChain, "-j", "RETURN") {
|
||||||
if err := iptables.RawCombinedOutput("-A", ingressChain, "-j", "RETURN"); err != nil {
|
if err := iptable.RawCombinedOutput("-A", ingressChain, "-j", "RETURN"); err != nil {
|
||||||
return fmt.Errorf("failed to add return rule to filter table ingress chain: %v", err)
|
return fmt.Errorf("failed to add return rule to filter table ingress chain: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, chain := range []string{"OUTPUT", "PREROUTING"} {
|
for _, chain := range []string{"OUTPUT", "PREROUTING"} {
|
||||||
if !iptables.Exists(iptables.Nat, chain, "-m", "addrtype", "--dst-type", "LOCAL", "-j", ingressChain) {
|
if !iptable.Exists(iptables.Nat, chain, "-m", "addrtype", "--dst-type", "LOCAL", "-j", ingressChain) {
|
||||||
if err := iptables.RawCombinedOutput("-t", "nat", "-I", chain, "-m", "addrtype", "--dst-type", "LOCAL", "-j", ingressChain); err != nil {
|
if err := iptable.RawCombinedOutput("-t", "nat", "-I", chain, "-m", "addrtype", "--dst-type", "LOCAL", "-j", ingressChain); err != nil {
|
||||||
return fmt.Errorf("failed to add jump rule in %s to ingress chain: %v", chain, err)
|
return fmt.Errorf("failed to add jump rule in %s to ingress chain: %v", chain, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !iptables.Exists(iptables.Filter, "FORWARD", "-j", ingressChain) {
|
if !iptable.Exists(iptables.Filter, "FORWARD", "-j", ingressChain) {
|
||||||
if err := iptables.RawCombinedOutput("-I", "FORWARD", "-j", ingressChain); err != nil {
|
if err := iptable.RawCombinedOutput("-I", "FORWARD", "-j", ingressChain); err != nil {
|
||||||
return fmt.Errorf("failed to add jump rule to %s in filter table forward chain: %v", ingressChain, err)
|
return fmt.Errorf("failed to add jump rule to %s in filter table forward chain: %v", ingressChain, err)
|
||||||
}
|
}
|
||||||
arrangeUserFilterRule()
|
arrangeUserFilterRule()
|
||||||
|
@ -380,8 +383,8 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro
|
||||||
}
|
}
|
||||||
|
|
||||||
ruleArgs := strings.Fields(fmt.Sprintf("-m addrtype --src-type LOCAL -o %s -j MASQUERADE", oifName))
|
ruleArgs := strings.Fields(fmt.Sprintf("-m addrtype --src-type LOCAL -o %s -j MASQUERADE", oifName))
|
||||||
if !iptables.Exists(iptables.Nat, "POSTROUTING", ruleArgs...) {
|
if !iptable.Exists(iptables.Nat, "POSTROUTING", ruleArgs...) {
|
||||||
if err := iptables.RawCombinedOutput(append([]string{"-t", "nat", "-I", "POSTROUTING"}, ruleArgs...)...); err != nil {
|
if err := iptable.RawCombinedOutput(append([]string{"-t", "nat", "-I", "POSTROUTING"}, ruleArgs...)...); err != nil {
|
||||||
return fmt.Errorf("failed to add ingress localhost POSTROUTING rule for %s: %v", oifName, err)
|
return fmt.Errorf("failed to add ingress localhost POSTROUTING rule for %s: %v", oifName, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -395,7 +398,7 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro
|
||||||
if portErr != nil && !isDelete {
|
if portErr != nil && !isDelete {
|
||||||
filterPortConfigs(filteredPorts, !isDelete)
|
filterPortConfigs(filteredPorts, !isDelete)
|
||||||
for _, rule := range rollbackRules {
|
for _, rule := range rollbackRules {
|
||||||
if err := iptables.RawCombinedOutput(rule...); err != nil {
|
if err := iptable.RawCombinedOutput(rule...); err != nil {
|
||||||
logrus.Warnf("roll back rule failed, %v: %v", rule, err)
|
logrus.Warnf("roll back rule failed, %v: %v", rule, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -403,10 +406,10 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for _, iPort := range filteredPorts {
|
for _, iPort := range filteredPorts {
|
||||||
if iptables.ExistChain(ingressChain, iptables.Nat) {
|
if iptable.ExistChain(ingressChain, iptables.Nat) {
|
||||||
rule := strings.Fields(fmt.Sprintf("-t nat %s %s -p %s --dport %d -j DNAT --to-destination %s:%d",
|
rule := strings.Fields(fmt.Sprintf("-t nat %s %s -p %s --dport %d -j DNAT --to-destination %s:%d",
|
||||||
addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort, gwIP, iPort.PublishedPort))
|
addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort, gwIP, iPort.PublishedPort))
|
||||||
if portErr = iptables.RawCombinedOutput(rule...); portErr != nil {
|
if portErr = iptable.RawCombinedOutput(rule...); portErr != nil {
|
||||||
errStr := fmt.Sprintf("set up rule failed, %v: %v", rule, portErr)
|
errStr := fmt.Sprintf("set up rule failed, %v: %v", rule, portErr)
|
||||||
if !isDelete {
|
if !isDelete {
|
||||||
return fmt.Errorf("%s", errStr)
|
return fmt.Errorf("%s", errStr)
|
||||||
|
@ -423,7 +426,7 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro
|
||||||
// 2) unmanaged containers on bridge networks
|
// 2) unmanaged containers on bridge networks
|
||||||
rule := strings.Fields(fmt.Sprintf("%s %s -m state -p %s --sport %d --state ESTABLISHED,RELATED -j ACCEPT",
|
rule := strings.Fields(fmt.Sprintf("%s %s -m state -p %s --sport %d --state ESTABLISHED,RELATED -j ACCEPT",
|
||||||
addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort))
|
addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort))
|
||||||
if portErr = iptables.RawCombinedOutput(rule...); portErr != nil {
|
if portErr = iptable.RawCombinedOutput(rule...); portErr != nil {
|
||||||
errStr := fmt.Sprintf("set up rule failed, %v: %v", rule, portErr)
|
errStr := fmt.Sprintf("set up rule failed, %v: %v", rule, portErr)
|
||||||
if !isDelete {
|
if !isDelete {
|
||||||
return fmt.Errorf("%s", errStr)
|
return fmt.Errorf("%s", errStr)
|
||||||
|
@ -436,7 +439,7 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro
|
||||||
|
|
||||||
rule = strings.Fields(fmt.Sprintf("%s %s -p %s --dport %d -j ACCEPT",
|
rule = strings.Fields(fmt.Sprintf("%s %s -p %s --dport %d -j ACCEPT",
|
||||||
addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort))
|
addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort))
|
||||||
if portErr = iptables.RawCombinedOutput(rule...); portErr != nil {
|
if portErr = iptable.RawCombinedOutput(rule...); portErr != nil {
|
||||||
errStr := fmt.Sprintf("set up rule failed, %v: %v", rule, portErr)
|
errStr := fmt.Sprintf("set up rule failed, %v: %v", rule, portErr)
|
||||||
if !isDelete {
|
if !isDelete {
|
||||||
return fmt.Errorf("%s", errStr)
|
return fmt.Errorf("%s", errStr)
|
||||||
|
@ -461,13 +464,14 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro
|
||||||
// This chain has the rules to allow access to the published ports for swarm tasks
|
// This chain has the rules to allow access to the published ports for swarm tasks
|
||||||
// from local bridge networks and docker_gwbridge (ie:taks on other swarm networks)
|
// from local bridge networks and docker_gwbridge (ie:taks on other swarm networks)
|
||||||
func arrangeIngressFilterRule() {
|
func arrangeIngressFilterRule() {
|
||||||
if iptables.ExistChain(ingressChain, iptables.Filter) {
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
if iptables.Exists(iptables.Filter, "FORWARD", "-j", ingressChain) {
|
if iptable.ExistChain(ingressChain, iptables.Filter) {
|
||||||
if err := iptables.RawCombinedOutput("-D", "FORWARD", "-j", ingressChain); err != nil {
|
if iptable.Exists(iptables.Filter, "FORWARD", "-j", ingressChain) {
|
||||||
|
if err := iptable.RawCombinedOutput("-D", "FORWARD", "-j", ingressChain); err != nil {
|
||||||
logrus.Warnf("failed to delete jump rule to ingressChain in filter table: %v", err)
|
logrus.Warnf("failed to delete jump rule to ingressChain in filter table: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := iptables.RawCombinedOutput("-I", "FORWARD", "-j", ingressChain); err != nil {
|
if err := iptable.RawCombinedOutput("-I", "FORWARD", "-j", ingressChain); err != nil {
|
||||||
logrus.Warnf("failed to add jump rule to ingressChain in filter table: %v", err)
|
logrus.Warnf("failed to add jump rule to ingressChain in filter table: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -606,6 +610,7 @@ func invokeFWMarker(path string, vip net.IP, fwMark uint32, ingressPorts []*Port
|
||||||
|
|
||||||
// Firewall marker reexec function.
|
// Firewall marker reexec function.
|
||||||
func fwMarker() {
|
func fwMarker() {
|
||||||
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
defer runtime.UnlockOSThread()
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
@ -660,7 +665,7 @@ func fwMarker() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ruleParams := strings.Fields(fmt.Sprintf("-m ipvs --ipvs -d %s -j SNAT --to-source %s", subnet, eIP))
|
ruleParams := strings.Fields(fmt.Sprintf("-m ipvs --ipvs -d %s -j SNAT --to-source %s", subnet, eIP))
|
||||||
if !iptables.Exists("nat", "POSTROUTING", ruleParams...) {
|
if !iptable.Exists("nat", "POSTROUTING", ruleParams...) {
|
||||||
rule := append(strings.Fields("-t nat -A POSTROUTING"), ruleParams...)
|
rule := append(strings.Fields("-t nat -A POSTROUTING"), ruleParams...)
|
||||||
rules = append(rules, rule)
|
rules = append(rules, rule)
|
||||||
|
|
||||||
|
@ -676,7 +681,7 @@ func fwMarker() {
|
||||||
rules = append(rules, rule)
|
rules = append(rules, rule)
|
||||||
|
|
||||||
for _, rule := range rules {
|
for _, rule := range rules {
|
||||||
if err := iptables.RawCombinedOutputNative(rule...); err != nil {
|
if err := iptable.RawCombinedOutputNative(rule...); err != nil {
|
||||||
logrus.Errorf("set up rule failed, %v: %v", rule, err)
|
logrus.Errorf("set up rule failed, %v: %v", rule, err)
|
||||||
os.Exit(8)
|
os.Exit(8)
|
||||||
}
|
}
|
||||||
|
@ -711,6 +716,7 @@ func addRedirectRules(path string, eIP *net.IPNet, ingressPorts []*PortConfig) e
|
||||||
|
|
||||||
// Redirector reexec function.
|
// Redirector reexec function.
|
||||||
func redirector() {
|
func redirector() {
|
||||||
|
iptable := iptables.GetIptable(iptables.IPv4)
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
defer runtime.UnlockOSThread()
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
@ -763,7 +769,7 @@ func redirector() {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rule := range rules {
|
for _, rule := range rules {
|
||||||
if err := iptables.RawCombinedOutputNative(rule...); err != nil {
|
if err := iptable.RawCombinedOutputNative(rule...); err != nil {
|
||||||
logrus.Errorf("set up rule failed, %v: %v", rule, err)
|
logrus.Errorf("set up rule failed, %v: %v", rule, err)
|
||||||
os.Exit(6)
|
os.Exit(6)
|
||||||
}
|
}
|
||||||
|
@ -779,15 +785,15 @@ func redirector() {
|
||||||
{"-d", eIP.String(), "-p", "udp", "-j", "DROP"},
|
{"-d", eIP.String(), "-p", "udp", "-j", "DROP"},
|
||||||
{"-d", eIP.String(), "-p", "tcp", "-j", "DROP"},
|
{"-d", eIP.String(), "-p", "tcp", "-j", "DROP"},
|
||||||
} {
|
} {
|
||||||
if !iptables.ExistsNative(iptables.Filter, "INPUT", rule...) {
|
if !iptable.ExistsNative(iptables.Filter, "INPUT", rule...) {
|
||||||
if err := iptables.RawCombinedOutputNative(append([]string{"-A", "INPUT"}, rule...)...); err != nil {
|
if err := iptable.RawCombinedOutputNative(append([]string{"-A", "INPUT"}, rule...)...); err != nil {
|
||||||
logrus.Errorf("set up rule failed, %v: %v", rule, err)
|
logrus.Errorf("set up rule failed, %v: %v", rule, err)
|
||||||
os.Exit(7)
|
os.Exit(7)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rule[0] = "-s"
|
rule[0] = "-s"
|
||||||
if !iptables.ExistsNative(iptables.Filter, "OUTPUT", rule...) {
|
if !iptable.ExistsNative(iptables.Filter, "OUTPUT", rule...) {
|
||||||
if err := iptables.RawCombinedOutputNative(append([]string{"-A", "OUTPUT"}, rule...)...); err != nil {
|
if err := iptable.RawCombinedOutputNative(append([]string{"-A", "OUTPUT"}, rule...)...); err != nil {
|
||||||
logrus.Errorf("set up rule failed, %v: %v", rule, err)
|
logrus.Errorf("set up rule failed, %v: %v", rule, err)
|
||||||
os.Exit(8)
|
os.Exit(8)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue