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

     1  package ipsetmanager
     2  
     3  import (
     4  	"encoding/base64"
     5  	"io"
     6  	"net"
     7  	"sync"
     8  
     9  	ipsetpackage "github.com/aporeto-inc/go-ipset/ipset"
    10  	"github.com/spaolacci/murmur3"
    11  	provider "go.aporeto.io/trireme-lib/controller/pkg/aclprovider"
    12  
    13  	"go.aporeto.io/trireme-lib/policy"
    14  	"go.uber.org/zap"
    15  )
    16  
    17  const (
    18  	//IPv6DefaultIP is the default ip of v6
    19  	IPv6DefaultIP = "::/0"
    20  	//IPv4DefaultIP is the  default ip for v4
    21  	IPv4DefaultIP = "0.0.0.0/0"
    22  	//IPsetV4 version for ipv4
    23  	IPsetV4 = iota
    24  	//IPsetV6 version for ipv6
    25  	IPsetV6
    26  )
    27  
    28  //ACLManager interface is used by supervisor. This interface provides the supervisor to
    29  //create ipsets corresponding to service ID.
    30  type ACLManager interface {
    31  	AddToIPset(set provider.Ipset, data string) error
    32  	DelFromIPset(set provider.Ipset, data string) error
    33  
    34  	RegisterExternalNets(contextID string, extnets policy.IPRuleList) error
    35  	DestroyUnusedIPsets()
    36  	RemoveExternalNets(contextID string)
    37  	GetIPsets(extnets policy.IPRuleList, ipver int) []string
    38  	UpdateIPsets([]string, string)
    39  }
    40  
    41  type ipsetInfo struct {
    42  	contextIDs map[string]bool
    43  	name       string
    44  	addresses  map[string]bool
    45  }
    46  
    47  type handler struct {
    48  	serviceIDtoIPset      map[string]*ipsetInfo
    49  	contextIDtoServiceIDs map[string]map[string]bool
    50  	ipset                 provider.IpsetProvider
    51  	ipsetPrefix           string
    52  	ipFilter              func(net.IP) bool
    53  	ipsetParams           *ipsetpackage.Params
    54  	toDestroy             []string
    55  }
    56  
    57  type managerType struct {
    58  	ipv4Handler *handler
    59  	ipv6Handler *handler
    60  	sync.RWMutex
    61  }
    62  
    63  const (
    64  	ipv4String = "v4-"
    65  	ipv6String = "v6-"
    66  )
    67  
    68  //CreateIPsetManager creates the handle with Interface ACLManager
    69  func CreateIPsetManager(ipsetv4 provider.IpsetProvider, ipsetv6 provider.IpsetProvider) ACLManager {
    70  	return &managerType{
    71  		ipv4Handler: &handler{
    72  			serviceIDtoIPset:      map[string]*ipsetInfo{},
    73  			contextIDtoServiceIDs: map[string]map[string]bool{},
    74  			ipset:                 ipsetv4,
    75  			ipsetPrefix:           ipv4String,
    76  			ipFilter: func(ip net.IP) bool {
    77  				return (ip.To4() != nil)
    78  			},
    79  			ipsetParams: &ipsetpackage.Params{},
    80  		},
    81  		ipv6Handler: &handler{
    82  			serviceIDtoIPset:      map[string]*ipsetInfo{},
    83  			contextIDtoServiceIDs: map[string]map[string]bool{},
    84  			ipset:                 ipsetv6,
    85  			ipsetPrefix:           ipv6String,
    86  			ipFilter: func(ip net.IP) bool {
    87  				return (ip.To4() == nil)
    88  			},
    89  			ipsetParams: &ipsetpackage.Params{HashFamily: "inet6"},
    90  		},
    91  	}
    92  
    93  }
    94  
    95  func hashServiceID(serviceID string) string {
    96  	hash := murmur3.New64()
    97  	if _, err := io.WriteString(hash, serviceID); err != nil {
    98  		return ""
    99  	}
   100  
   101  	return base64.URLEncoding.EncodeToString(hash.Sum(nil))
   102  }
   103  
   104  // AddToIPset is called with the ipset provider and the ip address to be added
   105  func (m *managerType) AddToIPset(set provider.Ipset, data string) error {
   106  
   107  	// ipset can not program this rule
   108  	if data == IPv4DefaultIP {
   109  		if err := m.AddToIPset(set, "0.0.0.0/1"); err != nil {
   110  			return err
   111  		}
   112  
   113  		return m.AddToIPset(set, "128.0.0.0/1")
   114  	}
   115  
   116  	// ipset can not program this rule
   117  	if data == IPv6DefaultIP {
   118  		if err := m.AddToIPset(set, "::/1"); err != nil {
   119  			return err
   120  		}
   121  
   122  		return m.AddToIPset(set, "8000::/1")
   123  	}
   124  
   125  	return set.Add(data, 0)
   126  }
   127  
   128  // DelFromIPset is called with the ipset set provider and the ip to be removed from ipset
   129  func (m *managerType) DelFromIPset(set provider.Ipset, data string) error {
   130  
   131  	if data == IPv4DefaultIP {
   132  		if err := m.DelFromIPset(set, "0.0.0.0/1"); err != nil {
   133  			return err
   134  		}
   135  
   136  		return m.DelFromIPset(set, "128.0.0.0/1")
   137  	}
   138  
   139  	if data == IPv6DefaultIP {
   140  		if err := m.DelFromIPset(set, "::/1"); err != nil {
   141  			return err
   142  		}
   143  
   144  		return m.DelFromIPset(set, "8000::/1")
   145  	}
   146  
   147  	return set.Del(data)
   148  }
   149  
   150  func (m *managerType) synchronizeIPsinIpset(ipHandler *handler, ipsetInfo *ipsetInfo, addresses []string) {
   151  	newips := map[string]bool{}
   152  	ipsetHandler := ipHandler.ipset.GetIpset(ipsetInfo.name)
   153  
   154  	for _, address := range addresses {
   155  		netIP := net.ParseIP(address)
   156  		if netIP == nil {
   157  			netIP, _, _ = net.ParseCIDR(address)
   158  		}
   159  
   160  		if !ipHandler.ipFilter(netIP) {
   161  			continue
   162  		}
   163  
   164  		newips[address] = true
   165  
   166  		if _, ok := ipsetInfo.addresses[address]; !ok {
   167  			if err := m.AddToIPset(ipsetHandler, address); err != nil {
   168  				zap.L().Error("Error adding IPs to ipset", zap.String("ipset", ipsetInfo.name), zap.String("address", address))
   169  			}
   170  		}
   171  		delete(ipsetInfo.addresses, address)
   172  	}
   173  
   174  	// Remove the old entries
   175  	for address, val := range ipsetInfo.addresses {
   176  		if val {
   177  			if err := m.DelFromIPset(ipsetHandler, address); err != nil {
   178  				zap.L().Error("Error removing IPs from ipset", zap.String("ipset", ipsetInfo.name), zap.String("address", address))
   179  			}
   180  		}
   181  	}
   182  
   183  	ipsetInfo.addresses = newips
   184  }
   185  
   186  func createIPset(ipHandler *handler, serviceID string) (*ipsetInfo, error) {
   187  	ipsetName := "TRI-" + ipHandler.ipsetPrefix + "ext-" + hashServiceID(serviceID)
   188  	_, err := ipHandler.ipset.NewIpset(ipsetName, "hash:net", ipHandler.ipsetParams)
   189  	if err != nil {
   190  		return nil, err
   191  	}
   192  
   193  	ipset := &ipsetInfo{contextIDs: map[string]bool{}, name: ipsetName, addresses: map[string]bool{}}
   194  	ipHandler.serviceIDtoIPset[serviceID] = ipset
   195  
   196  	return ipset, nil
   197  }
   198  
   199  func deleteServiceID(ipHandler *handler, serviceID string) {
   200  	ipsetInfo := ipHandler.serviceIDtoIPset[serviceID]
   201  	ipHandler.toDestroy = append(ipHandler.toDestroy, ipsetInfo.name)
   202  	delete(ipHandler.serviceIDtoIPset, serviceID)
   203  }
   204  
   205  func reduceReferenceFromServiceID(ipHandler *handler, contextID string, serviceID string) {
   206  	var ipset *ipsetInfo
   207  
   208  	if ipset = ipHandler.serviceIDtoIPset[serviceID]; ipset == nil {
   209  		zap.L().Error("Could not find ipset corresponding to serviceID", zap.String("serviceID", serviceID))
   210  		return
   211  	}
   212  
   213  	delete(ipset.contextIDs, contextID)
   214  
   215  	// there are no references from any pu. safe to destroy now
   216  	if len(ipset.contextIDs) == 0 {
   217  		deleteServiceID(ipHandler, serviceID)
   218  	}
   219  }
   220  
   221  // RegisterExternalNets registers the contextID and the corresponding serviceIDs
   222  func (m *managerType) RegisterExternalNets(contextID string, extnets policy.IPRuleList) error {
   223  	m.Lock()
   224  	defer m.Unlock()
   225  
   226  	processExtnets := func(ipHandler *handler) error {
   227  		for _, extnet := range extnets {
   228  			var ipset *ipsetInfo
   229  
   230  			serviceID := extnet.Policy.ServiceID
   231  			if ipset = ipHandler.serviceIDtoIPset[serviceID]; ipset == nil {
   232  				var err error
   233  				if ipset, err = createIPset(ipHandler, serviceID); err != nil {
   234  					return err
   235  				}
   236  			}
   237  
   238  			m.synchronizeIPsinIpset(ipHandler, ipset, extnet.Addresses)
   239  			// have a backreference from serviceID to contextID
   240  			ipset.contextIDs[contextID] = true
   241  		}
   242  
   243  		return nil
   244  	}
   245  
   246  	processOlderExtnets := func(ipHandler *handler) {
   247  		newExtnets := map[string]bool{}
   248  
   249  		for _, extnet := range extnets {
   250  
   251  			serviceID := extnet.Policy.ServiceID
   252  			newExtnets[serviceID] = true
   253  			m, ok := ipHandler.contextIDtoServiceIDs[contextID]
   254  
   255  			if ok && m[serviceID] {
   256  				delete(m, serviceID)
   257  			}
   258  		}
   259  
   260  		for serviceID := range ipHandler.contextIDtoServiceIDs[contextID] {
   261  			reduceReferenceFromServiceID(ipHandler, contextID, serviceID)
   262  		}
   263  
   264  		ipHandler.contextIDtoServiceIDs[contextID] = newExtnets
   265  	}
   266  
   267  	if err := processExtnets(m.ipv4Handler); err != nil {
   268  		return err
   269  	}
   270  
   271  	if err := processExtnets(m.ipv6Handler); err != nil {
   272  		return err
   273  	}
   274  
   275  	processOlderExtnets(m.ipv4Handler)
   276  	processOlderExtnets(m.ipv6Handler)
   277  
   278  	return nil
   279  }
   280  
   281  // DestroyUnusedIPsets destroys the unused ipsets.
   282  func (m *managerType) DestroyUnusedIPsets() {
   283  	m.Lock()
   284  	defer m.Unlock()
   285  
   286  	destroy := func(ipHandler *handler) {
   287  		for _, ipsetName := range ipHandler.toDestroy {
   288  			ipsetHandler := ipHandler.ipset.GetIpset(ipsetName)
   289  			if err := ipsetHandler.Destroy(); err != nil {
   290  				zap.L().Warn("Failed to destroy ipset", zap.String("ipset", ipsetName), zap.Error(err))
   291  			}
   292  		}
   293  
   294  		ipHandler.toDestroy = nil
   295  	}
   296  
   297  	destroy(m.ipv4Handler)
   298  	destroy(m.ipv6Handler)
   299  }
   300  
   301  // RemoveExternalNets is called when the contextID is being unsupervised such that all the external nets can be deleted.
   302  func (m *managerType) RemoveExternalNets(contextID string) {
   303  	m.Lock()
   304  
   305  	process := func(ipHandler *handler) {
   306  		m, ok := ipHandler.contextIDtoServiceIDs[contextID]
   307  		if ok {
   308  			for serviceID := range m {
   309  				reduceReferenceFromServiceID(ipHandler, contextID, serviceID)
   310  			}
   311  		}
   312  
   313  		delete(ipHandler.contextIDtoServiceIDs, contextID)
   314  	}
   315  
   316  	process(m.ipv4Handler)
   317  	process(m.ipv6Handler)
   318  
   319  	m.Unlock()
   320  	m.DestroyUnusedIPsets()
   321  }
   322  
   323  // GetIPsets returns the ipset names corresponding to the serviceIDs.
   324  func (m *managerType) GetIPsets(extnets policy.IPRuleList, ipver int) []string {
   325  	m.Lock()
   326  	defer m.Unlock()
   327  
   328  	var ipHandler *handler
   329  
   330  	if ipver == IPsetV4 {
   331  		ipHandler = m.ipv4Handler
   332  	} else {
   333  		ipHandler = m.ipv6Handler
   334  	}
   335  
   336  	var ipsets []string
   337  
   338  	for _, extnet := range extnets {
   339  		serviceID := extnet.Policy.ServiceID
   340  
   341  		ipsetInfo, ok := ipHandler.serviceIDtoIPset[serviceID]
   342  		if ok {
   343  			ipsets = append(ipsets, ipsetInfo.name)
   344  		}
   345  	}
   346  
   347  	return ipsets
   348  }
   349  
   350  // UpdateIPsets updates the ip addresses in the ipsets corresponding to the serviceID
   351  func (m *managerType) UpdateIPsets(addresses []string, serviceID string) {
   352  	m.Lock()
   353  	defer m.Unlock()
   354  
   355  	process := func(ipHandler *handler) {
   356  		for _, address := range addresses {
   357  			netIP := net.ParseIP(address)
   358  			if netIP == nil {
   359  				netIP, _, _ = net.ParseCIDR(address)
   360  			}
   361  
   362  			if !ipHandler.ipFilter(netIP) {
   363  				continue
   364  			}
   365  
   366  			if ipset := ipHandler.serviceIDtoIPset[serviceID]; ipset != nil {
   367  				ipsetHandler := ipHandler.ipset.GetIpset(ipset.name)
   368  				if err := m.AddToIPset(ipsetHandler, address); err != nil {
   369  					zap.L().Error("Error adding IPs to ipset", zap.String("ipset", ipset.name), zap.String("address", address))
   370  				}
   371  				ipset.addresses[address] = true
   372  			}
   373  		}
   374  	}
   375  
   376  	process(m.ipv4Handler)
   377  	process(m.ipv6Handler)
   378  }