tailscale/util/linuxfw/fake.go
Irbe Krumina 5fb721d4ad
util/linuxfw,wgengine/router: skip IPv6 firewall configuration in partial iptables mode (#11546)
We have hosts that support IPv6, but not IPv6 firewall configuration
in iptables mode.
We also have hosts that have some support for IPv6 firewall
configuration in iptables mode, but do not have iptables filter table.
We should:
- configure ip rules for all hosts that support IPv6
- only configure firewall rules in iptables mode if the host
has iptables filter table.

Updates tailscale/tailscale#11540

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
2024-03-29 05:23:03 +00:00

127 lines
2.7 KiB
Go

// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
//go:build linux
package linuxfw
import (
"errors"
"fmt"
"strings"
)
type fakeIPTables struct {
n map[string][]string
}
type fakeRule struct {
table, chain string
args []string
}
func newFakeIPTables() *fakeIPTables {
return &fakeIPTables{
n: map[string][]string{
"filter/INPUT": nil,
"filter/OUTPUT": nil,
"filter/FORWARD": nil,
"nat/PREROUTING": nil,
"nat/OUTPUT": nil,
"nat/POSTROUTING": nil,
"mangle/FORWARD": nil,
},
}
}
func (n *fakeIPTables) Insert(table, chain string, pos int, args ...string) error {
k := table + "/" + chain
if rules, ok := n.n[k]; ok {
if pos > len(rules)+1 {
return fmt.Errorf("bad position %d in %s", pos, k)
}
rules = append(rules, "")
copy(rules[pos:], rules[pos-1:])
rules[pos-1] = strings.Join(args, " ")
n.n[k] = rules
} else {
return fmt.Errorf("unknown table/chain %s", k)
}
return nil
}
func (n *fakeIPTables) Append(table, chain string, args ...string) error {
k := table + "/" + chain
return n.Insert(table, chain, len(n.n[k])+1, args...)
}
func (n *fakeIPTables) Exists(table, chain string, args ...string) (bool, error) {
k := table + "/" + chain
if rules, ok := n.n[k]; ok {
for _, rule := range rules {
if rule == strings.Join(args, " ") {
return true, nil
}
}
return false, nil
} else {
return false, fmt.Errorf("unknown table/chain %s", k)
}
}
func (n *fakeIPTables) Delete(table, chain string, args ...string) error {
k := table + "/" + chain
if rules, ok := n.n[k]; ok {
for i, rule := range rules {
if rule == strings.Join(args, " ") {
rules = append(rules[:i], rules[i+1:]...)
n.n[k] = rules
return nil
}
}
return fmt.Errorf("delete of unknown rule %q from %s", strings.Join(args, " "), k)
} else {
return fmt.Errorf("unknown table/chain %s", k)
}
}
func (n *fakeIPTables) ClearChain(table, chain string) error {
k := table + "/" + chain
if _, ok := n.n[k]; ok {
n.n[k] = nil
return nil
} else {
return errors.New("exitcode:1")
}
}
func (n *fakeIPTables) NewChain(table, chain string) error {
k := table + "/" + chain
if _, ok := n.n[k]; ok {
return fmt.Errorf("table/chain %s already exists", k)
}
n.n[k] = nil
return nil
}
func (n *fakeIPTables) DeleteChain(table, chain string) error {
k := table + "/" + chain
if rules, ok := n.n[k]; ok {
if len(rules) != 0 {
return fmt.Errorf("table/chain %s is not empty", k)
}
delete(n.n, k)
return nil
} else {
return fmt.Errorf("unknown table/chain %s", k)
}
}
func NewFakeIPTablesRunner() *iptablesRunner {
ipt4 := newFakeIPTables()
ipt6 := newFakeIPTables()
iptr := &iptablesRunner{ipt4, ipt6, true, true, true}
return iptr
}