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

     1  // +build linux darwin
     2  
     3  package provider
     4  
     5  import (
     6  	"fmt"
     7  	"os/exec"
     8  	"strings"
     9  
    10  	"github.com/aporeto-inc/go-ipset/ipset"
    11  	"go.uber.org/zap"
    12  )
    13  
    14  // IpsetProvider returns a fabric for Ipset.
    15  type IpsetProvider interface {
    16  	NewIpset(name string, ipsetType string, p *ipset.Params) (Ipset, error)
    17  	GetIpset(name string) Ipset
    18  	DestroyAll(prefix string) error
    19  	ListIPSets() ([]string, error)
    20  }
    21  
    22  // Ipset is an abstraction of all the methods an implementation of userspace
    23  // ipsets need to provide.
    24  type Ipset interface {
    25  	Add(entry string, timeout int) error
    26  	AddOption(entry string, option string, timeout int) error
    27  	Del(entry string) error
    28  	Destroy() error
    29  	Flush() error
    30  	Test(entry string) (bool, error)
    31  }
    32  
    33  type goIpsetProvider struct{}
    34  
    35  func ipsetCreateBitmapPort(setname string) error {
    36  	//Bitmap type is not supported by the ipset library
    37  	path, _ := exec.LookPath("ipset")
    38  	out, err := exec.Command(path, "create", setname, "bitmap:port", "range", "0-65535", "timeout", "0").CombinedOutput()
    39  	if err != nil {
    40  		if strings.Contains(string(out), "set with the same name already exists") {
    41  			zap.L().Warn("Set already exists - cleaning up", zap.String("set name", setname))
    42  			// Clean up the existing set
    43  			if _, cerr := exec.Command(path, "-F", setname).CombinedOutput(); cerr != nil {
    44  				return fmt.Errorf("Failed to clean up existing ipset: %s", err)
    45  			}
    46  			return nil
    47  		}
    48  		zap.L().Error("Unable to create set", zap.String("set name", setname), zap.String("ipset-output", string(out)))
    49  	}
    50  	return err
    51  }
    52  
    53  // NewIpset returns an IpsetProvider interface based on the go-ipset
    54  // external package.
    55  func (i *goIpsetProvider) NewIpset(name string, ipsetType string, p *ipset.Params) (Ipset, error) {
    56  	// Check if hashtype is a type of hash
    57  	if strings.HasPrefix(ipsetType, "hash:") {
    58  		return ipset.New(name, ipsetType, p)
    59  	}
    60  
    61  	if err := ipsetCreateBitmapPort(name); err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	return &ipset.IPSet{Name: name}, nil
    66  }
    67  
    68  // GetIpset gets the ipset object from the name.
    69  func (i *goIpsetProvider) GetIpset(name string) Ipset {
    70  	return &ipset.IPSet{
    71  		Name: name,
    72  	}
    73  }
    74  
    75  // DestroyAll destroys all the ipsets - it will fail if there are existing references
    76  func (i *goIpsetProvider) DestroyAll(prefix string) error {
    77  
    78  	return ipset.DestroyAll()
    79  }
    80  
    81  func (i *goIpsetProvider) ListIPSets() ([]string, error) {
    82  
    83  	path, err := exec.LookPath("ipset")
    84  	if err != nil {
    85  		return nil, fmt.Errorf("ipset command not found: %s", err)
    86  	}
    87  
    88  	out, err := exec.Command(path, "-L", "-name").CombinedOutput()
    89  	if err != nil {
    90  		return nil, fmt.Errorf("unable to list ipsets:%s", err)
    91  	}
    92  
    93  	return strings.Split(string(out), "\n"), nil
    94  }
    95  
    96  // NewGoIPsetProvider Return a Go IPSet Provider
    97  func NewGoIPsetProvider() IpsetProvider {
    98  	return &goIpsetProvider{}
    99  }