github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/pkg/ipsetmanager/ipsetprovider.go (about)

     1  // +build linux darwin
     2  
     3  package ipsetmanager
     4  
     5  import (
     6  	"fmt"
     7  	"os/exec"
     8  	"strings"
     9  
    10  	"github.com/aporeto-inc/go-ipset/ipset"
    11  	"go.aporeto.io/enforcerd/trireme-lib/controller/constants"
    12  	"go.uber.org/zap"
    13  )
    14  
    15  var (
    16  	// path to aporeto-ipset
    17  	ipsetBinPath string
    18  )
    19  
    20  // IpsetProvider returns a fabric for Ipset.
    21  type IpsetProvider interface {
    22  	NewIpset(name string, ipsetType string, p *ipset.Params) (Ipset, error)
    23  	GetIpset(name string) Ipset
    24  	DestroyAll(prefix string) error
    25  	ListIPSets() ([]string, error)
    26  }
    27  
    28  // Ipset is an abstraction of all the methods an implementation of userspace
    29  // ipsets need to provide.
    30  type Ipset interface {
    31  	Add(entry string, timeout int) error
    32  	AddOption(entry string, option string, timeout int) error
    33  	Del(entry string) error
    34  	Destroy() error
    35  	Flush() error
    36  	Test(entry string) (bool, error)
    37  }
    38  
    39  type goIpsetProvider struct{}
    40  
    41  var instance IpsetProvider = &goIpsetProvider{}
    42  
    43  func ipsetCreateBitmapPort(setname string) error {
    44  	//Bitmap type is not supported by the ipset library
    45  	out, err := exec.Command(ipsetBinPath, "create", setname, "bitmap:port", "range", "0-65535", "timeout", "0").CombinedOutput()
    46  	if err != nil {
    47  		if strings.Contains(string(out), "set with the same name already exists") {
    48  			zap.L().Warn("Set already exists - cleaning up", zap.String("set name", setname))
    49  			// Clean up the existing set
    50  			if _, cerr := exec.Command(ipsetBinPath, "-F", setname).CombinedOutput(); cerr != nil {
    51  				return fmt.Errorf("Failed to clean up existing ipset: %s", err)
    52  			}
    53  			return nil
    54  		}
    55  		zap.L().Error("Unable to create set", zap.String("set name", setname), zap.String("ipset-output", string(out)))
    56  	}
    57  	return err
    58  }
    59  
    60  // NewIpset returns an IpsetProvider interface based on the go-ipset
    61  // external package.
    62  func (i *goIpsetProvider) NewIpset(name string, ipsetType string, p *ipset.Params) (Ipset, error) {
    63  
    64  	// Check if hashtype is a type of hash
    65  	if strings.HasPrefix(ipsetType, "hash:") {
    66  		return ipset.New(name, ipsetType, p)
    67  	}
    68  
    69  	if err := ipsetCreateBitmapPort(name); err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	return &ipset.IPSet{Name: name}, nil
    74  }
    75  
    76  // GetIpset gets the ipset object from the name.
    77  func (i *goIpsetProvider) GetIpset(name string) Ipset {
    78  	return &ipset.IPSet{
    79  		Name: name,
    80  	}
    81  }
    82  
    83  // DestroyAll destroys all the ipsets with the given prefix
    84  func (i *goIpsetProvider) DestroyAll(prefix string) error {
    85  	return ipset.DestroyAll(prefix)
    86  }
    87  
    88  func (i *goIpsetProvider) ListIPSets() ([]string, error) {
    89  
    90  	out, err := exec.Command(ipsetBinPath, "-L", "-name").CombinedOutput()
    91  	if err != nil {
    92  		return nil, fmt.Errorf("unable to list ipsets:%s", err)
    93  	}
    94  
    95  	return strings.Split(string(out), "\n"), nil
    96  }
    97  
    98  func newIpset(name string, ipsetType string, p *ipset.Params) (Ipset, error) {
    99  	return instance.NewIpset(name, ipsetType, p)
   100  }
   101  
   102  func getIpset(name string) Ipset {
   103  	return instance.GetIpset(name)
   104  }
   105  
   106  func destroyAll(prefix string) error {
   107  	return instance.DestroyAll(prefix)
   108  }
   109  
   110  func listIPSets() ([]string, error) {
   111  	return instance.ListIPSets()
   112  }
   113  
   114  //SetIpsetTestInstance sets a test instance of ipsetprovider
   115  func SetIpsetTestInstance(ipsetprovider IpsetProvider) {
   116  	instance = ipsetprovider
   117  }
   118  
   119  //SetIPsetPath sets the path for aporeto-ipset
   120  func SetIPsetPath() {
   121  	ipsetBinPath, _ = exec.LookPath(constants.IpsetBinaryName) // nolint: errcheck
   122  	// tell the go-ipset package which ipset binary to use
   123  	ipset.Init(ipsetBinPath) // nolint: errcheck
   124  }