github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/internal/supervisor/iptablesctrl/instance.go (about)

     1  package iptablesctrl
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"strings"
     8  
     9  	"go.aporeto.io/enforcerd/trireme-lib/controller/constants"
    10  	provider "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/aclprovider"
    11  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/ebpf"
    12  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/fqconfig"
    13  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/ipsetmanager"
    14  	"go.aporeto.io/enforcerd/trireme-lib/controller/runtime"
    15  	"go.aporeto.io/enforcerd/trireme-lib/policy"
    16  	"go.uber.org/zap"
    17  )
    18  
    19  const (
    20  	//IPV4 version for ipv4
    21  	IPV4 = iota
    22  	//IPV6 version for ipv6
    23  	IPV6
    24  )
    25  
    26  //Instance is the structure holding the ipv4 and ipv6 handles
    27  type Instance struct {
    28  	iptv4 *iptables
    29  	iptv6 *iptables
    30  }
    31  
    32  // SetTargetNetworks updates ths target networks. There are three different
    33  // types of target networks:
    34  //   - TCPTargetNetworks for TCP traffic (by default 0.0.0.0/0)
    35  //   - UDPTargetNetworks for UDP traffic (by default empty)
    36  //   - ExcludedNetworks that are always ignored (by default empty)
    37  func (i *Instance) SetTargetNetworks(c *runtime.Configuration) error {
    38  
    39  	if err := i.iptv4.SetTargetNetworks(c); err != nil {
    40  		return err
    41  	}
    42  
    43  	if err := i.iptv6.SetTargetNetworks(c); err != nil {
    44  		return err
    45  	}
    46  
    47  	return nil
    48  }
    49  
    50  // Run starts the iptables controller
    51  func (i *Instance) Run(ctx context.Context) error {
    52  
    53  	if err := i.iptv4.Run(ctx); err != nil {
    54  		return err
    55  	}
    56  
    57  	if err := i.iptv6.Run(ctx); err != nil {
    58  		return err
    59  	}
    60  
    61  	return nil
    62  }
    63  
    64  // ConfigureRules implments the ConfigureRules interface. It will create the
    65  // port sets and then it will call install rules to create all the ACLs for
    66  // the given chains. PortSets are only created here. Updates will use the
    67  // exact same logic.
    68  func (i *Instance) ConfigureRules(version int, contextID string, pu *policy.PUInfo) error {
    69  	if err := i.iptv4.ConfigureRules(version, contextID, pu); err != nil {
    70  		return err
    71  	}
    72  
    73  	if err := i.iptv6.ConfigureRules(version, contextID, pu); err != nil {
    74  		return err
    75  	}
    76  
    77  	return nil
    78  }
    79  
    80  // DeleteRules implements the DeleteRules interface. This is responsible
    81  // for cleaning all ACLs and associated chains, as well as ll the sets
    82  // that we have created. Note, that this only clears up the state
    83  // for a given processing unit.
    84  func (i *Instance) DeleteRules(version int, contextID string, tcpPorts, udpPorts string, mark string, username string, containerInfo *policy.PUInfo) error {
    85  
    86  	if err := i.iptv4.DeleteRules(version, contextID, tcpPorts, udpPorts, mark, username, containerInfo); err != nil {
    87  		zap.L().Warn("Delete rules for iptables v4 returned error")
    88  	}
    89  
    90  	if err := i.iptv6.DeleteRules(version, contextID, tcpPorts, udpPorts, mark, username, containerInfo); err != nil {
    91  		zap.L().Warn("Delete rules for iptables v6 returned error")
    92  	}
    93  
    94  	return nil
    95  }
    96  
    97  // UpdateRules implements the update part of the interface. Update will call
    98  // installrules to install the new rules and then it will delete the old rules.
    99  // For installations that do not have latests iptables-restore we time
   100  // the operations so that the switch is almost atomic, by creating the new rules
   101  // first. For latest kernel versions iptables-restorce will update all the rules
   102  // in one shot.
   103  func (i *Instance) UpdateRules(version int, contextID string, containerInfo *policy.PUInfo, oldContainerInfo *policy.PUInfo) error {
   104  
   105  	if err := i.iptv4.UpdateRules(version, contextID, containerInfo, oldContainerInfo); err != nil {
   106  		return err
   107  	}
   108  
   109  	if err := i.iptv6.UpdateRules(version, contextID, containerInfo, oldContainerInfo); err != nil {
   110  		return err
   111  	}
   112  
   113  	return nil
   114  }
   115  
   116  // CleanUp requires the implementor to clean up all ACLs and destroy all
   117  // the IP sets.
   118  func (i *Instance) CleanUp() error {
   119  
   120  	if err := i.iptv4.CleanUp(); err != nil {
   121  		zap.L().Error("Failed to cleanup ipv4 rules")
   122  	}
   123  
   124  	if err := i.iptv6.CleanUp(); err != nil {
   125  		zap.L().Error("Failed to cleanup ipv6 rules")
   126  	}
   127  
   128  	return nil
   129  }
   130  
   131  // CreateCustomRulesChain creates a custom rules chain if it doesnt exist
   132  func (i *Instance) CreateCustomRulesChain() error {
   133  	nonbatchedv4tableprovider, _ := provider.NewGoIPTablesProviderV4([]string{}, CustomQOSChain)
   134  	nonbatchedv6tableprovider, _ := provider.NewGoIPTablesProviderV6([]string{}, CustomQOSChain)
   135  	err := nonbatchedv4tableprovider.NewChain(customQOSChainTable, CustomQOSChain)
   136  	if err != nil {
   137  		zap.L().Debug("Chain already exists", zap.Error(err))
   138  
   139  	}
   140  	postroutingchainrulesv4, err := nonbatchedv4tableprovider.ListRules(customQOSChainTable, customQOSChainNFHook)
   141  	if err != nil {
   142  		zap.L().Error("ListRules returned error", zap.Error(err))
   143  		return err
   144  	}
   145  	checkCustomRulesv4 := func() bool {
   146  		for _, rule := range postroutingchainrulesv4 {
   147  			if strings.Contains(rule, CustomQOSChain) {
   148  				return true
   149  			}
   150  		}
   151  		return false
   152  	}
   153  	if !checkCustomRulesv4() {
   154  		if err := nonbatchedv4tableprovider.Insert(customQOSChainTable, customQOSChainNFHook, 1,
   155  			"-m", "addrtype",
   156  			"--src-type", "LOCAL",
   157  			"-j", CustomQOSChain,
   158  		); err != nil {
   159  			zap.L().Debug("Unable to create ipv4 custom rule", zap.Error(err))
   160  		}
   161  	}
   162  
   163  	err = nonbatchedv6tableprovider.NewChain(customQOSChainTable, CustomQOSChain)
   164  	if err != nil {
   165  		zap.L().Debug("Chain already exists", zap.Error(err))
   166  	}
   167  	postroutingchainrulesv6, err := nonbatchedv6tableprovider.ListRules(customQOSChainTable, customQOSChainNFHook)
   168  	if err != nil {
   169  		return err
   170  	}
   171  	checkCustomRulesv6 := func() bool {
   172  		for _, rule := range postroutingchainrulesv6 {
   173  			if strings.Contains(rule, CustomQOSChain) {
   174  				return true
   175  			}
   176  		}
   177  		return false
   178  	}
   179  	if !checkCustomRulesv6() {
   180  		if err := nonbatchedv6tableprovider.Append(customQOSChainTable, customQOSChainNFHook,
   181  			"-m", "addrtype",
   182  			"--src-type", "LOCAL",
   183  			"-j", CustomQOSChain,
   184  		); err != nil {
   185  			zap.L().Debug("Unable to create ipv6 custom rule", zap.Error(err))
   186  		}
   187  	}
   188  
   189  	return nil
   190  }
   191  
   192  // NewInstance creates a new iptables controller instance
   193  func NewInstance(fqc fqconfig.FilterQueue, mode constants.ModeType, ipv6Enabled bool, ebpf ebpf.BPFModule, iptablesLockfile string, serviceMeshType policy.ServiceMesh) (*Instance, error) {
   194  
   195  	// our iptables binary `aporeto-iptables` uses the environment variable XT_LOCK_NAME
   196  	// to set the iptables lockfile. Standard iptables does not look at this environment variable
   197  	if iptablesLockfile != "" {
   198  		if err := os.Setenv("XT_LOCK_NAME", iptablesLockfile); err != nil {
   199  			return nil, fmt.Errorf("unable to set XT_LOCK_NAME: %s", err)
   200  		}
   201  	}
   202  
   203  	ipv4Impl, err := GetIPv4Impl()
   204  	if err != nil {
   205  		return nil, fmt.Errorf("unable to create ipv4 instance: %s", err)
   206  	}
   207  
   208  	ipsetV4 := ipsetmanager.V4()
   209  	iptInstanceV4 := createIPInstance(ipv4Impl, ipsetV4, fqc, mode, ebpf, serviceMeshType)
   210  
   211  	ipv6Impl, err := GetIPv6Impl(ipv6Enabled)
   212  	if err != nil {
   213  		return nil, fmt.Errorf("unable to create ipv6 instance: %s", err)
   214  	}
   215  
   216  	ipsetV6 := ipsetmanager.V6()
   217  	iptInstanceV6 := createIPInstance(ipv6Impl, ipsetV6, fqc, mode, ebpf, serviceMeshType)
   218  
   219  	return newInstanceWithProviders(iptInstanceV4, iptInstanceV6)
   220  }
   221  
   222  // newInstanceWithProviders is called after ipt and ips have been created. This helps
   223  // with all the unit testing to be able to mock the providers.
   224  func newInstanceWithProviders(iptv4 *iptables, iptv6 *iptables) (*Instance, error) {
   225  
   226  	i := &Instance{
   227  		iptv4: iptv4,
   228  		iptv6: iptv6,
   229  	}
   230  
   231  	return i, nil
   232  }
   233  
   234  // ACLProvider returns the current ACL provider that can be re-used by other entities.
   235  func (i *Instance) ACLProvider() []provider.IptablesProvider {
   236  	return []provider.IptablesProvider{i.iptv4.impl, i.iptv6.impl}
   237  }