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 }