1
0
mirror of https://github.com/netbirdio/netbird.git synced 2025-07-15 13:56:08 +02:00

Fix allow netbird traffic for nftables and userspace ()

Add default allow rules for input and output chains as part of the allownetbird call for userspace mode
This commit is contained in:
Zoltan Papp
2024-01-11 12:21:58 +01:00
committed by GitHub
parent 5311ce4e4a
commit 3591795a58
6 changed files with 99 additions and 4 deletions

@ -22,6 +22,13 @@ jobs:
go-version: "1.21.x" go-version: "1.21.x"
- name: Setup Android SDK - name: Setup Android SDK
uses: android-actions/setup-android@v2 uses: android-actions/setup-android@v2
- name: Setup Java
uses: actions/setup-java@v3
with:
java-version: "8"
distribution: "adopt"
- name: NDK Cache - name: NDK Cache
id: ndk-cache id: ndk-cache
uses: actions/cache@v3 uses: actions/cache@v3

@ -58,6 +58,7 @@ type AclManager struct {
type iFaceMapper interface { type iFaceMapper interface {
Name() string Name() string
Address() iface.WGAddress Address() iface.WGAddress
IsUserspaceBind() bool
} }
func newAclManager(table *nftables.Table, wgIface iFaceMapper, routeingFwChainName string) (*AclManager, error) { func newAclManager(table *nftables.Table, wgIface iFaceMapper, routeingFwChainName string) (*AclManager, error) {
@ -198,6 +199,81 @@ func (m *AclManager) DeleteRule(rule firewall.Rule) error {
return nil return nil
} }
// createDefaultAllowRules In case if the USP firewall manager can use the native firewall manager we must to create allow rules for
// input and output chains
func (m *AclManager) createDefaultAllowRules() error {
expIn := []expr.Any{
&expr.Payload{
DestRegister: 1,
Base: expr.PayloadBaseNetworkHeader,
Offset: 12,
Len: 4,
},
// mask
&expr.Bitwise{
SourceRegister: 1,
DestRegister: 1,
Len: 4,
Mask: []byte{0x00, 0x00, 0x00, 0x00},
Xor: zeroXor,
},
// net address
&expr.Cmp{
Register: 1,
Data: []byte{0x00, 0x00, 0x00, 0x00},
},
&expr.Verdict{
Kind: expr.VerdictAccept,
},
}
_ = m.rConn.InsertRule(&nftables.Rule{
Table: m.workTable,
Chain: m.chainInputRules,
Position: 0,
Exprs: expIn,
})
expOut := []expr.Any{
&expr.Payload{
DestRegister: 1,
Base: expr.PayloadBaseNetworkHeader,
Offset: 16,
Len: 4,
},
// mask
&expr.Bitwise{
SourceRegister: 1,
DestRegister: 1,
Len: 4,
Mask: []byte{0x00, 0x00, 0x00, 0x00},
Xor: zeroXor,
},
// net address
&expr.Cmp{
Register: 1,
Data: []byte{0x00, 0x00, 0x00, 0x00},
},
&expr.Verdict{
Kind: expr.VerdictAccept,
},
}
_ = m.rConn.InsertRule(&nftables.Rule{
Table: m.workTable,
Chain: m.chainOutputRules,
Position: 0,
Exprs: expOut,
})
err := m.rConn.Flush()
if err != nil {
log.Debugf("failed to create default allow rules: %s", err)
return err
}
return nil
}
// Flush rule/chain/set operations from the buffer // Flush rule/chain/set operations from the buffer
// //
// Method also get all rules after flush and refreshes handle values in the rulesets // Method also get all rules after flush and refreshes handle values in the rulesets

@ -106,11 +106,19 @@ func (m *Manager) RemoveRoutingRules(pair firewall.RouterPair) error {
} }
// AllowNetbird allows netbird interface traffic // AllowNetbird allows netbird interface traffic
// todo review this method usage
func (m *Manager) AllowNetbird() error { func (m *Manager) AllowNetbird() error {
if !m.wgIface.IsUserspaceBind() {
return nil
}
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()
err := m.aclManager.createDefaultAllowRules()
if err != nil {
return fmt.Errorf("failed to create default allow rules: %v", err)
}
chains, err := m.rConn.ListChainsOfTableFamily(nftables.TableFamilyIPv4) chains, err := m.rConn.ListChainsOfTableFamily(nftables.TableFamilyIPv4)
if err != nil { if err != nil {
return fmt.Errorf("list of chains: %w", err) return fmt.Errorf("list of chains: %w", err)
@ -145,6 +153,7 @@ func (m *Manager) AllowNetbird() error {
if err != nil { if err != nil {
return fmt.Errorf("failed to flush allow input netbird rules: %v", err) return fmt.Errorf("failed to flush allow input netbird rules: %v", err)
} }
return nil return nil
} }

@ -37,6 +37,8 @@ func (i *iFaceMock) Address() iface.WGAddress {
panic("AddressFunc is not set") panic("AddressFunc is not set")
} }
func (i *iFaceMock) IsUserspaceBind() bool { return false }
func TestNftablesManager(t *testing.T) { func TestNftablesManager(t *testing.T) {
mock := &iFaceMock{ mock := &iFaceMock{
NameFunc: func() string { NameFunc: func() string {

@ -38,7 +38,7 @@ func TestDefaultManager(t *testing.T) {
defer ctrl.Finish() defer ctrl.Finish()
ifaceMock := mocks.NewMockIFaceMapper(ctrl) ifaceMock := mocks.NewMockIFaceMapper(ctrl)
ifaceMock.EXPECT().IsUserspaceBind().Return(true) ifaceMock.EXPECT().IsUserspaceBind().Return(true).AnyTimes()
ifaceMock.EXPECT().SetFilter(gomock.Any()) ifaceMock.EXPECT().SetFilter(gomock.Any())
ip, network, err := net.ParseCIDR("172.0.0.1/32") ip, network, err := net.ParseCIDR("172.0.0.1/32")
if err != nil { if err != nil {
@ -331,7 +331,7 @@ func TestDefaultManagerEnableSSHRules(t *testing.T) {
defer ctrl.Finish() defer ctrl.Finish()
ifaceMock := mocks.NewMockIFaceMapper(ctrl) ifaceMock := mocks.NewMockIFaceMapper(ctrl)
ifaceMock.EXPECT().IsUserspaceBind().Return(true) ifaceMock.EXPECT().IsUserspaceBind().Return(true).AnyTimes()
ifaceMock.EXPECT().SetFilter(gomock.Any()) ifaceMock.EXPECT().SetFilter(gomock.Any())
ip, network, err := net.ParseCIDR("172.0.0.1/32") ip, network, err := net.ParseCIDR("172.0.0.1/32")
if err != nil { if err != nil {

@ -45,6 +45,7 @@ func (t *tunUSPDevice) Create() (wgConfigurer, error) {
log.Info("create tun interface") log.Info("create tun interface")
tunIface, err := tun.CreateTUN(t.name, t.mtu) tunIface, err := tun.CreateTUN(t.name, t.mtu)
if err != nil { if err != nil {
log.Debugf("faile to create tun unterface (%s, %d): %s", t.name, t.mtu, err)
return nil, err return nil, err
} }
t.wrapper = newDeviceWrapper(tunIface) t.wrapper = newDeviceWrapper(tunIface)