11package iptables
22
33import (
4+ "errors"
45 "fmt"
56 "net"
67 "slices"
78
89 "github.com/coreos/go-iptables/iptables"
910 "github.com/google/uuid"
10- "github.com/nadoo /ipset"
11+ ipset "github.com/lrh3321 /ipset-go "
1112 log "github.com/sirupsen/logrus"
1213
1314 firewall "github.com/netbirdio/netbird/client/firewall/manager"
@@ -40,19 +41,13 @@ type aclManager struct {
4041}
4142
4243func newAclManager (iptablesClient * iptables.IPTables , wgIface iFaceMapper ) (* aclManager , error ) {
43- m := & aclManager {
44+ return & aclManager {
4445 iptablesClient : iptablesClient ,
4546 wgIface : wgIface ,
4647 entries : make (map [string ][][]string ),
4748 optionalEntries : make (map [string ][]entry ),
4849 ipsetStore : newIpsetStore (),
49- }
50-
51- if err := ipset .Init (); err != nil {
52- return nil , fmt .Errorf ("init ipset: %w" , err )
53- }
54-
55- return m , nil
50+ }, nil
5651}
5752
5853func (m * aclManager ) init (stateManager * statemanager.Manager ) error {
@@ -98,8 +93,8 @@ func (m *aclManager) AddPeerFiltering(
9893 specs = append (specs , "-j" , actionToStr (action ))
9994 if ipsetName != "" {
10095 if ipList , ipsetExists := m .ipsetStore .ipset (ipsetName ); ipsetExists {
101- if err := ipset . Add (ipsetName , ip . String () ); err != nil {
102- return nil , fmt .Errorf ("failed to add IP to ipset: %w" , err )
96+ if err := m . addToIPSet (ipsetName , ip ); err != nil {
97+ return nil , fmt .Errorf ("add IP to ipset: %w" , err )
10398 }
10499 // if ruleset already exists it means we already have the firewall rule
105100 // so we need to update IPs in the ruleset and return new fw.Rule object for ACL manager.
@@ -113,14 +108,18 @@ func (m *aclManager) AddPeerFiltering(
113108 }}, nil
114109 }
115110
116- if err := ipset .Flush (ipsetName ); err != nil {
117- log .Errorf ("flush ipset %s before use it: %s" , ipsetName , err )
111+ if err := m .flushIPSet (ipsetName ); err != nil {
112+ if errors .Is (err , ipset .ErrSetNotExist ) {
113+ log .Debugf ("flush ipset %s before use: %v" , ipsetName , err )
114+ } else {
115+ log .Errorf ("flush ipset %s before use: %v" , ipsetName , err )
116+ }
118117 }
119- if err := ipset . Create (ipsetName ); err != nil {
120- return nil , fmt .Errorf ("failed to create ipset: %w" , err )
118+ if err := m . createIPSet (ipsetName ); err != nil {
119+ return nil , fmt .Errorf ("create ipset: %w" , err )
121120 }
122- if err := ipset . Add (ipsetName , ip . String () ); err != nil {
123- return nil , fmt .Errorf ("failed to add IP to ipset: %w" , err )
121+ if err := m . addToIPSet (ipsetName , ip ); err != nil {
122+ return nil , fmt .Errorf ("add IP to ipset: %w" , err )
124123 }
125124
126125 ipList := newIpList (ip .String ())
@@ -172,11 +171,16 @@ func (m *aclManager) DeletePeerRule(rule firewall.Rule) error {
172171 return fmt .Errorf ("invalid rule type" )
173172 }
174173
174+ shouldDestroyIpset := false
175175 if ipsetList , ok := m .ipsetStore .ipset (r .ipsetName ); ok {
176176 // delete IP from ruleset IPs list and ipset
177177 if _ , ok := ipsetList .ips [r .ip ]; ok {
178- if err := ipset .Del (r .ipsetName , r .ip ); err != nil {
179- return fmt .Errorf ("failed to delete ip from ipset: %w" , err )
178+ ip := net .ParseIP (r .ip )
179+ if ip == nil {
180+ return fmt .Errorf ("parse IP %s" , r .ip )
181+ }
182+ if err := m .delFromIPSet (r .ipsetName , ip ); err != nil {
183+ return fmt .Errorf ("delete ip from ipset: %w" , err )
180184 }
181185 delete (ipsetList .ips , r .ip )
182186 }
@@ -190,10 +194,7 @@ func (m *aclManager) DeletePeerRule(rule firewall.Rule) error {
190194 // we delete last IP from the set, that means we need to delete
191195 // set itself and associated firewall rule too
192196 m .ipsetStore .deleteIpset (r .ipsetName )
193-
194- if err := ipset .Destroy (r .ipsetName ); err != nil {
195- log .Errorf ("delete empty ipset: %v" , err )
196- }
197+ shouldDestroyIpset = true
197198 }
198199
199200 if err := m .iptablesClient .Delete (tableName , r .chain , r .specs ... ); err != nil {
@@ -206,6 +207,16 @@ func (m *aclManager) DeletePeerRule(rule firewall.Rule) error {
206207 }
207208 }
208209
210+ if shouldDestroyIpset {
211+ if err := m .destroyIPSet (r .ipsetName ); err != nil {
212+ if errors .Is (err , ipset .ErrBusy ) || errors .Is (err , ipset .ErrSetNotExist ) {
213+ log .Debugf ("destroy empty ipset: %v" , err )
214+ } else {
215+ log .Errorf ("destroy empty ipset: %v" , err )
216+ }
217+ }
218+ }
219+
209220 m .updateState ()
210221
211222 return nil
@@ -264,11 +275,19 @@ func (m *aclManager) cleanChains() error {
264275 }
265276
266277 for _ , ipsetName := range m .ipsetStore .ipsetNames () {
267- if err := ipset .Flush (ipsetName ); err != nil {
268- log .Errorf ("flush ipset %q during reset: %v" , ipsetName , err )
278+ if err := m .flushIPSet (ipsetName ); err != nil {
279+ if errors .Is (err , ipset .ErrSetNotExist ) {
280+ log .Debugf ("flush ipset %q during reset: %v" , ipsetName , err )
281+ } else {
282+ log .Errorf ("flush ipset %q during reset: %v" , ipsetName , err )
283+ }
269284 }
270- if err := ipset .Destroy (ipsetName ); err != nil {
271- log .Errorf ("delete ipset %q during reset: %v" , ipsetName , err )
285+ if err := m .destroyIPSet (ipsetName ); err != nil {
286+ if errors .Is (err , ipset .ErrBusy ) || errors .Is (err , ipset .ErrSetNotExist ) {
287+ log .Debugf ("destroy ipset %q during reset: %v" , ipsetName , err )
288+ } else {
289+ log .Errorf ("destroy ipset %q during reset: %v" , ipsetName , err )
290+ }
272291 }
273292 m .ipsetStore .deleteIpset (ipsetName )
274293 }
@@ -368,8 +387,8 @@ func (m *aclManager) updateState() {
368387// filterRuleSpecs returns the specs of a filtering rule
369388func filterRuleSpecs (ip net.IP , protocol string , sPort , dPort * firewall.Port , action firewall.Action , ipsetName string ) (specs []string ) {
370389 matchByIP := true
371- // don't use IP matching if IP is ip 0.0.0.0
372- if ip .String () == "0.0.0.0" {
390+ // don't use IP matching if IP is 0.0.0.0
391+ if ip .IsUnspecified () {
373392 matchByIP = false
374393 }
375394
@@ -416,3 +435,61 @@ func transformIPsetName(ipsetName string, sPort, dPort *firewall.Port, action fi
416435 return ipsetName + actionSuffix
417436 }
418437}
438+
439+ func (m * aclManager ) createIPSet (name string ) error {
440+ opts := ipset.CreateOptions {
441+ Replace : true ,
442+ }
443+
444+ if err := ipset .Create (name , ipset .TypeHashNet , opts ); err != nil {
445+ return fmt .Errorf ("create ipset %s: %w" , name , err )
446+ }
447+
448+ log .Debugf ("created ipset %s with type hash:net" , name )
449+ return nil
450+ }
451+
452+ func (m * aclManager ) addToIPSet (name string , ip net.IP ) error {
453+ cidr := uint8 (32 )
454+ if ip .To4 () == nil {
455+ cidr = 128
456+ }
457+
458+ entry := & ipset.Entry {
459+ IP : ip ,
460+ CIDR : cidr ,
461+ Replace : true ,
462+ }
463+
464+ if err := ipset .Add (name , entry ); err != nil {
465+ return fmt .Errorf ("add IP to ipset %s: %w" , name , err )
466+ }
467+
468+ return nil
469+ }
470+
471+ func (m * aclManager ) delFromIPSet (name string , ip net.IP ) error {
472+ cidr := uint8 (32 )
473+ if ip .To4 () == nil {
474+ cidr = 128
475+ }
476+
477+ entry := & ipset.Entry {
478+ IP : ip ,
479+ CIDR : cidr ,
480+ }
481+
482+ if err := ipset .Del (name , entry ); err != nil {
483+ return fmt .Errorf ("delete IP from ipset %s: %w" , name , err )
484+ }
485+
486+ return nil
487+ }
488+
489+ func (m * aclManager ) flushIPSet (name string ) error {
490+ return ipset .Flush (name )
491+ }
492+
493+ func (m * aclManager ) destroyIPSet (name string ) error {
494+ return ipset .Destroy (name )
495+ }
0 commit comments