mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-09 00:11:28 +02:00
Remove partial userspace firewall mode and open foreign chains via a table-less allower
This commit is contained in:
93
client/firewall/iptables/interface_allower_linux.go
Normal file
93
client/firewall/iptables/interface_allower_linux.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package iptables
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/coreos/go-iptables/iptables"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
nberrors "github.com/netbirdio/netbird/client/errors"
|
||||
)
|
||||
|
||||
// InterfaceAllower opens the NetBird interface on the iptables filter INPUT
|
||||
// chain so the host firewall doesn't drop traffic the userspace firewall
|
||||
// handles. It is the fallback used when nftables is unavailable (an
|
||||
// iptables-legacy host).
|
||||
//
|
||||
// It opens INPUT only: the userspace router never forwards in the kernel.
|
||||
// firewalld trust is handled by the uspfilter manager, not here.
|
||||
type InterfaceAllower struct {
|
||||
ifaceName string
|
||||
ipt4 *iptables.IPTables
|
||||
// ipt6 is nil when the interface has no IPv6 overlay address.
|
||||
ipt6 *iptables.IPTables
|
||||
}
|
||||
|
||||
// NewInterfaceAllower builds an iptables allower for the interface. It returns
|
||||
// an error when iptables is unavailable, so the caller can fall back to
|
||||
// firewalld trust.
|
||||
func NewInterfaceAllower(wgIface iFaceMapper) (*InterfaceAllower, error) {
|
||||
ipt4, err := iptables.NewWithProtocol(iptables.ProtocolIPv4)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("iptables not available: %w", err)
|
||||
}
|
||||
if _, err := ipt4.ListChains(tableFilter); err != nil {
|
||||
return nil, fmt.Errorf("iptables filter table not available: %w", err)
|
||||
}
|
||||
|
||||
a := &InterfaceAllower{ifaceName: wgIface.Name(), ipt4: ipt4}
|
||||
|
||||
// Missing v6 must not break the v4 path: open v4 only and continue.
|
||||
if wgIface.Address().HasIPv6() {
|
||||
ipt6, err := iptables.NewWithProtocol(iptables.ProtocolIPv6)
|
||||
if err != nil {
|
||||
log.Warnf("ip6tables not available, opening interface on v4 only: %v", err)
|
||||
} else if _, err := ipt6.ListChains(tableFilter); err != nil {
|
||||
log.Warnf("ip6tables filter table not available, opening interface on v4 only: %v", err)
|
||||
} else {
|
||||
a.ipt6 = ipt6
|
||||
}
|
||||
}
|
||||
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// Apply inserts the interface accept rule on the filter INPUT chain. It removes
|
||||
// any stale rule first so an unclean exit (e.g. SIGKILL, where Close never ran)
|
||||
// is recovered deterministically rather than accumulating duplicates.
|
||||
func (a *InterfaceAllower) Apply() error {
|
||||
var merr *multierror.Error
|
||||
for _, ipt := range a.clients() {
|
||||
if err := ipt.DeleteIfExists(tableFilter, chainInput, a.inputRule()...); err != nil {
|
||||
merr = multierror.Append(merr, fmt.Errorf("clean stale interface accept rule: %w", err))
|
||||
}
|
||||
if err := ipt.Insert(tableFilter, chainInput, 1, a.inputRule()...); err != nil {
|
||||
merr = multierror.Append(merr, fmt.Errorf("add interface accept rule: %w", err))
|
||||
}
|
||||
}
|
||||
return nberrors.FormatErrorOrNil(merr)
|
||||
}
|
||||
|
||||
// Close removes the interface accept rule.
|
||||
func (a *InterfaceAllower) Close() error {
|
||||
var merr *multierror.Error
|
||||
for _, ipt := range a.clients() {
|
||||
if err := ipt.DeleteIfExists(tableFilter, chainInput, a.inputRule()...); err != nil {
|
||||
merr = multierror.Append(merr, fmt.Errorf("remove interface accept rule: %w", err))
|
||||
}
|
||||
}
|
||||
return nberrors.FormatErrorOrNil(merr)
|
||||
}
|
||||
|
||||
func (a *InterfaceAllower) inputRule() []string {
|
||||
return []string{"-i", a.ifaceName, "-j", "ACCEPT"}
|
||||
}
|
||||
|
||||
func (a *InterfaceAllower) clients() []*iptables.IPTables {
|
||||
clients := []*iptables.IPTables{a.ipt4}
|
||||
if a.ipt6 != nil {
|
||||
clients = append(clients, a.ipt6)
|
||||
}
|
||||
return clients
|
||||
}
|
||||
Reference in New Issue
Block a user