diff --git a/client/firewall/iptables/manager.go b/client/firewall/iptables/manager.go deleted file mode 100644 index 72cf6d1b2..000000000 --- a/client/firewall/iptables/manager.go +++ /dev/null @@ -1,159 +0,0 @@ -package iptables - -import ( - "fmt" - "net" - "strconv" - "sync" - - "github.com/coreos/go-iptables/iptables" - - fw "github.com/netbirdio/netbird/client/firewall" -) - -const ( - // ChainFilterName is the name of the chain that is used for filtering by the Netbird client - ChainFilterName = "NETBIRD-ACL" -) - -// Manager of iptables firewall -type Manager struct { - mutex sync.Mutex - ruleCnt int - - ipv4Client *iptables.IPTables - ipv6Client *iptables.IPTables -} - -// Create iptables firewall manager -func Create() (*Manager, error) { - m := &Manager{} - - // init clients for booth ipv4 and ipv6 - ipv4Client, err := iptables.NewWithProtocol(iptables.ProtocolIPv4) - if err != nil { - return nil, fmt.Errorf("iptables is not installed in the system or not supported") - } - m.ipv4Client = ipv4Client - - ipv6Client, err := iptables.NewWithProtocol(iptables.ProtocolIPv6) - if err != nil { - return nil, fmt.Errorf("ip6tables is not installed in the system or not supported") - } - m.ipv6Client = ipv6Client - - if err := m.Reset(); err != nil { - return nil, fmt.Errorf("failed to reset firewall: %s", err) - } - - return m, nil -} - -// AddFiltering adds a filtering rule to the firewall -func (m *Manager) AddFiltering( - ip net.IP, - port *fw.Port, - direction fw.Direction, - action fw.Action, - comment string, -) (fw.Rule, error) { - m.mutex.Lock() - defer m.mutex.Unlock() - client := m.client(ip) - ok, err := client.ChainExists("filter", ChainFilterName) - if err != nil { - return nil, fmt.Errorf("failed to check if chain exists: %s", err) - } - if !ok { - if err := client.NewChain("filter", ChainFilterName); err != nil { - return nil, fmt.Errorf("failed to create chain: %s", err) - } - } - if port == nil || port.Values == nil || (port.IsRange && len(port.Values) != 2) { - return nil, fmt.Errorf("invalid port definition") - } - pv := strconv.Itoa(port.Values[0]) - if port.IsRange { - pv += ":" + strconv.Itoa(port.Values[1]) - } - specs := m.filterRuleSpecs("filter", ChainFilterName, ip, pv, direction, action, comment) - if err := client.AppendUnique("filter", ChainFilterName, specs...); err != nil { - return nil, err - } - m.ruleCnt++ - return &Rule{ruleNumber: m.ruleCnt, specs: specs, v6: ip.To4() == nil}, nil -} - -// DeleteRule deletes a rule from the firewall -func (m *Manager) DeleteRule(rule fw.Rule) error { - m.mutex.Lock() - defer m.mutex.Unlock() - r, ok := rule.(*Rule) - if !ok { - return fmt.Errorf("invalid rule type") - } - client := m.ipv4Client - if r.v6 { - client = m.ipv6Client - } - client.Delete("filter", ChainFilterName, r.specs...) - return nil -} - -// Reset firewall to the default state -func (m *Manager) Reset() error { - m.mutex.Lock() - defer m.mutex.Unlock() - if err := m.reset(m.ipv4Client, "filter", ChainFilterName); err != nil { - return fmt.Errorf("clean ipv4 firewall ACL chain: %w", err) - } - if err := m.reset(m.ipv6Client, "filter", ChainFilterName); err != nil { - return fmt.Errorf("clean ipv6 firewall ACL chain: %w", err) - } - return nil -} - -func (m *Manager) reset(client *iptables.IPTables, table, chain string) error { - ok, err := client.ChainExists(table, chain) - if err != nil { - return fmt.Errorf("failed to check if chain exists: %w", err) - } - if !ok { - return nil - } - if err := client.ClearChain(table, ChainFilterName); err != nil { - return fmt.Errorf("failed to clear chain: %w", err) - } - return client.DeleteChain(table, ChainFilterName) -} - -// filterRuleSpecs returns the specs of a filtering rule and its id -// -// id builded by hashing the table, chain and specs together -func (m *Manager) filterRuleSpecs( - table string, chain string, ip net.IP, port string, - direction fw.Direction, action fw.Action, comment string, -) (specs []string) { - if direction == fw.DirectionSrc { - specs = append(specs, "-s", ip.String()) - } - specs = append(specs, "-p", "tcp", "--dport", port) - specs = append(specs, "-j", m.action(action)) - return append(specs, "-m", "comment", "--comment", comment) -} - -// client returns corresponding iptables client for the given ip -func (m *Manager) client(ip net.IP) *iptables.IPTables { - if ip.To4() != nil { - return m.ipv4Client - } - return m.ipv6Client -} - -// action returns iptables action string for the given action -func (m *Manager) action(action fw.Action) string { - if action == fw.ActionAccept { - return "ACCEPT" - } - return "DROP" -} diff --git a/client/firewall/iptables/manager_linux.go b/client/firewall/iptables/manager_linux.go index e5aafd6d8..ba1d4340d 100644 --- a/client/firewall/iptables/manager_linux.go +++ b/client/firewall/iptables/manager_linux.go @@ -19,6 +19,7 @@ const ( // Manager of iptables firewall type Manager struct { +<<<<<<< HEAD mutex sync.Mutex ipv4Client *iptables.IPTables diff --git a/client/firewall/iptables/manager_test.go b/client/firewall/iptables/manager_test.go deleted file mode 100644 index ad87c8b3a..000000000 --- a/client/firewall/iptables/manager_test.go +++ /dev/null @@ -1,110 +0,0 @@ -package iptables - -import ( - "net" - "runtime" - "testing" - - "github.com/coreos/go-iptables/iptables" - fw "github.com/netbirdio/netbird/client/firewall" -) - -func TestNewManager(t *testing.T) { - if runtime.GOOS != "linux" { - t.Skip("iptables is only supported on linux") - } - - ipv4Client, err := iptables.NewWithProtocol(iptables.ProtocolIPv4) - if err != nil { - t.Fatal(err) - } - - manager, err := Create() - if err != nil { - t.Fatal(err) - } - - var rule1 fw.Rule - t.Run("add first rule", func(t *testing.T) { - ip := net.ParseIP("10.20.0.2") - port := &fw.Port{Proto: fw.PortProtocolTCP, Values: []int{8080}} - rule1, err = manager.AddFiltering(ip, port, fw.DirectionDst, fw.ActionAccept, "accept HTTP traffic") - if err != nil { - t.Errorf("failed to add rule: %v", err) - } - - checkRuleSpecs(t, ipv4Client, true, rule1.(*Rule).specs...) - }) - - var rule2 fw.Rule - t.Run("add second rule", func(t *testing.T) { - ip := net.ParseIP("10.20.0.3") - port := &fw.Port{ - Proto: fw.PortProtocolTCP, - Values: []int{8043: 8046}, - } - rule2, err = manager.AddFiltering( - ip, port, fw.DirectionDst, fw.ActionAccept, "accept HTTPS traffic from ports range") - if err != nil { - t.Errorf("failed to add rule: %v", err) - } - - checkRuleSpecs(t, ipv4Client, true, rule2.(*Rule).specs...) - }) - - t.Run("delete first rule", func(t *testing.T) { - if err := manager.DeleteRule(rule1); err != nil { - t.Errorf("failed to delete rule: %v", err) - } - - checkRuleSpecs(t, ipv4Client, false, rule1.(*Rule).specs...) - }) - - t.Run("delete second rule", func(t *testing.T) { - if err := manager.DeleteRule(rule2); err != nil { - t.Errorf("failed to delete rule: %v", err) - } - - checkRuleSpecs(t, ipv4Client, false, rule2.(*Rule).specs...) - }) - - t.Run("reset check", func(t *testing.T) { - // add second rule - ip := net.ParseIP("10.20.0.3") - port := &fw.Port{Proto: fw.PortProtocolUDP, Values: []int{5353}} - _, err = manager.AddFiltering(ip, port, fw.DirectionDst, fw.ActionAccept, "accept Fake DNS traffic") - if err != nil { - t.Errorf("failed to add rule: %v", err) - } - - if err := manager.Reset(); err != nil { - t.Errorf("failed to reset: %v", err) - } - - ok, err := ipv4Client.ChainExists("filter", ChainFilterName) - if err != nil { - t.Errorf("failed to drop chain: %v", err) - } - - if ok { - t.Errorf("chain '%v' still exists after Reset", ChainFilterName) - } - }) -} - -func checkRuleSpecs(t *testing.T, ipv4Client *iptables.IPTables, mustExists bool, rulespec ...string) { - exists, err := ipv4Client.Exists("filter", ChainFilterName, rulespec...) - if err != nil { - t.Errorf("failed to check rule: %v", err) - return - } - - if !exists && mustExists { - t.Errorf("rule '%v' does not exist", rulespec) - return - } - if exists && !mustExists { - t.Errorf("rule '%v' exist", rulespec) - return - } -}