Merge branch 'feature/flow' into feat/flow-resid
@@ -31,14 +31,22 @@ Please specify whether you use NetBird Cloud or self-host NetBird's control plan
|
|||||||
|
|
||||||
`netbird version`
|
`netbird version`
|
||||||
|
|
||||||
**NetBird status -dA output:**
|
**Is any other VPN software installed?**
|
||||||
|
|
||||||
If applicable, add the `netbird status -dA' command output.
|
If yes, which one?
|
||||||
|
|
||||||
**Do you face any (non-mobile) client issues?**
|
**Debug output**
|
||||||
|
|
||||||
Please provide the file created by `netbird debug for 1m -AS`.
|
To help us resolve the problem, please attach the following debug output
|
||||||
We advise reviewing the anonymized files for any remaining PII.
|
|
||||||
|
netbird status -dA
|
||||||
|
|
||||||
|
As well as the file created by
|
||||||
|
|
||||||
|
netbird debug for 1m -AS
|
||||||
|
|
||||||
|
|
||||||
|
We advise reviewing the anonymized output for any remaining personal information.
|
||||||
|
|
||||||
**Screenshots**
|
**Screenshots**
|
||||||
|
|
||||||
@@ -47,3 +55,10 @@ If applicable, add screenshots to help explain your problem.
|
|||||||
**Additional context**
|
**Additional context**
|
||||||
|
|
||||||
Add any other context about the problem here.
|
Add any other context about the problem here.
|
||||||
|
|
||||||
|
**Have you tried these troubleshooting steps?**
|
||||||
|
- [ ] Checked for newer NetBird versions
|
||||||
|
- [ ] Searched for similar issues on GitHub (including closed ones)
|
||||||
|
- [ ] Restarted the NetBird client
|
||||||
|
- [ ] Disabled other VPN software
|
||||||
|
- [ ] Checked firewall settings
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
arch: [ '386','amd64' ]
|
arch: [ 'amd64' ]
|
||||||
store: [ 'sqlite', 'postgres', 'mysql' ]
|
store: [ 'sqlite', 'postgres', 'mysql' ]
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
@@ -325,8 +325,8 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
arch: [ '386','amd64' ]
|
arch: [ 'amd64' ]
|
||||||
store: [ 'sqlite', 'postgres', 'mysql' ]
|
store: [ 'sqlite', 'postgres' ]
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
@@ -392,7 +392,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
arch: [ '386','amd64' ]
|
arch: [ 'amd64' ]
|
||||||
store: [ 'sqlite', 'postgres' ]
|
store: [ 'sqlite', 'postgres' ]
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
@@ -461,7 +461,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
arch: [ '386','amd64' ]
|
arch: [ 'amd64' ]
|
||||||
store: [ 'sqlite', 'postgres']
|
store: [ 'sqlite', 'postgres']
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ jobs:
|
|||||||
- name: Install goversioninfo
|
- name: Install goversioninfo
|
||||||
run: go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@233067e
|
run: go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@233067e
|
||||||
- name: Generate windows syso amd64
|
- name: Generate windows syso amd64
|
||||||
run: goversioninfo -icon client/ui/netbird.ico -manifest client/manifest.xml -product-name ${{ env.PRODUCT_NAME }} -copyright "${{ env.COPYRIGHT }}" -ver-major ${{ steps.semver_parser.outputs.major }} -ver-minor ${{ steps.semver_parser.outputs.minor }} -ver-patch ${{ steps.semver_parser.outputs.patch }} -ver-build 0 -file-version ${{ steps.semver_parser.outputs.fullversion }}.0 -product-version ${{ steps.semver_parser.outputs.fullversion }}.0 -o client/resources_windows_amd64.syso
|
run: goversioninfo -icon client/ui/assets/netbird.ico -manifest client/manifest.xml -product-name ${{ env.PRODUCT_NAME }} -copyright "${{ env.COPYRIGHT }}" -ver-major ${{ steps.semver_parser.outputs.major }} -ver-minor ${{ steps.semver_parser.outputs.minor }} -ver-patch ${{ steps.semver_parser.outputs.patch }} -ver-build 0 -file-version ${{ steps.semver_parser.outputs.fullversion }}.0 -product-version ${{ steps.semver_parser.outputs.fullversion }}.0 -o client/resources_windows_amd64.syso
|
||||||
- name: Run GoReleaser
|
- name: Run GoReleaser
|
||||||
uses: goreleaser/goreleaser-action@v4
|
uses: goreleaser/goreleaser-action@v4
|
||||||
with:
|
with:
|
||||||
@@ -150,7 +150,7 @@ jobs:
|
|||||||
- name: Install goversioninfo
|
- name: Install goversioninfo
|
||||||
run: go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@233067e
|
run: go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@233067e
|
||||||
- name: Generate windows syso amd64
|
- name: Generate windows syso amd64
|
||||||
run: goversioninfo -64 -icon client/ui/netbird.ico -manifest client/ui/manifest.xml -product-name ${{ env.PRODUCT_NAME }}-"UI" -copyright "${{ env.COPYRIGHT }}" -ver-major ${{ steps.semver_parser.outputs.major }} -ver-minor ${{ steps.semver_parser.outputs.minor }} -ver-patch ${{ steps.semver_parser.outputs.patch }} -ver-build 0 -file-version ${{ steps.semver_parser.outputs.fullversion }}.0 -product-version ${{ steps.semver_parser.outputs.fullversion }}.0 -o client/ui/resources_windows_amd64.syso
|
run: goversioninfo -64 -icon client/ui/assets/netbird.ico -manifest client/ui/manifest.xml -product-name ${{ env.PRODUCT_NAME }}-"UI" -copyright "${{ env.COPYRIGHT }}" -ver-major ${{ steps.semver_parser.outputs.major }} -ver-minor ${{ steps.semver_parser.outputs.minor }} -ver-patch ${{ steps.semver_parser.outputs.patch }} -ver-build 0 -file-version ${{ steps.semver_parser.outputs.fullversion }}.0 -product-version ${{ steps.semver_parser.outputs.fullversion }}.0 -o client/ui/resources_windows_amd64.syso
|
||||||
|
|
||||||
- name: Run GoReleaser
|
- name: Run GoReleaser
|
||||||
uses: goreleaser/goreleaser-action@v4
|
uses: goreleaser/goreleaser-action@v4
|
||||||
|
|||||||
@@ -53,9 +53,9 @@ nfpms:
|
|||||||
scripts:
|
scripts:
|
||||||
postinstall: "release_files/ui-post-install.sh"
|
postinstall: "release_files/ui-post-install.sh"
|
||||||
contents:
|
contents:
|
||||||
- src: client/ui/netbird.desktop
|
- src: client/ui/build/netbird.desktop
|
||||||
dst: /usr/share/applications/netbird.desktop
|
dst: /usr/share/applications/netbird.desktop
|
||||||
- src: client/ui/netbird.png
|
- src: client/ui/assets/netbird.png
|
||||||
dst: /usr/share/pixmaps/netbird.png
|
dst: /usr/share/pixmaps/netbird.png
|
||||||
dependencies:
|
dependencies:
|
||||||
- netbird
|
- netbird
|
||||||
@@ -72,9 +72,9 @@ nfpms:
|
|||||||
scripts:
|
scripts:
|
||||||
postinstall: "release_files/ui-post-install.sh"
|
postinstall: "release_files/ui-post-install.sh"
|
||||||
contents:
|
contents:
|
||||||
- src: client/ui/netbird.desktop
|
- src: client/ui/build/netbird.desktop
|
||||||
dst: /usr/share/applications/netbird.desktop
|
dst: /usr/share/applications/netbird.desktop
|
||||||
- src: client/ui/netbird.png
|
- src: client/ui/assets/netbird.png
|
||||||
dst: /usr/share/pixmaps/netbird.png
|
dst: /usr/share/pixmaps/netbird.png
|
||||||
dependencies:
|
dependencies:
|
||||||
- netbird
|
- netbird
|
||||||
|
|||||||
@@ -134,10 +134,11 @@ func (c *Client) Start(startCtx context.Context) error {
|
|||||||
|
|
||||||
// either startup error (permanent backoff err) or nil err (successful engine up)
|
// either startup error (permanent backoff err) or nil err (successful engine up)
|
||||||
// TODO: make after-startup backoff err available
|
// TODO: make after-startup backoff err available
|
||||||
run := make(chan error, 1)
|
run := make(chan struct{}, 1)
|
||||||
|
clientErr := make(chan error, 1)
|
||||||
go func() {
|
go func() {
|
||||||
if err := client.Run(run); err != nil {
|
if err := client.Run(run); err != nil {
|
||||||
run <- err
|
clientErr <- err
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -147,13 +148,9 @@ func (c *Client) Start(startCtx context.Context) error {
|
|||||||
return fmt.Errorf("stop error after context done. Stop error: %w. Context done: %w", stopErr, startCtx.Err())
|
return fmt.Errorf("stop error after context done. Stop error: %w. Context done: %w", stopErr, startCtx.Err())
|
||||||
}
|
}
|
||||||
return startCtx.Err()
|
return startCtx.Err()
|
||||||
case err := <-run:
|
case err := <-clientErr:
|
||||||
if err != nil {
|
return fmt.Errorf("startup: %w", err)
|
||||||
if stopErr := client.Stop(); stopErr != nil {
|
case <-run:
|
||||||
return fmt.Errorf("stop error after failed to startup. Stop error: %w. Start error: %w", stopErr, err)
|
|
||||||
}
|
|
||||||
return fmt.Errorf("startup: %w", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.connect = client
|
c.connect = client
|
||||||
|
|||||||
@@ -4,12 +4,13 @@ import (
|
|||||||
wgdevice "golang.zx2c4.com/wireguard/device"
|
wgdevice "golang.zx2c4.com/wireguard/device"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IFaceMapper defines subset methods of interface required for manager
|
// IFaceMapper defines subset methods of interface required for manager
|
||||||
type IFaceMapper interface {
|
type IFaceMapper interface {
|
||||||
Name() string
|
Name() string
|
||||||
Address() device.WGAddress
|
Address() wgaddr.Address
|
||||||
IsUserspaceBind() bool
|
IsUserspaceBind() bool
|
||||||
SetFilter(device.PacketFilter) error
|
SetFilter(device.PacketFilter) error
|
||||||
GetDevice() *device.FilteredDevice
|
GetDevice() *device.FilteredDevice
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
|
|
||||||
nberrors "github.com/netbirdio/netbird/client/errors"
|
nberrors "github.com/netbirdio/netbird/client/errors"
|
||||||
firewall "github.com/netbirdio/netbird/client/firewall/manager"
|
firewall "github.com/netbirdio/netbird/client/firewall/manager"
|
||||||
"github.com/netbirdio/netbird/client/iface"
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/client/internal/statemanager"
|
"github.com/netbirdio/netbird/client/internal/statemanager"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ type Manager struct {
|
|||||||
// iFaceMapper defines subset methods of interface required for manager
|
// iFaceMapper defines subset methods of interface required for manager
|
||||||
type iFaceMapper interface {
|
type iFaceMapper interface {
|
||||||
Name() string
|
Name() string
|
||||||
Address() iface.WGAddress
|
Address() wgaddr.Address
|
||||||
IsUserspaceBind() bool
|
IsUserspaceBind() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ func (m *Manager) SetLegacyManagement(isLegacy bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reset firewall to the default state
|
// Reset firewall to the default state
|
||||||
func (m *Manager) Reset(stateManager *statemanager.Manager) error {
|
func (m *Manager) Close(stateManager *statemanager.Manager) error {
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
|
|||||||
@@ -10,15 +10,15 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
fw "github.com/netbirdio/netbird/client/firewall/manager"
|
fw "github.com/netbirdio/netbird/client/firewall/manager"
|
||||||
"github.com/netbirdio/netbird/client/iface"
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ifaceMock = &iFaceMock{
|
var ifaceMock = &iFaceMock{
|
||||||
NameFunc: func() string {
|
NameFunc: func() string {
|
||||||
return "lo"
|
return "lo"
|
||||||
},
|
},
|
||||||
AddressFunc: func() iface.WGAddress {
|
AddressFunc: func() wgaddr.Address {
|
||||||
return iface.WGAddress{
|
return wgaddr.Address{
|
||||||
IP: net.ParseIP("10.20.0.1"),
|
IP: net.ParseIP("10.20.0.1"),
|
||||||
Network: &net.IPNet{
|
Network: &net.IPNet{
|
||||||
IP: net.ParseIP("10.20.0.0"),
|
IP: net.ParseIP("10.20.0.0"),
|
||||||
@@ -31,7 +31,7 @@ var ifaceMock = &iFaceMock{
|
|||||||
// iFaceMapper defines subset methods of interface required for manager
|
// iFaceMapper defines subset methods of interface required for manager
|
||||||
type iFaceMock struct {
|
type iFaceMock struct {
|
||||||
NameFunc func() string
|
NameFunc func() string
|
||||||
AddressFunc func() iface.WGAddress
|
AddressFunc func() wgaddr.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *iFaceMock) Name() string {
|
func (i *iFaceMock) Name() string {
|
||||||
@@ -41,7 +41,7 @@ func (i *iFaceMock) Name() string {
|
|||||||
panic("NameFunc is not set")
|
panic("NameFunc is not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *iFaceMock) Address() iface.WGAddress {
|
func (i *iFaceMock) Address() wgaddr.Address {
|
||||||
if i.AddressFunc != nil {
|
if i.AddressFunc != nil {
|
||||||
return i.AddressFunc()
|
return i.AddressFunc()
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ func TestIptablesManager(t *testing.T) {
|
|||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err := manager.Reset(nil)
|
err := manager.Close(nil)
|
||||||
require.NoError(t, err, "clear the manager state")
|
require.NoError(t, err, "clear the manager state")
|
||||||
|
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
@@ -100,14 +100,14 @@ func TestIptablesManager(t *testing.T) {
|
|||||||
_, err = manager.AddPeerFiltering(nil, ip, "udp", nil, port, fw.ActionAccept, "")
|
_, err = manager.AddPeerFiltering(nil, ip, "udp", nil, port, fw.ActionAccept, "")
|
||||||
require.NoError(t, err, "failed to add rule")
|
require.NoError(t, err, "failed to add rule")
|
||||||
|
|
||||||
err = manager.Reset(nil)
|
err = manager.Close(nil)
|
||||||
require.NoError(t, err, "failed to reset")
|
require.NoError(t, err, "failed to reset")
|
||||||
|
|
||||||
ok, err := ipv4Client.ChainExists("filter", chainNameInputRules)
|
ok, err := ipv4Client.ChainExists("filter", chainNameInputRules)
|
||||||
require.NoError(t, err, "failed check chain exists")
|
require.NoError(t, err, "failed check chain exists")
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
require.NoErrorf(t, err, "chain '%v' still exists after Reset", chainNameInputRules)
|
require.NoErrorf(t, err, "chain '%v' still exists after Close", chainNameInputRules)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -117,8 +117,8 @@ func TestIptablesManagerIPSet(t *testing.T) {
|
|||||||
NameFunc: func() string {
|
NameFunc: func() string {
|
||||||
return "lo"
|
return "lo"
|
||||||
},
|
},
|
||||||
AddressFunc: func() iface.WGAddress {
|
AddressFunc: func() wgaddr.Address {
|
||||||
return iface.WGAddress{
|
return wgaddr.Address{
|
||||||
IP: net.ParseIP("10.20.0.1"),
|
IP: net.ParseIP("10.20.0.1"),
|
||||||
Network: &net.IPNet{
|
Network: &net.IPNet{
|
||||||
IP: net.ParseIP("10.20.0.0"),
|
IP: net.ParseIP("10.20.0.0"),
|
||||||
@@ -136,7 +136,7 @@ func TestIptablesManagerIPSet(t *testing.T) {
|
|||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err := manager.Reset(nil)
|
err := manager.Close(nil)
|
||||||
require.NoError(t, err, "clear the manager state")
|
require.NoError(t, err, "clear the manager state")
|
||||||
|
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
@@ -166,7 +166,7 @@ func TestIptablesManagerIPSet(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("reset check", func(t *testing.T) {
|
t.Run("reset check", func(t *testing.T) {
|
||||||
err = manager.Reset(nil)
|
err = manager.Close(nil)
|
||||||
require.NoError(t, err, "failed to reset")
|
require.NoError(t, err, "failed to reset")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -184,8 +184,8 @@ func TestIptablesCreatePerformance(t *testing.T) {
|
|||||||
NameFunc: func() string {
|
NameFunc: func() string {
|
||||||
return "lo"
|
return "lo"
|
||||||
},
|
},
|
||||||
AddressFunc: func() iface.WGAddress {
|
AddressFunc: func() wgaddr.Address {
|
||||||
return iface.WGAddress{
|
return wgaddr.Address{
|
||||||
IP: net.ParseIP("10.20.0.1"),
|
IP: net.ParseIP("10.20.0.1"),
|
||||||
Network: &net.IPNet{
|
Network: &net.IPNet{
|
||||||
IP: net.ParseIP("10.20.0.0"),
|
IP: net.ParseIP("10.20.0.0"),
|
||||||
@@ -204,7 +204,7 @@ func TestIptablesCreatePerformance(t *testing.T) {
|
|||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err := manager.Reset(nil)
|
err := manager.Close(nil)
|
||||||
require.NoError(t, err, "clear the manager state")
|
require.NoError(t, err, "clear the manager state")
|
||||||
|
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|||||||
@@ -4,21 +4,20 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface"
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type InterfaceState struct {
|
type InterfaceState struct {
|
||||||
NameStr string `json:"name"`
|
NameStr string `json:"name"`
|
||||||
WGAddress iface.WGAddress `json:"wg_address"`
|
WGAddress wgaddr.Address `json:"wg_address"`
|
||||||
UserspaceBind bool `json:"userspace_bind"`
|
UserspaceBind bool `json:"userspace_bind"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *InterfaceState) Name() string {
|
func (i *InterfaceState) Name() string {
|
||||||
return i.NameStr
|
return i.NameStr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *InterfaceState) Address() device.WGAddress {
|
func (i *InterfaceState) Address() wgaddr.Address {
|
||||||
return i.WGAddress
|
return i.WGAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +61,7 @@ func (s *ShutdownState) Cleanup() error {
|
|||||||
ipt.aclMgr.ipsetStore = s.ACLIPsetStore
|
ipt.aclMgr.ipsetStore = s.ACLIPsetStore
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ipt.Reset(nil); err != nil {
|
if err := ipt.Close(nil); err != nil {
|
||||||
return fmt.Errorf("reset iptables manager: %w", err)
|
return fmt.Errorf("reset iptables manager: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,8 +102,8 @@ type Manager interface {
|
|||||||
// SetLegacyManagement sets the legacy management mode
|
// SetLegacyManagement sets the legacy management mode
|
||||||
SetLegacyManagement(legacy bool) error
|
SetLegacyManagement(legacy bool) error
|
||||||
|
|
||||||
// Reset firewall to the default state
|
// Close closes the firewall manager
|
||||||
Reset(stateManager *statemanager.Manager) error
|
Close(stateManager *statemanager.Manager) error
|
||||||
|
|
||||||
// Flush the changes to firewall controller
|
// Flush the changes to firewall controller
|
||||||
Flush() error
|
Flush() error
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
firewall "github.com/netbirdio/netbird/client/firewall/manager"
|
firewall "github.com/netbirdio/netbird/client/firewall/manager"
|
||||||
"github.com/netbirdio/netbird/client/iface"
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/client/internal/statemanager"
|
"github.com/netbirdio/netbird/client/internal/statemanager"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ const (
|
|||||||
// iFaceMapper defines subset methods of interface required for manager
|
// iFaceMapper defines subset methods of interface required for manager
|
||||||
type iFaceMapper interface {
|
type iFaceMapper interface {
|
||||||
Name() string
|
Name() string
|
||||||
Address() iface.WGAddress
|
Address() wgaddr.Address
|
||||||
IsUserspaceBind() bool
|
IsUserspaceBind() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ func (m *Manager) Init(stateManager *statemanager.Manager) error {
|
|||||||
// We only need to record minimal interface state for potential recreation.
|
// We only need to record minimal interface state for potential recreation.
|
||||||
// Unlike iptables, which requires tracking individual rules, nftables maintains
|
// Unlike iptables, which requires tracking individual rules, nftables maintains
|
||||||
// a known state (our netbird table plus a few static rules). This allows for easy
|
// a known state (our netbird table plus a few static rules). This allows for easy
|
||||||
// cleanup using Reset() without needing to store specific rules.
|
// cleanup using Close() without needing to store specific rules.
|
||||||
if err := stateManager.UpdateState(&ShutdownState{
|
if err := stateManager.UpdateState(&ShutdownState{
|
||||||
InterfaceState: &InterfaceState{
|
InterfaceState: &InterfaceState{
|
||||||
NameStr: m.wgIface.Name(),
|
NameStr: m.wgIface.Name(),
|
||||||
@@ -243,7 +243,7 @@ func (m *Manager) SetLegacyManagement(isLegacy bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reset firewall to the default state
|
// Reset firewall to the default state
|
||||||
func (m *Manager) Reset(stateManager *statemanager.Manager) error {
|
func (m *Manager) Close(stateManager *statemanager.Manager) error {
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
|
|||||||
@@ -16,15 +16,15 @@ import (
|
|||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
fw "github.com/netbirdio/netbird/client/firewall/manager"
|
fw "github.com/netbirdio/netbird/client/firewall/manager"
|
||||||
"github.com/netbirdio/netbird/client/iface"
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ifaceMock = &iFaceMock{
|
var ifaceMock = &iFaceMock{
|
||||||
NameFunc: func() string {
|
NameFunc: func() string {
|
||||||
return "lo"
|
return "lo"
|
||||||
},
|
},
|
||||||
AddressFunc: func() iface.WGAddress {
|
AddressFunc: func() wgaddr.Address {
|
||||||
return iface.WGAddress{
|
return wgaddr.Address{
|
||||||
IP: net.ParseIP("100.96.0.1"),
|
IP: net.ParseIP("100.96.0.1"),
|
||||||
Network: &net.IPNet{
|
Network: &net.IPNet{
|
||||||
IP: net.ParseIP("100.96.0.0"),
|
IP: net.ParseIP("100.96.0.0"),
|
||||||
@@ -37,7 +37,7 @@ var ifaceMock = &iFaceMock{
|
|||||||
// iFaceMapper defines subset methods of interface required for manager
|
// iFaceMapper defines subset methods of interface required for manager
|
||||||
type iFaceMock struct {
|
type iFaceMock struct {
|
||||||
NameFunc func() string
|
NameFunc func() string
|
||||||
AddressFunc func() iface.WGAddress
|
AddressFunc func() wgaddr.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *iFaceMock) Name() string {
|
func (i *iFaceMock) Name() string {
|
||||||
@@ -47,7 +47,7 @@ func (i *iFaceMock) Name() string {
|
|||||||
panic("NameFunc is not set")
|
panic("NameFunc is not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *iFaceMock) Address() iface.WGAddress {
|
func (i *iFaceMock) Address() wgaddr.Address {
|
||||||
if i.AddressFunc != nil {
|
if i.AddressFunc != nil {
|
||||||
return i.AddressFunc()
|
return i.AddressFunc()
|
||||||
}
|
}
|
||||||
@@ -65,7 +65,7 @@ func TestNftablesManager(t *testing.T) {
|
|||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err = manager.Reset(nil)
|
err = manager.Close(nil)
|
||||||
require.NoError(t, err, "failed to reset")
|
require.NoError(t, err, "failed to reset")
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}()
|
}()
|
||||||
@@ -162,7 +162,7 @@ func TestNftablesManager(t *testing.T) {
|
|||||||
// established rule remains
|
// established rule remains
|
||||||
require.Len(t, rules, 1, "expected 1 rules after deletion")
|
require.Len(t, rules, 1, "expected 1 rules after deletion")
|
||||||
|
|
||||||
err = manager.Reset(nil)
|
err = manager.Close(nil)
|
||||||
require.NoError(t, err, "failed to reset")
|
require.NoError(t, err, "failed to reset")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,8 +171,8 @@ func TestNFtablesCreatePerformance(t *testing.T) {
|
|||||||
NameFunc: func() string {
|
NameFunc: func() string {
|
||||||
return "lo"
|
return "lo"
|
||||||
},
|
},
|
||||||
AddressFunc: func() iface.WGAddress {
|
AddressFunc: func() wgaddr.Address {
|
||||||
return iface.WGAddress{
|
return wgaddr.Address{
|
||||||
IP: net.ParseIP("100.96.0.1"),
|
IP: net.ParseIP("100.96.0.1"),
|
||||||
Network: &net.IPNet{
|
Network: &net.IPNet{
|
||||||
IP: net.ParseIP("100.96.0.0"),
|
IP: net.ParseIP("100.96.0.0"),
|
||||||
@@ -191,7 +191,7 @@ func TestNFtablesCreatePerformance(t *testing.T) {
|
|||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := manager.Reset(nil); err != nil {
|
if err := manager.Close(nil); err != nil {
|
||||||
t.Errorf("clear the manager state: %v", err)
|
t.Errorf("clear the manager state: %v", err)
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
@@ -274,7 +274,7 @@ func TestNftablesManagerCompatibilityWithIptables(t *testing.T) {
|
|||||||
require.NoError(t, manager.Init(nil))
|
require.NoError(t, manager.Init(nil))
|
||||||
|
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
err := manager.Reset(nil)
|
err := manager.Close(nil)
|
||||||
require.NoError(t, err, "failed to reset manager state")
|
require.NoError(t, err, "failed to reset manager state")
|
||||||
|
|
||||||
// Verify iptables output after reset
|
// Verify iptables output after reset
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ func TestNftablesManager_AddNatRule(t *testing.T) {
|
|||||||
// need fw manager to init both acl mgr and router for all chains to be present
|
// need fw manager to init both acl mgr and router for all chains to be present
|
||||||
manager, err := Create(ifaceMock)
|
manager, err := Create(ifaceMock)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
require.NoError(t, manager.Reset(nil))
|
require.NoError(t, manager.Close(nil))
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, manager.Init(nil))
|
require.NoError(t, manager.Init(nil))
|
||||||
@@ -127,7 +127,7 @@ func TestNftablesManager_RemoveNatRule(t *testing.T) {
|
|||||||
t.Run(testCase.Name, func(t *testing.T) {
|
t.Run(testCase.Name, func(t *testing.T) {
|
||||||
manager, err := Create(ifaceMock)
|
manager, err := Create(ifaceMock)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
require.NoError(t, manager.Reset(nil))
|
require.NoError(t, manager.Close(nil))
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, manager.Init(nil))
|
require.NoError(t, manager.Init(nil))
|
||||||
|
|||||||
@@ -3,21 +3,20 @@ package nftables
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface"
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type InterfaceState struct {
|
type InterfaceState struct {
|
||||||
NameStr string `json:"name"`
|
NameStr string `json:"name"`
|
||||||
WGAddress iface.WGAddress `json:"wg_address"`
|
WGAddress wgaddr.Address `json:"wg_address"`
|
||||||
UserspaceBind bool `json:"userspace_bind"`
|
UserspaceBind bool `json:"userspace_bind"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *InterfaceState) Name() string {
|
func (i *InterfaceState) Name() string {
|
||||||
return i.NameStr
|
return i.NameStr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *InterfaceState) Address() device.WGAddress {
|
func (i *InterfaceState) Address() wgaddr.Address {
|
||||||
return i.WGAddress
|
return i.WGAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +38,7 @@ func (s *ShutdownState) Cleanup() error {
|
|||||||
return fmt.Errorf("create nftables manager: %w", err)
|
return fmt.Errorf("create nftables manager: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := nft.Reset(nil); err != nil {
|
if err := nft.Close(nil); err != nil {
|
||||||
return fmt.Errorf("reset nftables manager: %w", err)
|
return fmt.Errorf("reset nftables manager: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,12 +9,11 @@ import (
|
|||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/firewall/uspfilter/conntrack"
|
|
||||||
"github.com/netbirdio/netbird/client/internal/statemanager"
|
"github.com/netbirdio/netbird/client/internal/statemanager"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reset firewall to the default state
|
// Reset firewall to the default state
|
||||||
func (m *Manager) Reset(stateManager *statemanager.Manager) error {
|
func (m *Manager) Close(stateManager *statemanager.Manager) error {
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
@@ -23,17 +22,14 @@ func (m *Manager) Reset(stateManager *statemanager.Manager) error {
|
|||||||
|
|
||||||
if m.udpTracker != nil {
|
if m.udpTracker != nil {
|
||||||
m.udpTracker.Close()
|
m.udpTracker.Close()
|
||||||
m.udpTracker = conntrack.NewUDPTracker(conntrack.DefaultUDPTimeout, m.logger, m.flowLogger)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.icmpTracker != nil {
|
if m.icmpTracker != nil {
|
||||||
m.icmpTracker.Close()
|
m.icmpTracker.Close()
|
||||||
m.icmpTracker = conntrack.NewICMPTracker(conntrack.DefaultICMPTimeout, m.logger, m.flowLogger)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.tcpTracker != nil {
|
if m.tcpTracker != nil {
|
||||||
m.tcpTracker.Close()
|
m.tcpTracker.Close()
|
||||||
m.tcpTracker = conntrack.NewTCPTracker(conntrack.DefaultTCPTimeout, m.logger, m.flowLogger)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if fwder := m.forwarder.Load(); fwder != nil {
|
if fwder := m.forwarder.Load(); fwder != nil {
|
||||||
@@ -49,7 +45,7 @@ func (m *Manager) Reset(stateManager *statemanager.Manager) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if m.nativeFirewall != nil {
|
if m.nativeFirewall != nil {
|
||||||
return m.nativeFirewall.Reset(stateManager)
|
return m.nativeFirewall.Close(stateManager)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Reset firewall to the default state
|
// Reset firewall to the default state
|
||||||
func (m *Manager) Reset(*statemanager.Manager) error {
|
func (m *Manager) Close(*statemanager.Manager) error {
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ package common
|
|||||||
import (
|
import (
|
||||||
wgdevice "golang.zx2c4.com/wireguard/device"
|
wgdevice "golang.zx2c4.com/wireguard/device"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface"
|
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IFaceMapper defines subset methods of interface required for manager
|
// IFaceMapper defines subset methods of interface required for manager
|
||||||
type IFaceMapper interface {
|
type IFaceMapper interface {
|
||||||
SetFilter(device.PacketFilter) error
|
SetFilter(device.PacketFilter) error
|
||||||
Address() iface.WGAddress
|
Address() wgaddr.Address
|
||||||
GetWGDevice() *wgdevice.Device
|
GetWGDevice() *wgdevice.Device
|
||||||
GetDevice() *device.FilteredDevice
|
GetDevice() *device.FilteredDevice
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package conntrack
|
package conntrack
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -44,8 +45,8 @@ type ICMPTracker struct {
|
|||||||
connections map[ICMPConnKey]*ICMPConnTrack
|
connections map[ICMPConnKey]*ICMPConnTrack
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
cleanupTicker *time.Ticker
|
cleanupTicker *time.Ticker
|
||||||
|
tickerCancel context.CancelFunc
|
||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
done chan struct{}
|
|
||||||
flowLogger nftypes.FlowLogger
|
flowLogger nftypes.FlowLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,16 +56,18 @@ func NewICMPTracker(timeout time.Duration, logger *nblog.Logger, flowLogger nfty
|
|||||||
timeout = DefaultICMPTimeout
|
timeout = DefaultICMPTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
tracker := &ICMPTracker{
|
tracker := &ICMPTracker{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
connections: make(map[ICMPConnKey]*ICMPConnTrack),
|
connections: make(map[ICMPConnKey]*ICMPConnTrack),
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
cleanupTicker: time.NewTicker(ICMPCleanupInterval),
|
cleanupTicker: time.NewTicker(ICMPCleanupInterval),
|
||||||
done: make(chan struct{}),
|
tickerCancel: cancel,
|
||||||
flowLogger: flowLogger,
|
flowLogger: flowLogger,
|
||||||
}
|
}
|
||||||
|
|
||||||
go tracker.cleanupRoutine()
|
go tracker.cleanupRoutine(ctx)
|
||||||
return tracker
|
return tracker
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,12 +167,14 @@ func (t *ICMPTracker) IsValidInbound(srcIP netip.Addr, dstIP netip.Addr, id uint
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *ICMPTracker) cleanupRoutine() {
|
func (t *ICMPTracker) cleanupRoutine(ctx context.Context) {
|
||||||
|
defer t.tickerCancel()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-t.cleanupTicker.C:
|
case <-t.cleanupTicker.C:
|
||||||
t.cleanup()
|
t.cleanup()
|
||||||
case <-t.done:
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,8 +197,7 @@ func (t *ICMPTracker) cleanup() {
|
|||||||
|
|
||||||
// Close stops the cleanup routine and releases resources
|
// Close stops the cleanup routine and releases resources
|
||||||
func (t *ICMPTracker) Close() {
|
func (t *ICMPTracker) Close() {
|
||||||
t.cleanupTicker.Stop()
|
t.tickerCancel()
|
||||||
close(t.done)
|
|
||||||
|
|
||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
t.connections = nil
|
t.connections = nil
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package conntrack
|
|||||||
// TODO: Send RST packets for invalid/timed-out connections
|
// TODO: Send RST packets for invalid/timed-out connections
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@@ -122,7 +123,7 @@ type TCPTracker struct {
|
|||||||
connections map[ConnKey]*TCPConnTrack
|
connections map[ConnKey]*TCPConnTrack
|
||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
cleanupTicker *time.Ticker
|
cleanupTicker *time.Ticker
|
||||||
done chan struct{}
|
tickerCancel context.CancelFunc
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
flowLogger nftypes.FlowLogger
|
flowLogger nftypes.FlowLogger
|
||||||
}
|
}
|
||||||
@@ -133,16 +134,18 @@ func NewTCPTracker(timeout time.Duration, logger *nblog.Logger, flowLogger nftyp
|
|||||||
timeout = DefaultTCPTimeout
|
timeout = DefaultTCPTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
tracker := &TCPTracker{
|
tracker := &TCPTracker{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
connections: make(map[ConnKey]*TCPConnTrack),
|
connections: make(map[ConnKey]*TCPConnTrack),
|
||||||
cleanupTicker: time.NewTicker(TCPCleanupInterval),
|
cleanupTicker: time.NewTicker(TCPCleanupInterval),
|
||||||
done: make(chan struct{}),
|
tickerCancel: cancel,
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
flowLogger: flowLogger,
|
flowLogger: flowLogger,
|
||||||
}
|
}
|
||||||
|
|
||||||
go tracker.cleanupRoutine()
|
go tracker.cleanupRoutine(ctx)
|
||||||
return tracker
|
return tracker
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,12 +399,14 @@ func (t *TCPTracker) isValidStateForFlags(state TCPState, flags uint8) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TCPTracker) cleanupRoutine() {
|
func (t *TCPTracker) cleanupRoutine(ctx context.Context) {
|
||||||
|
defer t.cleanupTicker.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-t.cleanupTicker.C:
|
case <-t.cleanupTicker.C:
|
||||||
t.cleanup()
|
t.cleanup()
|
||||||
case <-t.done:
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -444,8 +449,7 @@ func (t *TCPTracker) cleanup() {
|
|||||||
|
|
||||||
// Close stops the cleanup routine and releases resources
|
// Close stops the cleanup routine and releases resources
|
||||||
func (t *TCPTracker) Close() {
|
func (t *TCPTracker) Close() {
|
||||||
t.cleanupTicker.Stop()
|
t.tickerCancel()
|
||||||
close(t.done)
|
|
||||||
|
|
||||||
// Clean up all remaining IPs
|
// Clean up all remaining IPs
|
||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package conntrack
|
package conntrack
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -31,8 +32,8 @@ type UDPTracker struct {
|
|||||||
connections map[ConnKey]*UDPConnTrack
|
connections map[ConnKey]*UDPConnTrack
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
cleanupTicker *time.Ticker
|
cleanupTicker *time.Ticker
|
||||||
|
tickerCancel context.CancelFunc
|
||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
done chan struct{}
|
|
||||||
flowLogger nftypes.FlowLogger
|
flowLogger nftypes.FlowLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,16 +43,18 @@ func NewUDPTracker(timeout time.Duration, logger *nblog.Logger, flowLogger nftyp
|
|||||||
timeout = DefaultUDPTimeout
|
timeout = DefaultUDPTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
tracker := &UDPTracker{
|
tracker := &UDPTracker{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
connections: make(map[ConnKey]*UDPConnTrack),
|
connections: make(map[ConnKey]*UDPConnTrack),
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
cleanupTicker: time.NewTicker(UDPCleanupInterval),
|
cleanupTicker: time.NewTicker(UDPCleanupInterval),
|
||||||
done: make(chan struct{}),
|
tickerCancel: cancel,
|
||||||
flowLogger: flowLogger,
|
flowLogger: flowLogger,
|
||||||
}
|
}
|
||||||
|
|
||||||
go tracker.cleanupRoutine()
|
go tracker.cleanupRoutine(ctx)
|
||||||
return tracker
|
return tracker
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,12 +143,14 @@ func (t *UDPTracker) IsValidInbound(srcIP netip.Addr, dstIP netip.Addr, srcPort
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cleanupRoutine periodically removes stale connections
|
// cleanupRoutine periodically removes stale connections
|
||||||
func (t *UDPTracker) cleanupRoutine() {
|
func (t *UDPTracker) cleanupRoutine(ctx context.Context) {
|
||||||
|
defer t.cleanupTicker.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-t.cleanupTicker.C:
|
case <-t.cleanupTicker.C:
|
||||||
t.cleanup()
|
t.cleanup()
|
||||||
case <-t.done:
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,8 +173,7 @@ func (t *UDPTracker) cleanup() {
|
|||||||
|
|
||||||
// Close stops the cleanup routine and releases resources
|
// Close stops the cleanup routine and releases resources
|
||||||
func (t *UDPTracker) Close() {
|
func (t *UDPTracker) Close() {
|
||||||
t.cleanupTicker.Stop()
|
t.tickerCancel()
|
||||||
close(t.done)
|
|
||||||
|
|
||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
t.connections = nil
|
t.connections = nil
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package conntrack
|
package conntrack
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -34,7 +35,7 @@ func TestNewUDPTracker(t *testing.T) {
|
|||||||
assert.Equal(t, tt.wantTimeout, tracker.timeout)
|
assert.Equal(t, tt.wantTimeout, tracker.timeout)
|
||||||
assert.NotNil(t, tracker.connections)
|
assert.NotNil(t, tracker.connections)
|
||||||
assert.NotNil(t, tracker.cleanupTicker)
|
assert.NotNil(t, tracker.cleanupTicker)
|
||||||
assert.NotNil(t, tracker.done)
|
assert.NotNil(t, tracker.tickerCancel)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,18 +160,21 @@ func TestUDPTracker_Cleanup(t *testing.T) {
|
|||||||
timeout := 50 * time.Millisecond
|
timeout := 50 * time.Millisecond
|
||||||
cleanupInterval := 25 * time.Millisecond
|
cleanupInterval := 25 * time.Millisecond
|
||||||
|
|
||||||
|
ctx, tickerCancel := context.WithCancel(context.Background())
|
||||||
|
defer tickerCancel()
|
||||||
|
|
||||||
// Create tracker with custom cleanup interval
|
// Create tracker with custom cleanup interval
|
||||||
tracker := &UDPTracker{
|
tracker := &UDPTracker{
|
||||||
connections: make(map[ConnKey]*UDPConnTrack),
|
connections: make(map[ConnKey]*UDPConnTrack),
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
cleanupTicker: time.NewTicker(cleanupInterval),
|
cleanupTicker: time.NewTicker(cleanupInterval),
|
||||||
done: make(chan struct{}),
|
tickerCancel: tickerCancel,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
flowLogger: flowLogger,
|
flowLogger: flowLogger,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start cleanup routine
|
// Start cleanup routine
|
||||||
go tracker.cleanupRoutine()
|
go tracker.cleanupRoutine(ctx)
|
||||||
|
|
||||||
// Add some connections
|
// Add some connections
|
||||||
connections := []struct {
|
connections := []struct {
|
||||||
|
|||||||
@@ -117,8 +117,8 @@ func (f *Forwarder) sendICMPEvent(typ nftypes.Type, flowID uuid.UUID, id stack.T
|
|||||||
Direction: nftypes.Ingress,
|
Direction: nftypes.Ingress,
|
||||||
Protocol: nftypes.ICMP,
|
Protocol: nftypes.ICMP,
|
||||||
// TODO: handle ipv6
|
// TODO: handle ipv6
|
||||||
SourceIP: netip.AddrFrom4(id.LocalAddress.As4()),
|
SourceIP: netip.AddrFrom4(id.RemoteAddress.As4()),
|
||||||
DestIP: netip.AddrFrom4(id.RemoteAddress.As4()),
|
DestIP: netip.AddrFrom4(id.LocalAddress.As4()),
|
||||||
ICMPType: icmpType,
|
ICMPType: icmpType,
|
||||||
ICMPCode: icmpCode,
|
ICMPCode: icmpCode,
|
||||||
|
|
||||||
|
|||||||
@@ -113,10 +113,10 @@ func (f *Forwarder) sendTCPEvent(typ nftypes.Type, flowID uuid.UUID, id stack.Tr
|
|||||||
Direction: nftypes.Ingress,
|
Direction: nftypes.Ingress,
|
||||||
Protocol: nftypes.TCP,
|
Protocol: nftypes.TCP,
|
||||||
// TODO: handle ipv6
|
// TODO: handle ipv6
|
||||||
SourceIP: netip.AddrFrom4(id.LocalAddress.As4()),
|
SourceIP: netip.AddrFrom4(id.RemoteAddress.As4()),
|
||||||
DestIP: netip.AddrFrom4(id.RemoteAddress.As4()),
|
DestIP: netip.AddrFrom4(id.LocalAddress.As4()),
|
||||||
SourcePort: id.LocalPort,
|
SourcePort: id.RemotePort,
|
||||||
DestPort: id.RemotePort,
|
DestPort: id.LocalPort,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ep != nil {
|
if ep != nil {
|
||||||
|
|||||||
@@ -89,21 +89,6 @@ func (f *udpForwarder) Stop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sendUDPEvent stores flow events for UDP connections
|
|
||||||
func (f *udpForwarder) sendUDPEvent(typ nftypes.Type, flowID uuid.UUID, id stack.TransportEndpointID) {
|
|
||||||
f.flowLogger.StoreEvent(nftypes.EventFields{
|
|
||||||
FlowID: flowID,
|
|
||||||
Type: typ,
|
|
||||||
Direction: nftypes.Ingress,
|
|
||||||
Protocol: 17,
|
|
||||||
// TODO: handle ipv6
|
|
||||||
SourceIP: netip.AddrFrom4(id.LocalAddress.As4()),
|
|
||||||
DestIP: netip.AddrFrom4(id.RemoteAddress.As4()),
|
|
||||||
SourcePort: id.LocalPort,
|
|
||||||
DestPort: id.RemotePort,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// cleanup periodically removes idle UDP connections
|
// cleanup periodically removes idle UDP connections
|
||||||
func (f *udpForwarder) cleanup() {
|
func (f *udpForwarder) cleanup() {
|
||||||
ticker := time.NewTicker(time.Minute)
|
ticker := time.NewTicker(time.Minute)
|
||||||
@@ -140,8 +125,6 @@ func (f *udpForwarder) cleanup() {
|
|||||||
f.Unlock()
|
f.Unlock()
|
||||||
|
|
||||||
f.logger.Trace("forwarder: cleaned up idle UDP connection %v", epID(idle.id))
|
f.logger.Trace("forwarder: cleaned up idle UDP connection %v", epID(idle.id))
|
||||||
|
|
||||||
f.sendUDPEvent(nftypes.TypeEnd, idle.conn.flowID, idle.id)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,18 +253,18 @@ func (f *Forwarder) proxyUDP(ctx context.Context, pConn *udpPacketConn, id stack
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sendUDPEvent stores flow events for UDP connections, mirrors the TCP version
|
// sendUDPEvent stores flow events for UDP connections
|
||||||
func (f *Forwarder) sendUDPEvent(typ nftypes.Type, flowID uuid.UUID, id stack.TransportEndpointID, ep tcpip.Endpoint) {
|
func (f *Forwarder) sendUDPEvent(typ nftypes.Type, flowID uuid.UUID, id stack.TransportEndpointID, ep tcpip.Endpoint) {
|
||||||
fields := nftypes.EventFields{
|
fields := nftypes.EventFields{
|
||||||
FlowID: flowID,
|
FlowID: flowID,
|
||||||
Type: typ,
|
Type: typ,
|
||||||
Direction: nftypes.Ingress,
|
Direction: nftypes.Ingress,
|
||||||
Protocol: 17, // UDP protocol number
|
Protocol: nftypes.UDP,
|
||||||
// TODO: handle ipv6
|
// TODO: handle ipv6
|
||||||
SourceIP: netip.AddrFrom4(id.LocalAddress.As4()),
|
SourceIP: netip.AddrFrom4(id.RemoteAddress.As4()),
|
||||||
DestIP: netip.AddrFrom4(id.RemoteAddress.As4()),
|
DestIP: netip.AddrFrom4(id.LocalAddress.As4()),
|
||||||
SourcePort: id.LocalPort,
|
SourcePort: id.RemotePort,
|
||||||
DestPort: id.RemotePort,
|
DestPort: id.LocalPort,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ep != nil {
|
if ep != nil {
|
||||||
|
|||||||
@@ -7,19 +7,19 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface"
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLocalIPManager(t *testing.T) {
|
func TestLocalIPManager(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
setupAddr iface.WGAddress
|
setupAddr wgaddr.Address
|
||||||
testIP netip.Addr
|
testIP netip.Addr
|
||||||
expected bool
|
expected bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Localhost range",
|
name: "Localhost range",
|
||||||
setupAddr: iface.WGAddress{
|
setupAddr: wgaddr.Address{
|
||||||
IP: net.ParseIP("192.168.1.1"),
|
IP: net.ParseIP("192.168.1.1"),
|
||||||
Network: &net.IPNet{
|
Network: &net.IPNet{
|
||||||
IP: net.ParseIP("192.168.1.0"),
|
IP: net.ParseIP("192.168.1.0"),
|
||||||
@@ -31,7 +31,7 @@ func TestLocalIPManager(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Localhost standard address",
|
name: "Localhost standard address",
|
||||||
setupAddr: iface.WGAddress{
|
setupAddr: wgaddr.Address{
|
||||||
IP: net.ParseIP("192.168.1.1"),
|
IP: net.ParseIP("192.168.1.1"),
|
||||||
Network: &net.IPNet{
|
Network: &net.IPNet{
|
||||||
IP: net.ParseIP("192.168.1.0"),
|
IP: net.ParseIP("192.168.1.0"),
|
||||||
@@ -43,7 +43,7 @@ func TestLocalIPManager(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Localhost range edge",
|
name: "Localhost range edge",
|
||||||
setupAddr: iface.WGAddress{
|
setupAddr: wgaddr.Address{
|
||||||
IP: net.ParseIP("192.168.1.1"),
|
IP: net.ParseIP("192.168.1.1"),
|
||||||
Network: &net.IPNet{
|
Network: &net.IPNet{
|
||||||
IP: net.ParseIP("192.168.1.0"),
|
IP: net.ParseIP("192.168.1.0"),
|
||||||
@@ -55,7 +55,7 @@ func TestLocalIPManager(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Local IP matches",
|
name: "Local IP matches",
|
||||||
setupAddr: iface.WGAddress{
|
setupAddr: wgaddr.Address{
|
||||||
IP: net.ParseIP("192.168.1.1"),
|
IP: net.ParseIP("192.168.1.1"),
|
||||||
Network: &net.IPNet{
|
Network: &net.IPNet{
|
||||||
IP: net.ParseIP("192.168.1.0"),
|
IP: net.ParseIP("192.168.1.0"),
|
||||||
@@ -67,7 +67,7 @@ func TestLocalIPManager(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Local IP doesn't match",
|
name: "Local IP doesn't match",
|
||||||
setupAddr: iface.WGAddress{
|
setupAddr: wgaddr.Address{
|
||||||
IP: net.ParseIP("192.168.1.1"),
|
IP: net.ParseIP("192.168.1.1"),
|
||||||
Network: &net.IPNet{
|
Network: &net.IPNet{
|
||||||
IP: net.ParseIP("192.168.1.0"),
|
IP: net.ParseIP("192.168.1.0"),
|
||||||
@@ -79,7 +79,7 @@ func TestLocalIPManager(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "IPv6 address",
|
name: "IPv6 address",
|
||||||
setupAddr: iface.WGAddress{
|
setupAddr: wgaddr.Address{
|
||||||
IP: net.ParseIP("fe80::1"),
|
IP: net.ParseIP("fe80::1"),
|
||||||
Network: &net.IPNet{
|
Network: &net.IPNet{
|
||||||
IP: net.ParseIP("fe80::"),
|
IP: net.ParseIP("fe80::"),
|
||||||
@@ -96,7 +96,7 @@ func TestLocalIPManager(t *testing.T) {
|
|||||||
manager := newLocalIPManager()
|
manager := newLocalIPManager()
|
||||||
|
|
||||||
mock := &IFaceMock{
|
mock := &IFaceMock{
|
||||||
AddressFunc: func() iface.WGAddress {
|
AddressFunc: func() wgaddr.Address {
|
||||||
return tt.setupAddr
|
return tt.setupAddr
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
fw "github.com/netbirdio/netbird/client/firewall/manager"
|
fw "github.com/netbirdio/netbird/client/firewall/manager"
|
||||||
"github.com/netbirdio/netbird/client/firewall/uspfilter/conntrack"
|
"github.com/netbirdio/netbird/client/firewall/uspfilter/conntrack"
|
||||||
"github.com/netbirdio/netbird/client/firewall/uspfilter/forwarder"
|
"github.com/netbirdio/netbird/client/firewall/uspfilter/forwarder"
|
||||||
"github.com/netbirdio/netbird/client/iface"
|
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
func verifyTraceStages(t *testing.T, trace *PacketTrace, expectedStages []PacketStage) {
|
func verifyTraceStages(t *testing.T, trace *PacketTrace, expectedStages []PacketStage) {
|
||||||
@@ -36,8 +36,8 @@ func TestTracePacket(t *testing.T) {
|
|||||||
setupTracerTest := func(statefulMode bool) *Manager {
|
setupTracerTest := func(statefulMode bool) *Manager {
|
||||||
ifaceMock := &IFaceMock{
|
ifaceMock := &IFaceMock{
|
||||||
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
||||||
AddressFunc: func() iface.WGAddress {
|
AddressFunc: func() wgaddr.Address {
|
||||||
return iface.WGAddress{
|
return wgaddr.Address{
|
||||||
IP: net.ParseIP("100.10.0.100"),
|
IP: net.ParseIP("100.10.0.100"),
|
||||||
Network: &net.IPNet{
|
Network: &net.IPNet{
|
||||||
IP: net.ParseIP("100.10.0.0"),
|
IP: net.ParseIP("100.10.0.0"),
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ func BenchmarkCoreFiltering(b *testing.B) {
|
|||||||
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
||||||
}, false, flowLogger)
|
}, false, flowLogger)
|
||||||
defer b.Cleanup(func() {
|
defer b.Cleanup(func() {
|
||||||
require.NoError(b, manager.Reset(nil))
|
require.NoError(b, manager.Close(nil))
|
||||||
})
|
})
|
||||||
|
|
||||||
manager.wgNetwork = &net.IPNet{
|
manager.wgNetwork = &net.IPNet{
|
||||||
@@ -216,7 +216,7 @@ func BenchmarkStateScaling(b *testing.B) {
|
|||||||
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
||||||
}, false, flowLogger)
|
}, false, flowLogger)
|
||||||
b.Cleanup(func() {
|
b.Cleanup(func() {
|
||||||
require.NoError(b, manager.Reset(nil))
|
require.NoError(b, manager.Close(nil))
|
||||||
})
|
})
|
||||||
|
|
||||||
manager.wgNetwork = &net.IPNet{
|
manager.wgNetwork = &net.IPNet{
|
||||||
@@ -264,7 +264,7 @@ func BenchmarkEstablishmentOverhead(b *testing.B) {
|
|||||||
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
||||||
}, false, flowLogger)
|
}, false, flowLogger)
|
||||||
b.Cleanup(func() {
|
b.Cleanup(func() {
|
||||||
require.NoError(b, manager.Reset(nil))
|
require.NoError(b, manager.Close(nil))
|
||||||
})
|
})
|
||||||
|
|
||||||
manager.wgNetwork = &net.IPNet{
|
manager.wgNetwork = &net.IPNet{
|
||||||
@@ -463,7 +463,7 @@ func BenchmarkRoutedNetworkReturn(b *testing.B) {
|
|||||||
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
||||||
}, false, flowLogger)
|
}, false, flowLogger)
|
||||||
b.Cleanup(func() {
|
b.Cleanup(func() {
|
||||||
require.NoError(b, manager.Reset(nil))
|
require.NoError(b, manager.Close(nil))
|
||||||
})
|
})
|
||||||
|
|
||||||
// Setup scenario
|
// Setup scenario
|
||||||
@@ -590,7 +590,7 @@ func BenchmarkLongLivedConnections(b *testing.B) {
|
|||||||
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
||||||
}, false, flowLogger)
|
}, false, flowLogger)
|
||||||
defer b.Cleanup(func() {
|
defer b.Cleanup(func() {
|
||||||
require.NoError(b, manager.Reset(nil))
|
require.NoError(b, manager.Close(nil))
|
||||||
})
|
})
|
||||||
|
|
||||||
manager.SetNetwork(&net.IPNet{
|
manager.SetNetwork(&net.IPNet{
|
||||||
@@ -678,7 +678,7 @@ func BenchmarkShortLivedConnections(b *testing.B) {
|
|||||||
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
||||||
}, false, flowLogger)
|
}, false, flowLogger)
|
||||||
defer b.Cleanup(func() {
|
defer b.Cleanup(func() {
|
||||||
require.NoError(b, manager.Reset(nil))
|
require.NoError(b, manager.Close(nil))
|
||||||
})
|
})
|
||||||
|
|
||||||
manager.SetNetwork(&net.IPNet{
|
manager.SetNetwork(&net.IPNet{
|
||||||
@@ -794,7 +794,7 @@ func BenchmarkParallelLongLivedConnections(b *testing.B) {
|
|||||||
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
||||||
}, false, flowLogger)
|
}, false, flowLogger)
|
||||||
defer b.Cleanup(func() {
|
defer b.Cleanup(func() {
|
||||||
require.NoError(b, manager.Reset(nil))
|
require.NoError(b, manager.Close(nil))
|
||||||
})
|
})
|
||||||
|
|
||||||
manager.SetNetwork(&net.IPNet{
|
manager.SetNetwork(&net.IPNet{
|
||||||
@@ -879,7 +879,7 @@ func BenchmarkParallelShortLivedConnections(b *testing.B) {
|
|||||||
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
||||||
}, false, flowLogger)
|
}, false, flowLogger)
|
||||||
defer b.Cleanup(func() {
|
defer b.Cleanup(func() {
|
||||||
require.NoError(b, manager.Reset(nil))
|
require.NoError(b, manager.Close(nil))
|
||||||
})
|
})
|
||||||
|
|
||||||
manager.SetNetwork(&net.IPNet{
|
manager.SetNetwork(&net.IPNet{
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ import (
|
|||||||
wgdevice "golang.zx2c4.com/wireguard/device"
|
wgdevice "golang.zx2c4.com/wireguard/device"
|
||||||
|
|
||||||
fw "github.com/netbirdio/netbird/client/firewall/manager"
|
fw "github.com/netbirdio/netbird/client/firewall/manager"
|
||||||
"github.com/netbirdio/netbird/client/iface"
|
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
"github.com/netbirdio/netbird/client/iface/mocks"
|
"github.com/netbirdio/netbird/client/iface/mocks"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPeerACLFiltering(t *testing.T) {
|
func TestPeerACLFiltering(t *testing.T) {
|
||||||
@@ -26,8 +26,8 @@ func TestPeerACLFiltering(t *testing.T) {
|
|||||||
|
|
||||||
ifaceMock := &IFaceMock{
|
ifaceMock := &IFaceMock{
|
||||||
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
||||||
AddressFunc: func() iface.WGAddress {
|
AddressFunc: func() wgaddr.Address {
|
||||||
return iface.WGAddress{
|
return wgaddr.Address{
|
||||||
IP: localIP,
|
IP: localIP,
|
||||||
Network: wgNet,
|
Network: wgNet,
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@ func TestPeerACLFiltering(t *testing.T) {
|
|||||||
require.NotNil(t, manager)
|
require.NotNil(t, manager)
|
||||||
|
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
require.NoError(t, manager.Reset(nil))
|
require.NoError(t, manager.Close(nil))
|
||||||
})
|
})
|
||||||
|
|
||||||
manager.wgNetwork = wgNet
|
manager.wgNetwork = wgNet
|
||||||
@@ -288,8 +288,8 @@ func setupRoutedManager(tb testing.TB, network string) *Manager {
|
|||||||
|
|
||||||
ifaceMock := &IFaceMock{
|
ifaceMock := &IFaceMock{
|
||||||
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
||||||
AddressFunc: func() iface.WGAddress {
|
AddressFunc: func() wgaddr.Address {
|
||||||
return iface.WGAddress{
|
return wgaddr.Address{
|
||||||
IP: localIP,
|
IP: localIP,
|
||||||
Network: wgNet,
|
Network: wgNet,
|
||||||
}
|
}
|
||||||
@@ -310,7 +310,7 @@ func setupRoutedManager(tb testing.TB, network string) *Manager {
|
|||||||
require.False(tb, manager.nativeRouter.Load())
|
require.False(tb, manager.nativeRouter.Load())
|
||||||
|
|
||||||
tb.Cleanup(func() {
|
tb.Cleanup(func() {
|
||||||
require.NoError(tb, manager.Reset(nil))
|
require.NoError(tb, manager.Close(nil))
|
||||||
})
|
})
|
||||||
|
|
||||||
return manager
|
return manager
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ import (
|
|||||||
fw "github.com/netbirdio/netbird/client/firewall/manager"
|
fw "github.com/netbirdio/netbird/client/firewall/manager"
|
||||||
"github.com/netbirdio/netbird/client/firewall/uspfilter/conntrack"
|
"github.com/netbirdio/netbird/client/firewall/uspfilter/conntrack"
|
||||||
"github.com/netbirdio/netbird/client/firewall/uspfilter/log"
|
"github.com/netbirdio/netbird/client/firewall/uspfilter/log"
|
||||||
"github.com/netbirdio/netbird/client/iface"
|
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/client/internal/netflow"
|
"github.com/netbirdio/netbird/client/internal/netflow"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ var flowLogger = netflow.NewManager(context.Background(), nil, []byte{}, nil).Ge
|
|||||||
|
|
||||||
type IFaceMock struct {
|
type IFaceMock struct {
|
||||||
SetFilterFunc func(device.PacketFilter) error
|
SetFilterFunc func(device.PacketFilter) error
|
||||||
AddressFunc func() iface.WGAddress
|
AddressFunc func() wgaddr.Address
|
||||||
GetWGDeviceFunc func() *wgdevice.Device
|
GetWGDeviceFunc func() *wgdevice.Device
|
||||||
GetDeviceFunc func() *device.FilteredDevice
|
GetDeviceFunc func() *device.FilteredDevice
|
||||||
}
|
}
|
||||||
@@ -54,9 +54,9 @@ func (i *IFaceMock) SetFilter(iface device.PacketFilter) error {
|
|||||||
return i.SetFilterFunc(iface)
|
return i.SetFilterFunc(iface)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *IFaceMock) Address() iface.WGAddress {
|
func (i *IFaceMock) Address() wgaddr.Address {
|
||||||
if i.AddressFunc == nil {
|
if i.AddressFunc == nil {
|
||||||
return iface.WGAddress{}
|
return wgaddr.Address{}
|
||||||
}
|
}
|
||||||
return i.AddressFunc()
|
return i.AddressFunc()
|
||||||
}
|
}
|
||||||
@@ -255,7 +255,7 @@ func TestManagerReset(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = m.Reset(nil)
|
err = m.Close(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to reset Manager: %v", err)
|
t.Errorf("failed to reset Manager: %v", err)
|
||||||
return
|
return
|
||||||
@@ -269,8 +269,8 @@ func TestManagerReset(t *testing.T) {
|
|||||||
func TestNotMatchByIP(t *testing.T) {
|
func TestNotMatchByIP(t *testing.T) {
|
||||||
ifaceMock := &IFaceMock{
|
ifaceMock := &IFaceMock{
|
||||||
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
SetFilterFunc: func(device.PacketFilter) error { return nil },
|
||||||
AddressFunc: func() iface.WGAddress {
|
AddressFunc: func() wgaddr.Address {
|
||||||
return iface.WGAddress{
|
return wgaddr.Address{
|
||||||
IP: net.ParseIP("100.10.0.100"),
|
IP: net.ParseIP("100.10.0.100"),
|
||||||
Network: &net.IPNet{
|
Network: &net.IPNet{
|
||||||
IP: net.ParseIP("100.10.0.0"),
|
IP: net.ParseIP("100.10.0.0"),
|
||||||
@@ -333,7 +333,7 @@ func TestNotMatchByIP(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = m.Reset(nil); err != nil {
|
if err = m.Close(nil); err != nil {
|
||||||
t.Errorf("failed to reset Manager: %v", err)
|
t.Errorf("failed to reset Manager: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -352,7 +352,7 @@ func TestRemovePacketHook(t *testing.T) {
|
|||||||
t.Fatalf("Failed to create Manager: %s", err)
|
t.Fatalf("Failed to create Manager: %s", err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
require.NoError(t, manager.Reset(nil))
|
require.NoError(t, manager.Close(nil))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Add a UDP packet hook
|
// Add a UDP packet hook
|
||||||
@@ -403,7 +403,7 @@ func TestProcessOutgoingHooks(t *testing.T) {
|
|||||||
manager.udpTracker.Close()
|
manager.udpTracker.Close()
|
||||||
manager.udpTracker = conntrack.NewUDPTracker(100*time.Millisecond, logger, flowLogger)
|
manager.udpTracker = conntrack.NewUDPTracker(100*time.Millisecond, logger, flowLogger)
|
||||||
defer func() {
|
defer func() {
|
||||||
require.NoError(t, manager.Reset(nil))
|
require.NoError(t, manager.Close(nil))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
manager.decoders = sync.Pool{
|
manager.decoders = sync.Pool{
|
||||||
@@ -484,7 +484,7 @@ func TestUSPFilterCreatePerformance(t *testing.T) {
|
|||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := manager.Reset(nil); err != nil {
|
if err := manager.Close(nil); err != nil {
|
||||||
t.Errorf("clear the manager state: %v", err)
|
t.Errorf("clear the manager state: %v", err)
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
@@ -530,7 +530,7 @@ func TestStatefulFirewall_UDPTracking(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
require.NoError(t, manager.Reset(nil))
|
require.NoError(t, manager.Close(nil))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Set up packet parameters
|
// Set up packet parameters
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/pion/stun/v2"
|
"github.com/pion/stun/v2"
|
||||||
@@ -14,6 +13,8 @@ import (
|
|||||||
"golang.org/x/net/ipv4"
|
"golang.org/x/net/ipv4"
|
||||||
"golang.org/x/net/ipv6"
|
"golang.org/x/net/ipv6"
|
||||||
wgConn "golang.zx2c4.com/wireguard/conn"
|
wgConn "golang.zx2c4.com/wireguard/conn"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RecvMessage struct {
|
type RecvMessage struct {
|
||||||
@@ -52,9 +53,10 @@ type ICEBind struct {
|
|||||||
|
|
||||||
muUDPMux sync.Mutex
|
muUDPMux sync.Mutex
|
||||||
udpMux *UniversalUDPMuxDefault
|
udpMux *UniversalUDPMuxDefault
|
||||||
|
address wgaddr.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewICEBind(transportNet transport.Net, filterFn FilterFn) *ICEBind {
|
func NewICEBind(transportNet transport.Net, filterFn FilterFn, address wgaddr.Address) *ICEBind {
|
||||||
b, _ := wgConn.NewStdNetBind().(*wgConn.StdNetBind)
|
b, _ := wgConn.NewStdNetBind().(*wgConn.StdNetBind)
|
||||||
ib := &ICEBind{
|
ib := &ICEBind{
|
||||||
StdNetBind: b,
|
StdNetBind: b,
|
||||||
@@ -64,6 +66,7 @@ func NewICEBind(transportNet transport.Net, filterFn FilterFn) *ICEBind {
|
|||||||
endpoints: make(map[netip.Addr]net.Conn),
|
endpoints: make(map[netip.Addr]net.Conn),
|
||||||
closedChan: make(chan struct{}),
|
closedChan: make(chan struct{}),
|
||||||
closed: true,
|
closed: true,
|
||||||
|
address: address,
|
||||||
}
|
}
|
||||||
|
|
||||||
rc := receiverCreator{
|
rc := receiverCreator{
|
||||||
@@ -108,35 +111,17 @@ func (s *ICEBind) GetICEMux() (*UniversalUDPMuxDefault, error) {
|
|||||||
return s.udpMux, nil
|
return s.udpMux, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *ICEBind) SetEndpoint(peerAddress *net.UDPAddr, conn net.Conn) (*net.UDPAddr, error) {
|
func (b *ICEBind) SetEndpoint(fakeIP netip.Addr, conn net.Conn) {
|
||||||
fakeUDPAddr, err := fakeAddress(peerAddress)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// force IPv4
|
|
||||||
fakeAddr, ok := netip.AddrFromSlice(fakeUDPAddr.IP.To4())
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("failed to convert IP to netip.Addr")
|
|
||||||
}
|
|
||||||
|
|
||||||
b.endpointsMu.Lock()
|
b.endpointsMu.Lock()
|
||||||
b.endpoints[fakeAddr] = conn
|
b.endpoints[fakeIP] = conn
|
||||||
b.endpointsMu.Unlock()
|
b.endpointsMu.Unlock()
|
||||||
|
|
||||||
return fakeUDPAddr, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *ICEBind) RemoveEndpoint(fakeUDPAddr *net.UDPAddr) {
|
func (b *ICEBind) RemoveEndpoint(fakeIP netip.Addr) {
|
||||||
fakeAddr, ok := netip.AddrFromSlice(fakeUDPAddr.IP.To4())
|
|
||||||
if !ok {
|
|
||||||
log.Warnf("failed to convert IP to netip.Addr")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
b.endpointsMu.Lock()
|
b.endpointsMu.Lock()
|
||||||
defer b.endpointsMu.Unlock()
|
defer b.endpointsMu.Unlock()
|
||||||
delete(b.endpoints, fakeAddr)
|
|
||||||
|
delete(b.endpoints, fakeIP)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *ICEBind) Send(bufs [][]byte, ep wgConn.Endpoint) error {
|
func (b *ICEBind) Send(bufs [][]byte, ep wgConn.Endpoint) error {
|
||||||
@@ -161,9 +146,10 @@ func (s *ICEBind) createIPv4ReceiverFn(pc *ipv4.PacketConn, conn *net.UDPConn, r
|
|||||||
|
|
||||||
s.udpMux = NewUniversalUDPMuxDefault(
|
s.udpMux = NewUniversalUDPMuxDefault(
|
||||||
UniversalUDPMuxParams{
|
UniversalUDPMuxParams{
|
||||||
UDPConn: conn,
|
UDPConn: conn,
|
||||||
Net: s.transportNet,
|
Net: s.transportNet,
|
||||||
FilterFn: s.filterFn,
|
FilterFn: s.filterFn,
|
||||||
|
WGAddress: s.address,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return func(bufs [][]byte, sizes []int, eps []wgConn.Endpoint) (n int, err error) {
|
return func(bufs [][]byte, sizes []int, eps []wgConn.Endpoint) (n int, err error) {
|
||||||
@@ -275,21 +261,6 @@ func (c *ICEBind) receiveRelayed(buffs [][]byte, sizes []int, eps []wgConn.Endpo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fakeAddress returns a fake address that is used to as an identifier for the peer.
|
|
||||||
// The fake address is in the format of 127.1.x.x where x.x is the last two octets of the peer address.
|
|
||||||
func fakeAddress(peerAddress *net.UDPAddr) (*net.UDPAddr, error) {
|
|
||||||
octets := strings.Split(peerAddress.IP.String(), ".")
|
|
||||||
if len(octets) != 4 {
|
|
||||||
return nil, fmt.Errorf("invalid IP format")
|
|
||||||
}
|
|
||||||
|
|
||||||
newAddr := &net.UDPAddr{
|
|
||||||
IP: net.ParseIP(fmt.Sprintf("127.1.%s.%s", octets[2], octets[3])),
|
|
||||||
Port: peerAddress.Port,
|
|
||||||
}
|
|
||||||
return newAddr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMessages(msgsPool *sync.Pool) *[]ipv6.Message {
|
func getMessages(msgsPool *sync.Pool) *[]ipv6.Message {
|
||||||
return msgsPool.Get().(*[]ipv6.Message)
|
return msgsPool.Get().(*[]ipv6.Message)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import (
|
|||||||
"github.com/pion/logging"
|
"github.com/pion/logging"
|
||||||
"github.com/pion/stun/v2"
|
"github.com/pion/stun/v2"
|
||||||
"github.com/pion/transport/v3"
|
"github.com/pion/transport/v3"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FilterFn is a function that filters out candidates based on the address.
|
// FilterFn is a function that filters out candidates based on the address.
|
||||||
@@ -41,6 +43,7 @@ type UniversalUDPMuxParams struct {
|
|||||||
XORMappedAddrCacheTTL time.Duration
|
XORMappedAddrCacheTTL time.Duration
|
||||||
Net transport.Net
|
Net transport.Net
|
||||||
FilterFn FilterFn
|
FilterFn FilterFn
|
||||||
|
WGAddress wgaddr.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUniversalUDPMuxDefault creates an implementation of UniversalUDPMux embedding UDPMux
|
// NewUniversalUDPMuxDefault creates an implementation of UniversalUDPMux embedding UDPMux
|
||||||
@@ -64,6 +67,7 @@ func NewUniversalUDPMuxDefault(params UniversalUDPMuxParams) *UniversalUDPMuxDef
|
|||||||
mux: m,
|
mux: m,
|
||||||
logger: params.Logger,
|
logger: params.Logger,
|
||||||
filterFn: params.FilterFn,
|
filterFn: params.FilterFn,
|
||||||
|
address: params.WGAddress,
|
||||||
}
|
}
|
||||||
|
|
||||||
// embed UDPMux
|
// embed UDPMux
|
||||||
@@ -118,6 +122,7 @@ type udpConn struct {
|
|||||||
filterFn FilterFn
|
filterFn FilterFn
|
||||||
// TODO: reset cache on route changes
|
// TODO: reset cache on route changes
|
||||||
addrCache sync.Map
|
addrCache sync.Map
|
||||||
|
address wgaddr.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *udpConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
func (u *udpConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
||||||
@@ -159,6 +164,11 @@ func (u *udpConn) performFilterCheck(addr net.Addr) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if u.address.Network.Contains(a.AsSlice()) {
|
||||||
|
log.Warnf("Address %s is part of the NetBird network %s, refusing to write", addr, u.address)
|
||||||
|
return fmt.Errorf("address %s is part of the NetBird network %s, refusing to write", addr, u.address)
|
||||||
|
}
|
||||||
|
|
||||||
if isRouted, prefix, err := u.filterFn(a); err != nil {
|
if isRouted, prefix, err := u.filterFn(a); err != nil {
|
||||||
log.Errorf("Failed to check if address %s is routed: %v", addr, err)
|
log.Errorf("Failed to check if address %s is routed: %v", addr, err)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -9,13 +9,14 @@ import (
|
|||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WGTunDevice interface {
|
type WGTunDevice interface {
|
||||||
Create() (device.WGConfigurer, error)
|
Create() (device.WGConfigurer, error)
|
||||||
Up() (*bind.UniversalUDPMuxDefault, error)
|
Up() (*bind.UniversalUDPMuxDefault, error)
|
||||||
UpdateAddr(address WGAddress) error
|
UpdateAddr(address wgaddr.Address) error
|
||||||
WgAddress() WGAddress
|
WgAddress() wgaddr.Address
|
||||||
DeviceName() string
|
DeviceName() string
|
||||||
Close() error
|
Close() error
|
||||||
FilteredDevice() *device.FilteredDevice
|
FilteredDevice() *device.FilteredDevice
|
||||||
|
|||||||
@@ -13,11 +13,12 @@ import (
|
|||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/configurer"
|
"github.com/netbirdio/netbird/client/iface/configurer"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WGTunDevice ignore the WGTunDevice interface on Android because the creation of the tun device is different on this platform
|
// WGTunDevice ignore the WGTunDevice interface on Android because the creation of the tun device is different on this platform
|
||||||
type WGTunDevice struct {
|
type WGTunDevice struct {
|
||||||
address WGAddress
|
address wgaddr.Address
|
||||||
port int
|
port int
|
||||||
key string
|
key string
|
||||||
mtu int
|
mtu int
|
||||||
@@ -31,7 +32,7 @@ type WGTunDevice struct {
|
|||||||
configurer WGConfigurer
|
configurer WGConfigurer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTunDevice(address WGAddress, port int, key string, mtu int, iceBind *bind.ICEBind, tunAdapter TunAdapter) *WGTunDevice {
|
func NewTunDevice(address wgaddr.Address, port int, key string, mtu int, iceBind *bind.ICEBind, tunAdapter TunAdapter) *WGTunDevice {
|
||||||
return &WGTunDevice{
|
return &WGTunDevice{
|
||||||
address: address,
|
address: address,
|
||||||
port: port,
|
port: port,
|
||||||
@@ -93,7 +94,7 @@ func (t *WGTunDevice) Up() (*bind.UniversalUDPMuxDefault, error) {
|
|||||||
return udpMux, nil
|
return udpMux, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *WGTunDevice) UpdateAddr(addr WGAddress) error {
|
func (t *WGTunDevice) UpdateAddr(addr wgaddr.Address) error {
|
||||||
// todo implement
|
// todo implement
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -123,7 +124,7 @@ func (t *WGTunDevice) DeviceName() string {
|
|||||||
return t.name
|
return t.name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *WGTunDevice) WgAddress() WGAddress {
|
func (t *WGTunDevice) WgAddress() wgaddr.Address {
|
||||||
return t.address
|
return t.address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,11 +13,12 @@ import (
|
|||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/configurer"
|
"github.com/netbirdio/netbird/client/iface/configurer"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TunDevice struct {
|
type TunDevice struct {
|
||||||
name string
|
name string
|
||||||
address WGAddress
|
address wgaddr.Address
|
||||||
port int
|
port int
|
||||||
key string
|
key string
|
||||||
mtu int
|
mtu int
|
||||||
@@ -29,7 +30,7 @@ type TunDevice struct {
|
|||||||
configurer WGConfigurer
|
configurer WGConfigurer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTunDevice(name string, address WGAddress, port int, key string, mtu int, iceBind *bind.ICEBind) *TunDevice {
|
func NewTunDevice(name string, address wgaddr.Address, port int, key string, mtu int, iceBind *bind.ICEBind) *TunDevice {
|
||||||
return &TunDevice{
|
return &TunDevice{
|
||||||
name: name,
|
name: name,
|
||||||
address: address,
|
address: address,
|
||||||
@@ -85,7 +86,7 @@ func (t *TunDevice) Up() (*bind.UniversalUDPMuxDefault, error) {
|
|||||||
return udpMux, nil
|
return udpMux, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunDevice) UpdateAddr(address WGAddress) error {
|
func (t *TunDevice) UpdateAddr(address wgaddr.Address) error {
|
||||||
t.address = address
|
t.address = address
|
||||||
return t.assignAddr()
|
return t.assignAddr()
|
||||||
}
|
}
|
||||||
@@ -106,7 +107,7 @@ func (t *TunDevice) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunDevice) WgAddress() WGAddress {
|
func (t *TunDevice) WgAddress() wgaddr.Address {
|
||||||
return t.address
|
return t.address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,11 +14,12 @@ import (
|
|||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/configurer"
|
"github.com/netbirdio/netbird/client/iface/configurer"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TunDevice struct {
|
type TunDevice struct {
|
||||||
name string
|
name string
|
||||||
address WGAddress
|
address wgaddr.Address
|
||||||
port int
|
port int
|
||||||
key string
|
key string
|
||||||
iceBind *bind.ICEBind
|
iceBind *bind.ICEBind
|
||||||
@@ -30,7 +31,7 @@ type TunDevice struct {
|
|||||||
configurer WGConfigurer
|
configurer WGConfigurer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTunDevice(name string, address WGAddress, port int, key string, iceBind *bind.ICEBind, tunFd int) *TunDevice {
|
func NewTunDevice(name string, address wgaddr.Address, port int, key string, iceBind *bind.ICEBind, tunFd int) *TunDevice {
|
||||||
return &TunDevice{
|
return &TunDevice{
|
||||||
name: name,
|
name: name,
|
||||||
address: address,
|
address: address,
|
||||||
@@ -120,11 +121,11 @@ func (t *TunDevice) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunDevice) WgAddress() WGAddress {
|
func (t *TunDevice) WgAddress() wgaddr.Address {
|
||||||
return t.address
|
return t.address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunDevice) UpdateAddr(addr WGAddress) error {
|
func (t *TunDevice) UpdateAddr(_ wgaddr.Address) error {
|
||||||
// todo implement
|
// todo implement
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,13 @@ import (
|
|||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/configurer"
|
"github.com/netbirdio/netbird/client/iface/configurer"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/sharedsock"
|
"github.com/netbirdio/netbird/sharedsock"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TunKernelDevice struct {
|
type TunKernelDevice struct {
|
||||||
name string
|
name string
|
||||||
address WGAddress
|
address wgaddr.Address
|
||||||
wgPort int
|
wgPort int
|
||||||
key string
|
key string
|
||||||
mtu int
|
mtu int
|
||||||
@@ -34,7 +35,7 @@ type TunKernelDevice struct {
|
|||||||
filterFn bind.FilterFn
|
filterFn bind.FilterFn
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewKernelDevice(name string, address WGAddress, wgPort int, key string, mtu int, transportNet transport.Net) *TunKernelDevice {
|
func NewKernelDevice(name string, address wgaddr.Address, wgPort int, key string, mtu int, transportNet transport.Net) *TunKernelDevice {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
return &TunKernelDevice{
|
return &TunKernelDevice{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
@@ -99,9 +100,10 @@ func (t *TunKernelDevice) Up() (*bind.UniversalUDPMuxDefault, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
bindParams := bind.UniversalUDPMuxParams{
|
bindParams := bind.UniversalUDPMuxParams{
|
||||||
UDPConn: rawSock,
|
UDPConn: rawSock,
|
||||||
Net: t.transportNet,
|
Net: t.transportNet,
|
||||||
FilterFn: t.filterFn,
|
FilterFn: t.filterFn,
|
||||||
|
WGAddress: t.address,
|
||||||
}
|
}
|
||||||
mux := bind.NewUniversalUDPMuxDefault(bindParams)
|
mux := bind.NewUniversalUDPMuxDefault(bindParams)
|
||||||
go mux.ReadFromConn(t.ctx)
|
go mux.ReadFromConn(t.ctx)
|
||||||
@@ -112,7 +114,7 @@ func (t *TunKernelDevice) Up() (*bind.UniversalUDPMuxDefault, error) {
|
|||||||
return t.udpMux, nil
|
return t.udpMux, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunKernelDevice) UpdateAddr(address WGAddress) error {
|
func (t *TunKernelDevice) UpdateAddr(address wgaddr.Address) error {
|
||||||
t.address = address
|
t.address = address
|
||||||
return t.assignAddr()
|
return t.assignAddr()
|
||||||
}
|
}
|
||||||
@@ -145,7 +147,7 @@ func (t *TunKernelDevice) Close() error {
|
|||||||
return closErr
|
return closErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunKernelDevice) WgAddress() WGAddress {
|
func (t *TunKernelDevice) WgAddress() wgaddr.Address {
|
||||||
return t.address
|
return t.address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,12 +13,13 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/configurer"
|
"github.com/netbirdio/netbird/client/iface/configurer"
|
||||||
nbnetstack "github.com/netbirdio/netbird/client/iface/netstack"
|
nbnetstack "github.com/netbirdio/netbird/client/iface/netstack"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
nbnet "github.com/netbirdio/netbird/util/net"
|
nbnet "github.com/netbirdio/netbird/util/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TunNetstackDevice struct {
|
type TunNetstackDevice struct {
|
||||||
name string
|
name string
|
||||||
address WGAddress
|
address wgaddr.Address
|
||||||
port int
|
port int
|
||||||
key string
|
key string
|
||||||
mtu int
|
mtu int
|
||||||
@@ -34,7 +35,7 @@ type TunNetstackDevice struct {
|
|||||||
net *netstack.Net
|
net *netstack.Net
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNetstackDevice(name string, address WGAddress, wgPort int, key string, mtu int, iceBind *bind.ICEBind, listenAddress string) *TunNetstackDevice {
|
func NewNetstackDevice(name string, address wgaddr.Address, wgPort int, key string, mtu int, iceBind *bind.ICEBind, listenAddress string) *TunNetstackDevice {
|
||||||
return &TunNetstackDevice{
|
return &TunNetstackDevice{
|
||||||
name: name,
|
name: name,
|
||||||
address: address,
|
address: address,
|
||||||
@@ -97,7 +98,7 @@ func (t *TunNetstackDevice) Up() (*bind.UniversalUDPMuxDefault, error) {
|
|||||||
return udpMux, nil
|
return udpMux, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunNetstackDevice) UpdateAddr(WGAddress) error {
|
func (t *TunNetstackDevice) UpdateAddr(wgaddr.Address) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +117,7 @@ func (t *TunNetstackDevice) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunNetstackDevice) WgAddress() WGAddress {
|
func (t *TunNetstackDevice) WgAddress() wgaddr.Address {
|
||||||
return t.address
|
return t.address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,12 @@ import (
|
|||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/configurer"
|
"github.com/netbirdio/netbird/client/iface/configurer"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
type USPDevice struct {
|
type USPDevice struct {
|
||||||
name string
|
name string
|
||||||
address WGAddress
|
address wgaddr.Address
|
||||||
port int
|
port int
|
||||||
key string
|
key string
|
||||||
mtu int
|
mtu int
|
||||||
@@ -28,7 +29,7 @@ type USPDevice struct {
|
|||||||
configurer WGConfigurer
|
configurer WGConfigurer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUSPDevice(name string, address WGAddress, port int, key string, mtu int, iceBind *bind.ICEBind) *USPDevice {
|
func NewUSPDevice(name string, address wgaddr.Address, port int, key string, mtu int, iceBind *bind.ICEBind) *USPDevice {
|
||||||
log.Infof("using userspace bind mode")
|
log.Infof("using userspace bind mode")
|
||||||
|
|
||||||
return &USPDevice{
|
return &USPDevice{
|
||||||
@@ -93,7 +94,7 @@ func (t *USPDevice) Up() (*bind.UniversalUDPMuxDefault, error) {
|
|||||||
return udpMux, nil
|
return udpMux, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *USPDevice) UpdateAddr(address WGAddress) error {
|
func (t *USPDevice) UpdateAddr(address wgaddr.Address) error {
|
||||||
t.address = address
|
t.address = address
|
||||||
return t.assignAddr()
|
return t.assignAddr()
|
||||||
}
|
}
|
||||||
@@ -113,7 +114,7 @@ func (t *USPDevice) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *USPDevice) WgAddress() WGAddress {
|
func (t *USPDevice) WgAddress() wgaddr.Address {
|
||||||
return t.address
|
return t.address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,13 +13,14 @@ import (
|
|||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/configurer"
|
"github.com/netbirdio/netbird/client/iface/configurer"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultWindowsGUIDSTring = "{f2f29e61-d91f-4d76-8151-119b20c4bdeb}"
|
const defaultWindowsGUIDSTring = "{f2f29e61-d91f-4d76-8151-119b20c4bdeb}"
|
||||||
|
|
||||||
type TunDevice struct {
|
type TunDevice struct {
|
||||||
name string
|
name string
|
||||||
address WGAddress
|
address wgaddr.Address
|
||||||
port int
|
port int
|
||||||
key string
|
key string
|
||||||
mtu int
|
mtu int
|
||||||
@@ -32,7 +33,7 @@ type TunDevice struct {
|
|||||||
configurer WGConfigurer
|
configurer WGConfigurer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTunDevice(name string, address WGAddress, port int, key string, mtu int, iceBind *bind.ICEBind) *TunDevice {
|
func NewTunDevice(name string, address wgaddr.Address, port int, key string, mtu int, iceBind *bind.ICEBind) *TunDevice {
|
||||||
return &TunDevice{
|
return &TunDevice{
|
||||||
name: name,
|
name: name,
|
||||||
address: address,
|
address: address,
|
||||||
@@ -118,7 +119,7 @@ func (t *TunDevice) Up() (*bind.UniversalUDPMuxDefault, error) {
|
|||||||
return udpMux, nil
|
return udpMux, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunDevice) UpdateAddr(address WGAddress) error {
|
func (t *TunDevice) UpdateAddr(address wgaddr.Address) error {
|
||||||
t.address = address
|
t.address = address
|
||||||
return t.assignAddr()
|
return t.assignAddr()
|
||||||
}
|
}
|
||||||
@@ -139,7 +140,7 @@ func (t *TunDevice) Close() error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (t *TunDevice) WgAddress() WGAddress {
|
func (t *TunDevice) WgAddress() wgaddr.Address {
|
||||||
return t.address
|
return t.address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface/freebsd"
|
"github.com/netbirdio/netbird/client/iface/freebsd"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
type wgLink struct {
|
type wgLink struct {
|
||||||
@@ -56,7 +57,7 @@ func (l *wgLink) up() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *wgLink) assignAddr(address WGAddress) error {
|
func (l *wgLink) assignAddr(address wgaddr.Address) error {
|
||||||
link, err := freebsd.LinkByName(l.name)
|
link, err := freebsd.LinkByName(l.name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("link by name: %w", err)
|
return fmt.Errorf("link by name: %w", err)
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
type wgLink struct {
|
type wgLink struct {
|
||||||
@@ -90,7 +92,7 @@ func (l *wgLink) up() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *wgLink) assignAddr(address WGAddress) error {
|
func (l *wgLink) assignAddr(address wgaddr.Address) error {
|
||||||
//delete existing addresses
|
//delete existing addresses
|
||||||
list, err := netlink.AddrList(l, 0)
|
list, err := netlink.AddrList(l, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -7,13 +7,14 @@ import (
|
|||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WGTunDevice interface {
|
type WGTunDevice interface {
|
||||||
Create(routes []string, dns string, searchDomains []string) (device.WGConfigurer, error)
|
Create(routes []string, dns string, searchDomains []string) (device.WGConfigurer, error)
|
||||||
Up() (*bind.UniversalUDPMuxDefault, error)
|
Up() (*bind.UniversalUDPMuxDefault, error)
|
||||||
UpdateAddr(address WGAddress) error
|
UpdateAddr(address wgaddr.Address) error
|
||||||
WgAddress() WGAddress
|
WgAddress() wgaddr.Address
|
||||||
DeviceName() string
|
DeviceName() string
|
||||||
Close() error
|
Close() error
|
||||||
FilteredDevice() *device.FilteredDevice
|
FilteredDevice() *device.FilteredDevice
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/configurer"
|
"github.com/netbirdio/netbird/client/iface/configurer"
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,8 +29,6 @@ const (
|
|||||||
WgInterfaceDefault = configurer.WgInterfaceDefault
|
WgInterfaceDefault = configurer.WgInterfaceDefault
|
||||||
)
|
)
|
||||||
|
|
||||||
type WGAddress = device.WGAddress
|
|
||||||
|
|
||||||
type wgProxyFactory interface {
|
type wgProxyFactory interface {
|
||||||
GetProxy() wgproxy.Proxy
|
GetProxy() wgproxy.Proxy
|
||||||
Free() error
|
Free() error
|
||||||
@@ -72,7 +71,7 @@ func (w *WGIface) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Address returns the interface address
|
// Address returns the interface address
|
||||||
func (w *WGIface) Address() device.WGAddress {
|
func (w *WGIface) Address() wgaddr.Address {
|
||||||
return w.tun.WgAddress()
|
return w.tun.WgAddress()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +102,7 @@ func (w *WGIface) UpdateAddr(newAddr string) error {
|
|||||||
w.mu.Lock()
|
w.mu.Lock()
|
||||||
defer w.mu.Unlock()
|
defer w.mu.Unlock()
|
||||||
|
|
||||||
addr, err := device.ParseWGAddress(newAddr)
|
addr, err := wgaddr.ParseWGAddress(newAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,18 @@ package iface
|
|||||||
import (
|
import (
|
||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewWGIFace Creates a new WireGuard interface instance
|
// NewWGIFace Creates a new WireGuard interface instance
|
||||||
func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
||||||
wgAddress, err := device.ParseWGAddress(opts.Address)
|
wgAddress, err := wgaddr.ParseWGAddress(opts.Address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn)
|
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress)
|
||||||
|
|
||||||
wgIFace := &WGIface{
|
wgIFace := &WGIface{
|
||||||
userspaceBind: true,
|
userspaceBind: true,
|
||||||
|
|||||||
@@ -6,17 +6,18 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
"github.com/netbirdio/netbird/client/iface/netstack"
|
"github.com/netbirdio/netbird/client/iface/netstack"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewWGIFace Creates a new WireGuard interface instance
|
// NewWGIFace Creates a new WireGuard interface instance
|
||||||
func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
||||||
wgAddress, err := device.ParseWGAddress(opts.Address)
|
wgAddress, err := wgaddr.ParseWGAddress(opts.Address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn)
|
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress)
|
||||||
|
|
||||||
var tun WGTunDevice
|
var tun WGTunDevice
|
||||||
if netstack.IsEnabled() {
|
if netstack.IsEnabled() {
|
||||||
|
|||||||
@@ -5,17 +5,18 @@ package iface
|
|||||||
import (
|
import (
|
||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewWGIFace Creates a new WireGuard interface instance
|
// NewWGIFace Creates a new WireGuard interface instance
|
||||||
func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
||||||
wgAddress, err := device.ParseWGAddress(opts.Address)
|
wgAddress, err := wgaddr.ParseWGAddress(opts.Address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn)
|
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress)
|
||||||
|
|
||||||
wgIFace := &WGIface{
|
wgIFace := &WGIface{
|
||||||
tun: device.NewTunDevice(opts.IFaceName, wgAddress, opts.WGPort, opts.WGPrivKey, iceBind, opts.MobileArgs.TunFd),
|
tun: device.NewTunDevice(opts.IFaceName, wgAddress, opts.WGPort, opts.WGPrivKey, iceBind, opts.MobileArgs.TunFd),
|
||||||
|
|||||||
@@ -8,12 +8,13 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
"github.com/netbirdio/netbird/client/iface/netstack"
|
"github.com/netbirdio/netbird/client/iface/netstack"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewWGIFace Creates a new WireGuard interface instance
|
// NewWGIFace Creates a new WireGuard interface instance
|
||||||
func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
||||||
wgAddress, err := device.ParseWGAddress(opts.Address)
|
wgAddress, err := wgaddr.ParseWGAddress(opts.Address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -21,7 +22,7 @@ func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
|||||||
wgIFace := &WGIface{}
|
wgIFace := &WGIface{}
|
||||||
|
|
||||||
if netstack.IsEnabled() {
|
if netstack.IsEnabled() {
|
||||||
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn)
|
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress)
|
||||||
wgIFace.tun = device.NewNetstackDevice(opts.IFaceName, wgAddress, opts.WGPort, opts.WGPrivKey, opts.MTU, iceBind, netstack.ListenAddr())
|
wgIFace.tun = device.NewNetstackDevice(opts.IFaceName, wgAddress, opts.WGPort, opts.WGPrivKey, opts.MTU, iceBind, netstack.ListenAddr())
|
||||||
wgIFace.userspaceBind = true
|
wgIFace.userspaceBind = true
|
||||||
wgIFace.wgProxyFactory = wgproxy.NewUSPFactory(iceBind)
|
wgIFace.wgProxyFactory = wgproxy.NewUSPFactory(iceBind)
|
||||||
@@ -34,7 +35,7 @@ func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
|||||||
return wgIFace, nil
|
return wgIFace, nil
|
||||||
}
|
}
|
||||||
if device.ModuleTunIsLoaded() {
|
if device.ModuleTunIsLoaded() {
|
||||||
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn)
|
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress)
|
||||||
wgIFace.tun = device.NewUSPDevice(opts.IFaceName, wgAddress, opts.WGPort, opts.WGPrivKey, opts.MTU, iceBind)
|
wgIFace.tun = device.NewUSPDevice(opts.IFaceName, wgAddress, opts.WGPort, opts.WGPrivKey, opts.MTU, iceBind)
|
||||||
wgIFace.userspaceBind = true
|
wgIFace.userspaceBind = true
|
||||||
wgIFace.wgProxyFactory = wgproxy.NewUSPFactory(iceBind)
|
wgIFace.wgProxyFactory = wgproxy.NewUSPFactory(iceBind)
|
||||||
|
|||||||
@@ -4,16 +4,17 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
"github.com/netbirdio/netbird/client/iface/netstack"
|
"github.com/netbirdio/netbird/client/iface/netstack"
|
||||||
|
wgaddr "github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewWGIFace Creates a new WireGuard interface instance
|
// NewWGIFace Creates a new WireGuard interface instance
|
||||||
func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
||||||
wgAddress, err := device.ParseWGAddress(opts.Address)
|
wgAddress, err := wgaddr.ParseWGAddress(opts.Address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn)
|
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress)
|
||||||
|
|
||||||
var tun WGTunDevice
|
var tun WGTunDevice
|
||||||
if netstack.IsEnabled() {
|
if netstack.IsEnabled() {
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func (t *NetStackTun) Create() (tun.Device, *netstack.Net, error) {
|
|||||||
|
|
||||||
skipProxy, err := strconv.ParseBool(os.Getenv(EnvSkipProxy))
|
skipProxy, err := strconv.ParseBool(os.Getenv(EnvSkipProxy))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to parse NB_ETSTACK_SKIP_PROXY: %s", err)
|
log.Errorf("failed to parse %s: %s", EnvSkipProxy, err)
|
||||||
}
|
}
|
||||||
if skipProxy {
|
if skipProxy {
|
||||||
return nsTunDev, tunNet, nil
|
return nsTunDev, tunNet, nil
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
package device
|
package wgaddr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WGAddress WireGuard parsed address
|
// Address WireGuard parsed address
|
||||||
type WGAddress struct {
|
type Address struct {
|
||||||
IP net.IP
|
IP net.IP
|
||||||
Network *net.IPNet
|
Network *net.IPNet
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseWGAddress parse a string ("1.2.3.4/24") address to WG Address
|
// ParseWGAddress parse a string ("1.2.3.4/24") address to WG Address
|
||||||
func ParseWGAddress(address string) (WGAddress, error) {
|
func ParseWGAddress(address string) (Address, error) {
|
||||||
ip, network, err := net.ParseCIDR(address)
|
ip, network, err := net.ParseCIDR(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return WGAddress{}, err
|
return Address{}, err
|
||||||
}
|
}
|
||||||
return WGAddress{
|
return Address{
|
||||||
IP: ip,
|
IP: ip,
|
||||||
Network: network,
|
Network: network,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (addr WGAddress) String() string {
|
func (addr Address) String() string {
|
||||||
maskSize, _ := addr.Network.Mask.Size()
|
maskSize, _ := addr.Network.Mask.Size()
|
||||||
return fmt.Sprintf("%s/%d", addr.IP.String(), maskSize)
|
return fmt.Sprintf("%s/%d", addr.IP.String(), maskSize)
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@@ -16,13 +17,13 @@ import (
|
|||||||
type ProxyBind struct {
|
type ProxyBind struct {
|
||||||
Bind *bind.ICEBind
|
Bind *bind.ICEBind
|
||||||
|
|
||||||
wgAddr *net.UDPAddr
|
fakeNetIP *netip.AddrPort
|
||||||
wgEndpoint *bind.Endpoint
|
wgBindEndpoint *bind.Endpoint
|
||||||
remoteConn net.Conn
|
remoteConn net.Conn
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
closeMu sync.Mutex
|
closeMu sync.Mutex
|
||||||
closed bool
|
closed bool
|
||||||
|
|
||||||
pausedMu sync.Mutex
|
pausedMu sync.Mutex
|
||||||
paused bool
|
paused bool
|
||||||
@@ -33,20 +34,24 @@ type ProxyBind struct {
|
|||||||
// endpoint is the NetBird address of the remote peer. The SetEndpoint return with the address what will be used in the
|
// endpoint is the NetBird address of the remote peer. The SetEndpoint return with the address what will be used in the
|
||||||
// WireGuard configuration.
|
// WireGuard configuration.
|
||||||
func (p *ProxyBind) AddTurnConn(ctx context.Context, nbAddr *net.UDPAddr, remoteConn net.Conn) error {
|
func (p *ProxyBind) AddTurnConn(ctx context.Context, nbAddr *net.UDPAddr, remoteConn net.Conn) error {
|
||||||
addr, err := p.Bind.SetEndpoint(nbAddr, remoteConn)
|
fakeNetIP, err := fakeAddress(nbAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
p.wgAddr = addr
|
p.fakeNetIP = fakeNetIP
|
||||||
p.wgEndpoint = addrToEndpoint(addr)
|
p.wgBindEndpoint = &bind.Endpoint{AddrPort: *fakeNetIP}
|
||||||
p.remoteConn = remoteConn
|
p.remoteConn = remoteConn
|
||||||
p.ctx, p.cancel = context.WithCancel(ctx)
|
p.ctx, p.cancel = context.WithCancel(ctx)
|
||||||
return err
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
func (p *ProxyBind) EndpointAddr() *net.UDPAddr {
|
func (p *ProxyBind) EndpointAddr() *net.UDPAddr {
|
||||||
return p.wgAddr
|
return &net.UDPAddr{
|
||||||
|
IP: p.fakeNetIP.Addr().AsSlice(),
|
||||||
|
Port: int(p.fakeNetIP.Port()),
|
||||||
|
Zone: p.fakeNetIP.Addr().Zone(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProxyBind) Work() {
|
func (p *ProxyBind) Work() {
|
||||||
@@ -54,6 +59,8 @@ func (p *ProxyBind) Work() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.Bind.SetEndpoint(p.fakeNetIP.Addr(), p.remoteConn)
|
||||||
|
|
||||||
p.pausedMu.Lock()
|
p.pausedMu.Lock()
|
||||||
p.paused = false
|
p.paused = false
|
||||||
p.pausedMu.Unlock()
|
p.pausedMu.Unlock()
|
||||||
@@ -93,7 +100,7 @@ func (p *ProxyBind) close() error {
|
|||||||
|
|
||||||
p.cancel()
|
p.cancel()
|
||||||
|
|
||||||
p.Bind.RemoveEndpoint(p.wgAddr)
|
p.Bind.RemoveEndpoint(p.fakeNetIP.Addr())
|
||||||
|
|
||||||
if rErr := p.remoteConn.Close(); rErr != nil && !errors.Is(rErr, net.ErrClosed) {
|
if rErr := p.remoteConn.Close(); rErr != nil && !errors.Is(rErr, net.ErrClosed) {
|
||||||
return rErr
|
return rErr
|
||||||
@@ -126,7 +133,7 @@ func (p *ProxyBind) proxyToLocal(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
msg := bind.RecvMessage{
|
msg := bind.RecvMessage{
|
||||||
Endpoint: p.wgEndpoint,
|
Endpoint: p.wgBindEndpoint,
|
||||||
Buffer: buf[:n],
|
Buffer: buf[:n],
|
||||||
}
|
}
|
||||||
p.Bind.RecvChan <- msg
|
p.Bind.RecvChan <- msg
|
||||||
@@ -134,8 +141,19 @@ func (p *ProxyBind) proxyToLocal(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addrToEndpoint(addr *net.UDPAddr) *bind.Endpoint {
|
// fakeAddress returns a fake address that is used to as an identifier for the peer.
|
||||||
ip, _ := netip.AddrFromSlice(addr.IP.To4())
|
// The fake address is in the format of 127.1.x.x where x.x is the last two octets of the peer address.
|
||||||
addrPort := netip.AddrPortFrom(ip, uint16(addr.Port))
|
func fakeAddress(peerAddress *net.UDPAddr) (*netip.AddrPort, error) {
|
||||||
return &bind.Endpoint{AddrPort: addrPort}
|
octets := strings.Split(peerAddress.IP.String(), ".")
|
||||||
|
if len(octets) != 4 {
|
||||||
|
return nil, fmt.Errorf("invalid IP format")
|
||||||
|
}
|
||||||
|
|
||||||
|
fakeIP, err := netip.ParseAddr(fmt.Sprintf("127.1.%s.%s", octets[2], octets[3]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse new IP: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
netipAddr := netip.AddrPortFrom(fakeIP, uint16(peerAddress.Port))
|
||||||
|
return &netipAddr, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
!define DESCRIPTION "A WireGuard®-based mesh network that connects your devices into a single private network"
|
!define DESCRIPTION "A WireGuard®-based mesh network that connects your devices into a single private network"
|
||||||
!define INSTALLER_NAME "netbird-installer.exe"
|
!define INSTALLER_NAME "netbird-installer.exe"
|
||||||
!define MAIN_APP_EXE "Netbird"
|
!define MAIN_APP_EXE "Netbird"
|
||||||
!define ICON "ui\\netbird.ico"
|
!define ICON "ui\\assets\\netbird.ico"
|
||||||
!define BANNER "ui\\banner.bmp"
|
!define BANNER "ui\\build\\banner.bmp"
|
||||||
!define LICENSE_DATA "..\\LICENSE"
|
!define LICENSE_DATA "..\\LICENSE"
|
||||||
|
|
||||||
!define INSTALL_DIR "$PROGRAMFILES64\${APP_NAME}"
|
!define INSTALL_DIR "$PROGRAMFILES64\${APP_NAME}"
|
||||||
@@ -22,6 +22,8 @@
|
|||||||
!define UI_REG_APP_PATH "Software\Microsoft\Windows\CurrentVersion\App Paths\${UI_APP_EXE}"
|
!define UI_REG_APP_PATH "Software\Microsoft\Windows\CurrentVersion\App Paths\${UI_APP_EXE}"
|
||||||
!define UI_UNINSTALL_PATH "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UI_APP_NAME}"
|
!define UI_UNINSTALL_PATH "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UI_APP_NAME}"
|
||||||
|
|
||||||
|
!define AUTOSTART_REG_KEY "Software\Microsoft\Windows\CurrentVersion\Run"
|
||||||
|
|
||||||
Unicode True
|
Unicode True
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
@@ -68,6 +70,9 @@ ShowInstDetails Show
|
|||||||
|
|
||||||
!insertmacro MUI_PAGE_DIRECTORY
|
!insertmacro MUI_PAGE_DIRECTORY
|
||||||
|
|
||||||
|
; Custom page for autostart checkbox
|
||||||
|
Page custom AutostartPage AutostartPageLeave
|
||||||
|
|
||||||
!insertmacro MUI_PAGE_INSTFILES
|
!insertmacro MUI_PAGE_INSTFILES
|
||||||
|
|
||||||
!insertmacro MUI_PAGE_FINISH
|
!insertmacro MUI_PAGE_FINISH
|
||||||
@@ -80,8 +85,36 @@ ShowInstDetails Show
|
|||||||
|
|
||||||
!insertmacro MUI_LANGUAGE "English"
|
!insertmacro MUI_LANGUAGE "English"
|
||||||
|
|
||||||
|
; Variables for autostart option
|
||||||
|
Var AutostartCheckbox
|
||||||
|
Var AutostartEnabled
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
; Function to create the autostart options page
|
||||||
|
Function AutostartPage
|
||||||
|
!insertmacro MUI_HEADER_TEXT "Startup Options" "Configure how ${APP_NAME} launches with Windows."
|
||||||
|
|
||||||
|
nsDialogs::Create 1018
|
||||||
|
Pop $0
|
||||||
|
|
||||||
|
${If} $0 == error
|
||||||
|
Abort
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
|
${NSD_CreateCheckbox} 0 20u 100% 10u "Start ${APP_NAME} UI automatically when Windows starts"
|
||||||
|
Pop $AutostartCheckbox
|
||||||
|
${NSD_Check} $AutostartCheckbox ; Default to checked
|
||||||
|
StrCpy $AutostartEnabled "1" ; Default to enabled
|
||||||
|
|
||||||
|
nsDialogs::Show
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
; Function to handle leaving the autostart page
|
||||||
|
Function AutostartPageLeave
|
||||||
|
${NSD_GetState} $AutostartCheckbox $AutostartEnabled
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
Function GetAppFromCommand
|
Function GetAppFromCommand
|
||||||
Exch $1
|
Exch $1
|
||||||
Push $2
|
Push $2
|
||||||
@@ -163,6 +196,16 @@ WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "Publisher" "${COMP_NAME}"
|
|||||||
|
|
||||||
WriteRegStr ${REG_ROOT} "${UI_REG_APP_PATH}" "" "$INSTDIR\${UI_APP_EXE}"
|
WriteRegStr ${REG_ROOT} "${UI_REG_APP_PATH}" "" "$INSTDIR\${UI_APP_EXE}"
|
||||||
|
|
||||||
|
; Create autostart registry entry based on checkbox
|
||||||
|
DetailPrint "Autostart enabled: $AutostartEnabled"
|
||||||
|
${If} $AutostartEnabled == "1"
|
||||||
|
WriteRegStr HKCU "${AUTOSTART_REG_KEY}" "${APP_NAME}" "$INSTDIR\${UI_APP_EXE}.exe"
|
||||||
|
DetailPrint "Added autostart registry entry: $INSTDIR\${UI_APP_EXE}.exe"
|
||||||
|
${Else}
|
||||||
|
DeleteRegValue HKCU "${AUTOSTART_REG_KEY}" "${APP_NAME}"
|
||||||
|
DetailPrint "Autostart not enabled by user"
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
EnVar::SetHKLM
|
EnVar::SetHKLM
|
||||||
EnVar::AddValueEx "path" "$INSTDIR"
|
EnVar::AddValueEx "path" "$INSTDIR"
|
||||||
|
|
||||||
@@ -186,7 +229,10 @@ ExecWait '"$INSTDIR\${MAIN_APP_EXE}" service stop'
|
|||||||
ExecWait '"$INSTDIR\${MAIN_APP_EXE}" service uninstall'
|
ExecWait '"$INSTDIR\${MAIN_APP_EXE}" service uninstall'
|
||||||
|
|
||||||
# kill ui client
|
# kill ui client
|
||||||
ExecWait `taskkill /im ${UI_APP_EXE}.exe`
|
ExecWait `taskkill /im ${UI_APP_EXE}.exe /f`
|
||||||
|
|
||||||
|
; Remove autostart registry entry
|
||||||
|
DeleteRegValue HKCU "${AUTOSTART_REG_KEY}" "${APP_NAME}"
|
||||||
|
|
||||||
# wait the service uninstall take unblock the executable
|
# wait the service uninstall take unblock the executable
|
||||||
Sleep 3000
|
Sleep 3000
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/netbirdio/netbird/client/firewall"
|
"github.com/netbirdio/netbird/client/firewall"
|
||||||
"github.com/netbirdio/netbird/client/firewall/manager"
|
"github.com/netbirdio/netbird/client/firewall/manager"
|
||||||
"github.com/netbirdio/netbird/client/iface"
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/client/internal/acl/mocks"
|
"github.com/netbirdio/netbird/client/internal/acl/mocks"
|
||||||
"github.com/netbirdio/netbird/client/internal/netflow"
|
"github.com/netbirdio/netbird/client/internal/netflow"
|
||||||
mgmProto "github.com/netbirdio/netbird/management/proto"
|
mgmProto "github.com/netbirdio/netbird/management/proto"
|
||||||
@@ -49,7 +49,7 @@ func TestDefaultManager(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ifaceMock.EXPECT().Name().Return("lo").AnyTimes()
|
ifaceMock.EXPECT().Name().Return("lo").AnyTimes()
|
||||||
ifaceMock.EXPECT().Address().Return(iface.WGAddress{
|
ifaceMock.EXPECT().Address().Return(wgaddr.Address{
|
||||||
IP: ip,
|
IP: ip,
|
||||||
Network: network,
|
Network: network,
|
||||||
}).AnyTimes()
|
}).AnyTimes()
|
||||||
@@ -62,7 +62,7 @@ func TestDefaultManager(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer func(fw manager.Manager) {
|
defer func(fw manager.Manager) {
|
||||||
_ = fw.Reset(nil)
|
_ = fw.Close(nil)
|
||||||
}(fw)
|
}(fw)
|
||||||
acl := NewDefaultManager(fw)
|
acl := NewDefaultManager(fw)
|
||||||
|
|
||||||
@@ -343,7 +343,7 @@ func TestDefaultManagerEnableSSHRules(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ifaceMock.EXPECT().Name().Return("lo").AnyTimes()
|
ifaceMock.EXPECT().Name().Return("lo").AnyTimes()
|
||||||
ifaceMock.EXPECT().Address().Return(iface.WGAddress{
|
ifaceMock.EXPECT().Address().Return(wgaddr.Address{
|
||||||
IP: ip,
|
IP: ip,
|
||||||
Network: network,
|
Network: network,
|
||||||
}).AnyTimes()
|
}).AnyTimes()
|
||||||
@@ -356,7 +356,7 @@ func TestDefaultManagerEnableSSHRules(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer func(fw manager.Manager) {
|
defer func(fw manager.Manager) {
|
||||||
_ = fw.Reset(nil)
|
_ = fw.Close(nil)
|
||||||
}(fw)
|
}(fw)
|
||||||
acl := NewDefaultManager(fw)
|
acl := NewDefaultManager(fw)
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
gomock "github.com/golang/mock/gomock"
|
gomock "github.com/golang/mock/gomock"
|
||||||
wgdevice "golang.zx2c4.com/wireguard/device"
|
wgdevice "golang.zx2c4.com/wireguard/device"
|
||||||
|
|
||||||
iface "github.com/netbirdio/netbird/client/iface"
|
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MockIFaceMapper is a mock of IFaceMapper interface.
|
// MockIFaceMapper is a mock of IFaceMapper interface.
|
||||||
@@ -38,10 +38,10 @@ func (m *MockIFaceMapper) EXPECT() *MockIFaceMapperMockRecorder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Address mocks base method.
|
// Address mocks base method.
|
||||||
func (m *MockIFaceMapper) Address() iface.WGAddress {
|
func (m *MockIFaceMapper) Address() wgaddr.Address {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "Address")
|
ret := m.ctrl.Call(m, "Address")
|
||||||
ret0, _ := ret[0].(iface.WGAddress)
|
ret0, _ := ret[0].(wgaddr.Address)
|
||||||
return ret0
|
return ret0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ func NewConnectClient(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run with main logic.
|
// Run with main logic.
|
||||||
func (c *ConnectClient) Run(runningChan chan error) error {
|
func (c *ConnectClient) Run(runningChan chan struct{}) error {
|
||||||
return c.run(MobileDependency{}, runningChan)
|
return c.run(MobileDependency{}, runningChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ func (c *ConnectClient) RunOniOS(
|
|||||||
return c.run(mobileDependency, nil)
|
return c.run(mobileDependency, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConnectClient) run(mobileDependency MobileDependency, runningChan chan error) error {
|
func (c *ConnectClient) run(mobileDependency MobileDependency, runningChan chan struct{}) error {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
rec := c.statusRecorder
|
rec := c.statusRecorder
|
||||||
@@ -159,10 +159,9 @@ func (c *ConnectClient) run(mobileDependency MobileDependency, runningChan chan
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer c.statusRecorder.ClientStop()
|
defer c.statusRecorder.ClientStop()
|
||||||
runningChanOpen := true
|
|
||||||
operation := func() error {
|
operation := func() error {
|
||||||
// if context cancelled we not start new backoff cycle
|
// if context cancelled we not start new backoff cycle
|
||||||
if c.isContextCancelled() {
|
if c.ctx.Err() != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,10 +281,11 @@ func (c *ConnectClient) run(mobileDependency MobileDependency, runningChan chan
|
|||||||
log.Infof("Netbird engine started, the IP is: %s", peerConfig.GetAddress())
|
log.Infof("Netbird engine started, the IP is: %s", peerConfig.GetAddress())
|
||||||
state.Set(StatusConnected)
|
state.Set(StatusConnected)
|
||||||
|
|
||||||
if runningChan != nil && runningChanOpen {
|
if runningChan != nil {
|
||||||
runningChan <- nil
|
select {
|
||||||
close(runningChan)
|
case runningChan <- struct{}{}:
|
||||||
runningChanOpen = false
|
default:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
<-engineCtx.Done()
|
<-engineCtx.Done()
|
||||||
@@ -379,15 +379,6 @@ func (c *ConnectClient) Stop() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConnectClient) isContextCancelled() bool {
|
|
||||||
select {
|
|
||||||
case <-c.ctx.Done():
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetNetworkMapPersistence enables or disables network map persistence.
|
// SetNetworkMapPersistence enables or disables network map persistence.
|
||||||
// When enabled, the last received network map will be stored and can be retrieved
|
// When enabled, the last received network map will be stored and can be retrieved
|
||||||
// through the Engine's getLatestNetworkMap method. When disabled, any stored
|
// through the Engine's getLatestNetworkMap method. When disabled, any stored
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/iface/configurer"
|
"github.com/netbirdio/netbird/client/iface/configurer"
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
pfmock "github.com/netbirdio/netbird/client/iface/mocks"
|
pfmock "github.com/netbirdio/netbird/client/iface/mocks"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/client/internal/netflow"
|
"github.com/netbirdio/netbird/client/internal/netflow"
|
||||||
"github.com/netbirdio/netbird/client/internal/peer"
|
"github.com/netbirdio/netbird/client/internal/peer"
|
||||||
"github.com/netbirdio/netbird/client/internal/statemanager"
|
"github.com/netbirdio/netbird/client/internal/statemanager"
|
||||||
@@ -40,9 +41,9 @@ func (w *mocWGIface) Name() string {
|
|||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *mocWGIface) Address() iface.WGAddress {
|
func (w *mocWGIface) Address() wgaddr.Address {
|
||||||
ip, network, _ := net.ParseCIDR("100.66.100.0/24")
|
ip, network, _ := net.ParseCIDR("100.66.100.0/24")
|
||||||
return iface.WGAddress{
|
return wgaddr.Address{
|
||||||
IP: ip,
|
IP: ip,
|
||||||
Network: network,
|
Network: network,
|
||||||
}
|
}
|
||||||
@@ -1018,7 +1019,7 @@ func TestHandlerChain_DomainPriorities(t *testing.T) {
|
|||||||
mh.AssertExpectations(t)
|
mh.AssertExpectations(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset mocks
|
// Close mocks
|
||||||
if mh, ok := tc.expectedHandler.(*MockHandler); ok {
|
if mh, ok := tc.expectedHandler.(*MockHandler); ok {
|
||||||
mh.ExpectedCalls = nil
|
mh.ExpectedCalls = nil
|
||||||
mh.Calls = nil
|
mh.Calls = nil
|
||||||
|
|||||||
@@ -5,15 +5,15 @@ package dns
|
|||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface"
|
|
||||||
"github.com/netbirdio/netbird/client/iface/configurer"
|
"github.com/netbirdio/netbird/client/iface/configurer"
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WGIface defines subset methods of interface required for manager
|
// WGIface defines subset methods of interface required for manager
|
||||||
type WGIface interface {
|
type WGIface interface {
|
||||||
Name() string
|
Name() string
|
||||||
Address() iface.WGAddress
|
Address() wgaddr.Address
|
||||||
ToInterface() *net.Interface
|
ToInterface() *net.Interface
|
||||||
IsUserspaceBind() bool
|
IsUserspaceBind() bool
|
||||||
GetFilter() device.PacketFilter
|
GetFilter() device.PacketFilter
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/netbirdio/netbird/client/iface"
|
|
||||||
"github.com/netbirdio/netbird/client/iface/configurer"
|
"github.com/netbirdio/netbird/client/iface/configurer"
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WGIface defines subset methods of interface required for manager
|
// WGIface defines subset methods of interface required for manager
|
||||||
type WGIface interface {
|
type WGIface interface {
|
||||||
Name() string
|
Name() string
|
||||||
Address() iface.WGAddress
|
Address() wgaddr.Address
|
||||||
IsUserspaceBind() bool
|
IsUserspaceBind() bool
|
||||||
GetFilter() device.PacketFilter
|
GetFilter() device.PacketFilter
|
||||||
GetDevice() *device.FilteredDevice
|
GetDevice() *device.FilteredDevice
|
||||||
|
|||||||
@@ -1428,7 +1428,7 @@ func (e *Engine) close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if e.firewall != nil {
|
if e.firewall != nil {
|
||||||
err := e.firewall.Reset(e.stateManager)
|
err := e.firewall.Close(e.stateManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("failed to reset firewall: %s", err)
|
log.Warnf("failed to reset firewall: %s", err)
|
||||||
}
|
}
|
||||||
@@ -1641,16 +1641,19 @@ func (e *Engine) probeTURNs() []relay.ProbeResult {
|
|||||||
return relay.ProbeAll(e.ctx, relay.ProbeTURN, turns)
|
return relay.ProbeAll(e.ctx, relay.ProbeTURN, turns)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restartEngine restarts the engine by cancelling the client context
|
||||||
func (e *Engine) restartEngine() {
|
func (e *Engine) restartEngine() {
|
||||||
log.Info("restarting engine")
|
e.syncMsgMux.Lock()
|
||||||
CtxGetState(e.ctx).Set(StatusConnecting)
|
defer e.syncMsgMux.Unlock()
|
||||||
|
|
||||||
if err := e.Stop(); err != nil {
|
if e.ctx.Err() != nil {
|
||||||
log.Errorf("Failed to stop engine: %v", err)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Info("restarting engine")
|
||||||
|
CtxGetState(e.ctx).Set(StatusConnecting)
|
||||||
_ = CtxGetState(e.ctx).Wrap(ErrResetConnection)
|
_ = CtxGetState(e.ctx).Wrap(ErrResetConnection)
|
||||||
log.Infof("cancelling client, engine will be recreated")
|
log.Infof("cancelling client context, engine will be recreated")
|
||||||
e.clientCancel()
|
e.clientCancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1662,34 +1665,17 @@ func (e *Engine) startNetworkMonitor() {
|
|||||||
|
|
||||||
e.networkMonitor = networkmonitor.New()
|
e.networkMonitor = networkmonitor.New()
|
||||||
go func() {
|
go func() {
|
||||||
var mu sync.Mutex
|
if err := e.networkMonitor.Listen(e.ctx); err != nil {
|
||||||
var debounceTimer *time.Timer
|
if errors.Is(err, context.Canceled) {
|
||||||
|
log.Infof("network monitor stopped")
|
||||||
// Start the network monitor with a callback, Start will block until the monitor is stopped,
|
return
|
||||||
// a network change is detected, or an error occurs on start up
|
|
||||||
err := e.networkMonitor.Start(e.ctx, func() {
|
|
||||||
// This function is called when a network change is detected
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
|
|
||||||
if debounceTimer != nil {
|
|
||||||
log.Infof("Network monitor: detected network change, reset debounceTimer")
|
|
||||||
debounceTimer.Stop()
|
|
||||||
}
|
}
|
||||||
|
log.Errorf("network monitor error: %v", err)
|
||||||
// Set a new timer to debounce rapid network changes
|
return
|
||||||
debounceTimer = time.AfterFunc(2*time.Second, func() {
|
|
||||||
// This function is called after the debounce period
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
|
|
||||||
log.Infof("Network monitor: detected network change, restarting engine")
|
|
||||||
e.restartEngine()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
if err != nil && !errors.Is(err, networkmonitor.ErrStopped) {
|
|
||||||
log.Errorf("Network monitor: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Infof("Network monitor: detected network change, restarting engine")
|
||||||
|
e.restartEngine()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/configurer"
|
"github.com/netbirdio/netbird/client/iface/configurer"
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
||||||
"github.com/netbirdio/netbird/client/internal/dns"
|
"github.com/netbirdio/netbird/client/internal/dns"
|
||||||
"github.com/netbirdio/netbird/client/internal/peer"
|
"github.com/netbirdio/netbird/client/internal/peer"
|
||||||
@@ -75,7 +76,7 @@ type MockWGIface struct {
|
|||||||
CreateOnAndroidFunc func(routeRange []string, ip string, domains []string) error
|
CreateOnAndroidFunc func(routeRange []string, ip string, domains []string) error
|
||||||
IsUserspaceBindFunc func() bool
|
IsUserspaceBindFunc func() bool
|
||||||
NameFunc func() string
|
NameFunc func() string
|
||||||
AddressFunc func() device.WGAddress
|
AddressFunc func() wgaddr.Address
|
||||||
ToInterfaceFunc func() *net.Interface
|
ToInterfaceFunc func() *net.Interface
|
||||||
UpFunc func() (*bind.UniversalUDPMuxDefault, error)
|
UpFunc func() (*bind.UniversalUDPMuxDefault, error)
|
||||||
UpdateAddrFunc func(newAddr string) error
|
UpdateAddrFunc func(newAddr string) error
|
||||||
@@ -114,7 +115,7 @@ func (m *MockWGIface) Name() string {
|
|||||||
return m.NameFunc()
|
return m.NameFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockWGIface) Address() device.WGAddress {
|
func (m *MockWGIface) Address() wgaddr.Address {
|
||||||
return m.AddressFunc()
|
return m.AddressFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,8 +365,8 @@ func TestEngine_UpdateNetworkMap(t *testing.T) {
|
|||||||
RemovePeerFunc: func(peerKey string) error {
|
RemovePeerFunc: func(peerKey string) error {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
AddressFunc: func() iface.WGAddress {
|
AddressFunc: func() wgaddr.Address {
|
||||||
return iface.WGAddress{
|
return wgaddr.Address{
|
||||||
IP: net.ParseIP("10.20.0.1"),
|
IP: net.ParseIP("10.20.0.1"),
|
||||||
Network: &net.IPNet{
|
Network: &net.IPNet{
|
||||||
IP: net.ParseIP("10.20.0.0"),
|
IP: net.ParseIP("10.20.0.0"),
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/configurer"
|
"github.com/netbirdio/netbird/client/iface/configurer"
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ type wgIfaceBase interface {
|
|||||||
CreateOnAndroid(routeRange []string, ip string, domains []string) error
|
CreateOnAndroid(routeRange []string, ip string, domains []string) error
|
||||||
IsUserspaceBind() bool
|
IsUserspaceBind() bool
|
||||||
Name() string
|
Name() string
|
||||||
Address() device.WGAddress
|
Address() wgaddr.Address
|
||||||
ToInterface() *net.Interface
|
ToInterface() *net.Interface
|
||||||
Up() (*bind.UniversalUDPMuxDefault, error)
|
Up() (*bind.UniversalUDPMuxDefault, error)
|
||||||
UpdateAddr(newAddr string) error
|
UpdateAddr(newAddr string) error
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Protocol uint8
|
type Protocol uint8
|
||||||
@@ -147,5 +147,5 @@ type ConnTracker interface {
|
|||||||
type IFaceMapper interface {
|
type IFaceMapper interface {
|
||||||
IsUserspaceBind() bool
|
IsUserspaceBind() bool
|
||||||
Name() string
|
Name() string
|
||||||
Address() device.WGAddress
|
Address() wgaddr.Address
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/internal/routemanager/systemops"
|
"github.com/netbirdio/netbird/client/internal/routemanager/systemops"
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkChange(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop, callback func()) error {
|
func checkChange(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop) error {
|
||||||
fd, err := unix.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC)
|
fd, err := unix.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open routing socket: %v", err)
|
return fmt.Errorf("failed to open routing socket: %v", err)
|
||||||
@@ -28,18 +28,10 @@ func checkChange(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop, ca
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
|
||||||
<-ctx.Done()
|
|
||||||
err := unix.Close(fd)
|
|
||||||
if err != nil && !errors.Is(err, unix.EBADF) {
|
|
||||||
log.Debugf("Network monitor: closed routing socket: %v", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return ErrStopped
|
return ctx.Err()
|
||||||
default:
|
default:
|
||||||
buf := make([]byte, 2048)
|
buf := make([]byte, 2048)
|
||||||
n, err := unix.Read(fd, buf)
|
n, err := unix.Read(fd, buf)
|
||||||
@@ -76,11 +68,11 @@ func checkChange(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop, ca
|
|||||||
switch msg.Type {
|
switch msg.Type {
|
||||||
case unix.RTM_ADD:
|
case unix.RTM_ADD:
|
||||||
log.Infof("Network monitor: default route changed: via %s, interface %s", route.Gw, intf)
|
log.Infof("Network monitor: default route changed: via %s, interface %s", route.Gw, intf)
|
||||||
go callback()
|
return nil
|
||||||
case unix.RTM_DELETE:
|
case unix.RTM_DELETE:
|
||||||
if nexthopv4.Intf != nil && route.Gw.Compare(nexthopv4.IP) == 0 || nexthopv6.Intf != nil && route.Gw.Compare(nexthopv6.IP) == 0 {
|
if nexthopv4.Intf != nil && route.Gw.Compare(nexthopv4.IP) == 0 || nexthopv6.Intf != nil && route.Gw.Compare(nexthopv6.IP) == 0 {
|
||||||
log.Infof("Network monitor: default route removed: via %s, interface %s", route.Gw, intf)
|
log.Infof("Network monitor: default route removed: via %s, interface %s", route.Gw, intf)
|
||||||
go callback()
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/internal/routemanager/systemops"
|
"github.com/netbirdio/netbird/client/internal/routemanager/systemops"
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkChange(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop, callback func()) error {
|
func checkChange(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop) error {
|
||||||
if nexthopv4.Intf == nil && nexthopv6.Intf == nil {
|
if nexthopv4.Intf == nil && nexthopv6.Intf == nil {
|
||||||
return errors.New("no interfaces available")
|
return errors.New("no interfaces available")
|
||||||
}
|
}
|
||||||
@@ -31,8 +31,7 @@ func checkChange(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop, ca
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return ErrStopped
|
return ctx.Err()
|
||||||
|
|
||||||
// handle route changes
|
// handle route changes
|
||||||
case route := <-routeChan:
|
case route := <-routeChan:
|
||||||
// default route and main table
|
// default route and main table
|
||||||
@@ -43,12 +42,10 @@ func checkChange(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop, ca
|
|||||||
// triggered on added/replaced routes
|
// triggered on added/replaced routes
|
||||||
case syscall.RTM_NEWROUTE:
|
case syscall.RTM_NEWROUTE:
|
||||||
log.Infof("Network monitor: default route changed: via %s, interface %d", route.Gw, route.LinkIndex)
|
log.Infof("Network monitor: default route changed: via %s, interface %d", route.Gw, route.LinkIndex)
|
||||||
go callback()
|
|
||||||
return nil
|
return nil
|
||||||
case syscall.RTM_DELROUTE:
|
case syscall.RTM_DELROUTE:
|
||||||
if nexthopv4.Intf != nil && route.Gw.Equal(nexthopv4.IP.AsSlice()) || nexthopv6.Intf != nil && route.Gw.Equal(nexthopv6.IP.AsSlice()) {
|
if nexthopv4.Intf != nil && route.Gw.Equal(nexthopv4.IP.AsSlice()) || nexthopv6.Intf != nil && route.Gw.Equal(nexthopv6.IP.AsSlice()) {
|
||||||
log.Infof("Network monitor: default route removed: via %s, interface %d", route.Gw, route.LinkIndex)
|
log.Infof("Network monitor: default route removed: via %s, interface %d", route.Gw, route.LinkIndex)
|
||||||
go callback()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/internal/routemanager/systemops"
|
"github.com/netbirdio/netbird/client/internal/routemanager/systemops"
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkChange(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop, callback func()) error {
|
func checkChange(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop) error {
|
||||||
routeMonitor, err := systemops.NewRouteMonitor(ctx)
|
routeMonitor, err := systemops.NewRouteMonitor(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create route monitor: %w", err)
|
return fmt.Errorf("failed to create route monitor: %w", err)
|
||||||
@@ -24,20 +24,20 @@ func checkChange(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop, ca
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return ErrStopped
|
return ctx.Err()
|
||||||
case route := <-routeMonitor.RouteUpdates():
|
case route := <-routeMonitor.RouteUpdates():
|
||||||
if route.Destination.Bits() != 0 {
|
if route.Destination.Bits() != 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if routeChanged(route, nexthopv4, nexthopv6, callback) {
|
if routeChanged(route, nexthopv4, nexthopv6) {
|
||||||
break
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func routeChanged(route systemops.RouteUpdate, nexthopv4, nexthopv6 systemops.Nexthop, callback func()) bool {
|
func routeChanged(route systemops.RouteUpdate, nexthopv4, nexthopv6 systemops.Nexthop) bool {
|
||||||
intf := "<nil>"
|
intf := "<nil>"
|
||||||
if route.Interface != nil {
|
if route.Interface != nil {
|
||||||
intf = route.Interface.Name
|
intf = route.Interface.Name
|
||||||
@@ -51,18 +51,15 @@ func routeChanged(route systemops.RouteUpdate, nexthopv4, nexthopv6 systemops.Ne
|
|||||||
case systemops.RouteModified:
|
case systemops.RouteModified:
|
||||||
// TODO: get routing table to figure out if our route is affected for modified routes
|
// TODO: get routing table to figure out if our route is affected for modified routes
|
||||||
log.Infof("Network monitor: default route changed: via %s, interface %s", route.NextHop, intf)
|
log.Infof("Network monitor: default route changed: via %s, interface %s", route.NextHop, intf)
|
||||||
go callback()
|
|
||||||
return true
|
return true
|
||||||
case systemops.RouteAdded:
|
case systemops.RouteAdded:
|
||||||
if route.NextHop.Is4() && route.NextHop != nexthopv4.IP || route.NextHop.Is6() && route.NextHop != nexthopv6.IP {
|
if route.NextHop.Is4() && route.NextHop != nexthopv4.IP || route.NextHop.Is6() && route.NextHop != nexthopv6.IP {
|
||||||
log.Infof("Network monitor: default route added: via %s, interface %s", route.NextHop, intf)
|
log.Infof("Network monitor: default route added: via %s, interface %s", route.NextHop, intf)
|
||||||
go callback()
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
case systemops.RouteDeleted:
|
case systemops.RouteDeleted:
|
||||||
if nexthopv4.Intf != nil && route.NextHop == nexthopv4.IP || nexthopv6.Intf != nil && route.NextHop == nexthopv6.IP {
|
if nexthopv4.Intf != nil && route.NextHop == nexthopv4.IP || nexthopv6.Intf != nil && route.NextHop == nexthopv6.IP {
|
||||||
log.Infof("Network monitor: default route removed: via %s, interface %s", route.NextHop, intf)
|
log.Infof("Network monitor: default route removed: via %s, interface %s", route.NextHop, intf)
|
||||||
go callback()
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,27 @@
|
|||||||
|
//go:build !ios && !android
|
||||||
|
|
||||||
package networkmonitor
|
package networkmonitor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/netip"
|
||||||
|
"runtime/debug"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cenkalti/backoff/v4"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/client/internal/routemanager/systemops"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrStopped = errors.New("monitor has been stopped")
|
const (
|
||||||
|
debounceTime = 2 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
var checkChangeFn = checkChange
|
||||||
|
|
||||||
// NetworkMonitor watches for changes in network configuration.
|
// NetworkMonitor watches for changes in network configuration.
|
||||||
type NetworkMonitor struct {
|
type NetworkMonitor struct {
|
||||||
@@ -19,3 +34,99 @@ type NetworkMonitor struct {
|
|||||||
func New() *NetworkMonitor {
|
func New() *NetworkMonitor {
|
||||||
return &NetworkMonitor{}
|
return &NetworkMonitor{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Listen begins monitoring network changes. When a change is detected, this function will return without error.
|
||||||
|
func (nw *NetworkMonitor) Listen(ctx context.Context) (err error) {
|
||||||
|
nw.mu.Lock()
|
||||||
|
if nw.cancel != nil {
|
||||||
|
nw.mu.Unlock()
|
||||||
|
return errors.New("network monitor already started")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, nw.cancel = context.WithCancel(ctx)
|
||||||
|
defer nw.cancel()
|
||||||
|
nw.wg.Add(1)
|
||||||
|
nw.mu.Unlock()
|
||||||
|
|
||||||
|
defer nw.wg.Done()
|
||||||
|
|
||||||
|
var nexthop4, nexthop6 systemops.Nexthop
|
||||||
|
|
||||||
|
operation := func() error {
|
||||||
|
var errv4, errv6 error
|
||||||
|
nexthop4, errv4 = systemops.GetNextHop(netip.IPv4Unspecified())
|
||||||
|
nexthop6, errv6 = systemops.GetNextHop(netip.IPv6Unspecified())
|
||||||
|
|
||||||
|
if errv4 != nil && errv6 != nil {
|
||||||
|
return errors.New("failed to get default next hops")
|
||||||
|
}
|
||||||
|
|
||||||
|
if errv4 == nil {
|
||||||
|
log.Debugf("Network monitor: IPv4 default route: %s, interface: %s", nexthop4.IP, nexthop4.Intf.Name)
|
||||||
|
}
|
||||||
|
if errv6 == nil {
|
||||||
|
log.Debugf("Network monitor: IPv6 default route: %s, interface: %s", nexthop6.IP, nexthop6.Intf.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// continue if either route was found
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
expBackOff := backoff.WithContext(backoff.NewExponentialBackOff(), ctx)
|
||||||
|
|
||||||
|
if err := backoff.Retry(operation, expBackOff); err != nil {
|
||||||
|
return fmt.Errorf("failed to get default next hops: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// recover in case sys ops panic
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err = fmt.Errorf("panic occurred: %v, stack trace: %s", r, debug.Stack())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
event := make(chan struct{}, 1)
|
||||||
|
go nw.checkChanges(ctx, event, nexthop4, nexthop6)
|
||||||
|
|
||||||
|
// debounce changes
|
||||||
|
timer := time.NewTimer(0)
|
||||||
|
timer.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-event:
|
||||||
|
timer.Reset(debounceTime)
|
||||||
|
case <-timer.C:
|
||||||
|
return nil
|
||||||
|
case <-ctx.Done():
|
||||||
|
timer.Stop()
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop stops the network monitor.
|
||||||
|
func (nw *NetworkMonitor) Stop() {
|
||||||
|
nw.mu.Lock()
|
||||||
|
defer nw.mu.Unlock()
|
||||||
|
|
||||||
|
if nw.cancel == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nw.cancel()
|
||||||
|
nw.wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nw *NetworkMonitor) checkChanges(ctx context.Context, event chan struct{}, nexthop4 systemops.Nexthop, nexthop6 systemops.Nexthop) {
|
||||||
|
for {
|
||||||
|
if err := checkChangeFn(ctx, nexthop4, nexthop6); err != nil {
|
||||||
|
close(event)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// prevent blocking
|
||||||
|
select {
|
||||||
|
case event <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
//go:build !ios && !android
|
|
||||||
|
|
||||||
package networkmonitor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/netip"
|
|
||||||
"runtime/debug"
|
|
||||||
|
|
||||||
"github.com/cenkalti/backoff/v4"
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/internal/routemanager/systemops"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Start begins monitoring network changes. When a change is detected, it calls the callback asynchronously and returns.
|
|
||||||
func (nw *NetworkMonitor) Start(ctx context.Context, callback func()) (err error) {
|
|
||||||
if ctx.Err() != nil {
|
|
||||||
return ctx.Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
nw.mu.Lock()
|
|
||||||
ctx, nw.cancel = context.WithCancel(ctx)
|
|
||||||
nw.mu.Unlock()
|
|
||||||
|
|
||||||
nw.wg.Add(1)
|
|
||||||
defer nw.wg.Done()
|
|
||||||
|
|
||||||
var nexthop4, nexthop6 systemops.Nexthop
|
|
||||||
|
|
||||||
operation := func() error {
|
|
||||||
var errv4, errv6 error
|
|
||||||
nexthop4, errv4 = systemops.GetNextHop(netip.IPv4Unspecified())
|
|
||||||
nexthop6, errv6 = systemops.GetNextHop(netip.IPv6Unspecified())
|
|
||||||
|
|
||||||
if errv4 != nil && errv6 != nil {
|
|
||||||
return errors.New("failed to get default next hops")
|
|
||||||
}
|
|
||||||
|
|
||||||
if errv4 == nil {
|
|
||||||
log.Debugf("Network monitor: IPv4 default route: %s, interface: %s", nexthop4.IP, nexthop4.Intf.Name)
|
|
||||||
}
|
|
||||||
if errv6 == nil {
|
|
||||||
log.Debugf("Network monitor: IPv6 default route: %s, interface: %s", nexthop6.IP, nexthop6.Intf.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// continue if either route was found
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
expBackOff := backoff.WithContext(backoff.NewExponentialBackOff(), ctx)
|
|
||||||
|
|
||||||
if err := backoff.Retry(operation, expBackOff); err != nil {
|
|
||||||
return fmt.Errorf("failed to get default next hops: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// recover in case sys ops panic
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
err = fmt.Errorf("panic occurred: %v, stack trace: %s", r, debug.Stack())
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := checkChange(ctx, nexthop4, nexthop6, callback); err != nil {
|
|
||||||
return fmt.Errorf("check change: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop stops the network monitor.
|
|
||||||
func (nw *NetworkMonitor) Stop() {
|
|
||||||
nw.mu.Lock()
|
|
||||||
defer nw.mu.Unlock()
|
|
||||||
|
|
||||||
if nw.cancel != nil {
|
|
||||||
nw.cancel()
|
|
||||||
nw.wg.Wait()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,10 +2,21 @@
|
|||||||
|
|
||||||
package networkmonitor
|
package networkmonitor
|
||||||
|
|
||||||
import "context"
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
func (nw *NetworkMonitor) Start(context.Context, func()) error {
|
type NetworkMonitor struct {
|
||||||
return nil
|
}
|
||||||
|
|
||||||
|
// New creates a new network monitor.
|
||||||
|
func New() *NetworkMonitor {
|
||||||
|
return &NetworkMonitor{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nw *NetworkMonitor) Listen(_ context.Context) error {
|
||||||
|
return fmt.Errorf("network monitor not supported on mobile platforms")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nw *NetworkMonitor) Stop() {
|
func (nw *NetworkMonitor) Stop() {
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
package networkmonitor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/client/internal/routemanager/systemops"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MocMultiEvent struct {
|
||||||
|
counter int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MocMultiEvent) checkChange(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop) error {
|
||||||
|
if m.counter == 0 {
|
||||||
|
<-ctx.Done()
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
m.counter--
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNetworkMonitor_Close(t *testing.T) {
|
||||||
|
checkChangeFn = func(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop) error {
|
||||||
|
<-ctx.Done()
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
nw := New()
|
||||||
|
|
||||||
|
var resErr error
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
resErr = nw.Listen(context.Background())
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
time.Sleep(1 * time.Second) // wait for the goroutine to start
|
||||||
|
nw.Stop()
|
||||||
|
|
||||||
|
<-done
|
||||||
|
if !errors.Is(resErr, context.Canceled) {
|
||||||
|
t.Errorf("unexpected error: %v", resErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNetworkMonitor_Event(t *testing.T) {
|
||||||
|
checkChangeFn = func(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop) error {
|
||||||
|
timeout, cancel := context.WithTimeout(ctx, 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
case <-timeout.Done():
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nw := New()
|
||||||
|
defer nw.Stop()
|
||||||
|
|
||||||
|
var resErr error
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
resErr = nw.Listen(context.Background())
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-done
|
||||||
|
if !errors.Is(resErr, nil) {
|
||||||
|
t.Errorf("unexpected error: %v", nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNetworkMonitor_MultiEvent(t *testing.T) {
|
||||||
|
eventsRepeated := 3
|
||||||
|
me := &MocMultiEvent{counter: eventsRepeated}
|
||||||
|
checkChangeFn = me.checkChange
|
||||||
|
|
||||||
|
nw := New()
|
||||||
|
defer nw.Stop()
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
started := time.Now()
|
||||||
|
go func() {
|
||||||
|
if resErr := nw.Listen(context.Background()); resErr != nil {
|
||||||
|
t.Errorf("unexpected error: %v", resErr)
|
||||||
|
}
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-done
|
||||||
|
expectedResponseTime := time.Duration(eventsRepeated)*time.Second + debounceTime
|
||||||
|
if time.Since(started) < expectedResponseTime {
|
||||||
|
t.Errorf("unexpected duration: %v", time.Since(started))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -442,8 +442,8 @@ func (conn *Conn) onRelayConnectionIsReady(rci RelayConnInfo) {
|
|||||||
|
|
||||||
conn.log.Infof("created new wgProxy for relay connection: %s", wgProxy.EndpointAddr().String())
|
conn.log.Infof("created new wgProxy for relay connection: %s", wgProxy.EndpointAddr().String())
|
||||||
|
|
||||||
if conn.iceP2PIsActive() {
|
if conn.isICEActive() {
|
||||||
conn.log.Debugf("do not switch to relay because current priority is: %s", conn.currentConnPriority.String())
|
conn.log.Infof("do not switch to relay because current priority is: %s", conn.currentConnPriority.String())
|
||||||
conn.setRelayedProxy(wgProxy)
|
conn.setRelayedProxy(wgProxy)
|
||||||
conn.statusRelay.Set(StatusConnected)
|
conn.statusRelay.Set(StatusConnected)
|
||||||
conn.updateRelayStatus(rci.relayedConn.RemoteAddr().String(), rci.rosenpassPubKey)
|
conn.updateRelayStatus(rci.relayedConn.RemoteAddr().String(), rci.rosenpassPubKey)
|
||||||
@@ -711,8 +711,8 @@ func (conn *Conn) isReadyToUpgrade() bool {
|
|||||||
return conn.wgProxyRelay != nil && conn.currentConnPriority != connPriorityRelay
|
return conn.wgProxyRelay != nil && conn.currentConnPriority != connPriorityRelay
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Conn) iceP2PIsActive() bool {
|
func (conn *Conn) isICEActive() bool {
|
||||||
return conn.currentConnPriority == connPriorityICEP2P && conn.statusICE.Get() == StatusConnected
|
return (conn.currentConnPriority == connPriorityICEP2P || conn.currentConnPriority == connPriorityICETurn) && conn.statusICE.Get() == StatusConnected
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Conn) removeWgPeer() error {
|
func (conn *Conn) removeWgPeer() error {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface/configurer"
|
"github.com/netbirdio/netbird/client/iface/configurer"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,4 +17,5 @@ type WGIface interface {
|
|||||||
RemovePeer(peerKey string) error
|
RemovePeer(peerKey string) error
|
||||||
GetStats(peerKey string) (configurer.WGStats, error)
|
GetStats(peerKey string) (configurer.WGStats, error)
|
||||||
GetProxy() wgproxy.Proxy
|
GetProxy() wgproxy.Proxy
|
||||||
|
Address() wgaddr.Address
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -358,6 +358,12 @@ func extraSrflxCandidate(candidate ice.Candidate) (*ice.CandidateServerReflexive
|
|||||||
}
|
}
|
||||||
|
|
||||||
func candidateViaRoutes(candidate ice.Candidate, clientRoutes route.HAMap) bool {
|
func candidateViaRoutes(candidate ice.Candidate, clientRoutes route.HAMap) bool {
|
||||||
|
addr, err := netip.ParseAddr(candidate.Address())
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to parse IP address %s: %v", candidate.Address(), err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
var routePrefixes []netip.Prefix
|
var routePrefixes []netip.Prefix
|
||||||
for _, routes := range clientRoutes {
|
for _, routes := range clientRoutes {
|
||||||
if len(routes) > 0 && routes[0] != nil {
|
if len(routes) > 0 && routes[0] != nil {
|
||||||
@@ -365,14 +371,8 @@ func candidateViaRoutes(candidate ice.Candidate, clientRoutes route.HAMap) bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addr, err := netip.ParseAddr(candidate.Address())
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to parse IP address %s: %v", candidate.Address(), err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, prefix := range routePrefixes {
|
for _, prefix := range routePrefixes {
|
||||||
// default route is
|
// default route is handled by route exclusion / ip rules
|
||||||
if prefix.Bits() == 0 {
|
if prefix.Bits() == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,6 +160,12 @@ func (d *DnsInterceptor) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set the AuthenticatedData flag and the EDNS0 buffer size to 4096 bytes to support larger dns records
|
||||||
|
if r.Extra == nil {
|
||||||
|
r.SetEdns0(4096, false)
|
||||||
|
r.MsgHdr.AuthenticatedData = true
|
||||||
|
}
|
||||||
|
|
||||||
client := &dns.Client{
|
client := &dns.Client{
|
||||||
Timeout: 5 * time.Second,
|
Timeout: 5 * time.Second,
|
||||||
Net: "udp",
|
Net: "udp",
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package iface
|
|||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface"
|
|
||||||
"github.com/netbirdio/netbird/client/iface/configurer"
|
"github.com/netbirdio/netbird/client/iface/configurer"
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
type wgIfaceBase interface {
|
type wgIfaceBase interface {
|
||||||
@@ -13,7 +13,7 @@ type wgIfaceBase interface {
|
|||||||
RemoveAllowedIP(peerKey string, allowedIP string) error
|
RemoveAllowedIP(peerKey string, allowedIP string) error
|
||||||
|
|
||||||
Name() string
|
Name() string
|
||||||
Address() iface.WGAddress
|
Address() wgaddr.Address
|
||||||
ToInterface() *net.Interface
|
ToInterface() *net.Interface
|
||||||
IsUserspaceBind() bool
|
IsUserspaceBind() bool
|
||||||
GetFilter() device.PacketFilter
|
GetFilter() device.PacketFilter
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
</InstallExecuteSequence>
|
</InstallExecuteSequence>
|
||||||
|
|
||||||
<!-- Icons -->
|
<!-- Icons -->
|
||||||
<Icon Id="NetbirdIcon" SourceFile=".\client\ui\netbird.ico" />
|
<Icon Id="NetbirdIcon" SourceFile=".\client\ui\assets\netbird.ico" />
|
||||||
<Property Id="ARPPRODUCTICON" Value="NetbirdIcon" />
|
<Property Id="ARPPRODUCTICON" Value="NetbirdIcon" />
|
||||||
|
|
||||||
</Package>
|
</Package>
|
||||||
|
|||||||
@@ -5,5 +5,5 @@
|
|||||||
#define STRINGIZE(x) #x
|
#define STRINGIZE(x) #x
|
||||||
#define EXPAND(x) STRINGIZE(x)
|
#define EXPAND(x) STRINGIZE(x)
|
||||||
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST manifest.xml
|
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST manifest.xml
|
||||||
7 ICON ui/netbird.ico
|
7 ICON ui/assets/netbird.ico
|
||||||
wintun.dll RCDATA wintun.dll
|
wintun.dll RCDATA wintun.dll
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package server
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
windowsPanicLogEnvVar = "NB_WINDOWS_PANIC_LOG"
|
|
||||||
// STD_ERROR_HANDLE ((DWORD)-12) = 4294967284
|
// STD_ERROR_HANDLE ((DWORD)-12) = 4294967284
|
||||||
stdErrorHandle = ^uintptr(11)
|
stdErrorHandle = ^uintptr(11)
|
||||||
)
|
)
|
||||||
@@ -25,13 +24,10 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func handlePanicLog() error {
|
func handlePanicLog() error {
|
||||||
logPath := os.Getenv(windowsPanicLogEnvVar)
|
// TODO: move this to a central location
|
||||||
if logPath == "" {
|
logDir := path.Join(os.Getenv("PROGRAMDATA"), "Netbird")
|
||||||
return nil
|
logPath := path.Join(logDir, "netbird.err")
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure the directory exists
|
|
||||||
logDir := filepath.Dir(logPath)
|
|
||||||
if err := os.MkdirAll(logDir, 0750); err != nil {
|
if err := os.MkdirAll(logDir, 0750); err != nil {
|
||||||
return fmt.Errorf("create panic log directory: %w", err)
|
return fmt.Errorf("create panic log directory: %w", err)
|
||||||
}
|
}
|
||||||
@@ -39,13 +35,11 @@ func handlePanicLog() error {
|
|||||||
return fmt.Errorf("enforce permission on panic log file: %w", err)
|
return fmt.Errorf("enforce permission on panic log file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open log file with append mode
|
|
||||||
f, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
|
f, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("open panic log file: %w", err)
|
return fmt.Errorf("open panic log file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect stderr to the file
|
|
||||||
if err = redirectStderr(f); err != nil {
|
if err = redirectStderr(f); err != nil {
|
||||||
if closeErr := f.Close(); closeErr != nil {
|
if closeErr := f.Close(); closeErr != nil {
|
||||||
log.Warnf("failed to close file after redirect error: %v", closeErr)
|
log.Warnf("failed to close file after redirect error: %v", closeErr)
|
||||||
@@ -59,7 +53,6 @@ func handlePanicLog() error {
|
|||||||
|
|
||||||
// redirectStderr redirects stderr to the provided file
|
// redirectStderr redirects stderr to the provided file
|
||||||
func redirectStderr(f *os.File) error {
|
func redirectStderr(f *os.File) error {
|
||||||
// Get the current process's stderr handle
|
|
||||||
if err := setStdHandle(f); err != nil {
|
if err := setStdHandle(f); err != nil {
|
||||||
return fmt.Errorf("failed to set stderr handle: %w", err)
|
return fmt.Errorf("failed to set stderr handle: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ func (s *Server) Start() error {
|
|||||||
// mechanism to keep the client connected even when the connection is lost.
|
// mechanism to keep the client connected even when the connection is lost.
|
||||||
// we cancel retry if the client receive a stop or down command, or if disable auto connect is configured.
|
// we cancel retry if the client receive a stop or down command, or if disable auto connect is configured.
|
||||||
func (s *Server) connectWithRetryRuns(ctx context.Context, config *internal.Config, statusRecorder *peer.Status,
|
func (s *Server) connectWithRetryRuns(ctx context.Context, config *internal.Config, statusRecorder *peer.Status,
|
||||||
runningChan chan error,
|
runningChan chan struct{},
|
||||||
) {
|
) {
|
||||||
backOff := getConnectWithBackoff(ctx)
|
backOff := getConnectWithBackoff(ctx)
|
||||||
retryStarted := false
|
retryStarted := false
|
||||||
@@ -628,20 +628,21 @@ func (s *Server) Up(callerCtx context.Context, _ *proto.UpRequest) (*proto.UpRes
|
|||||||
s.statusRecorder.UpdateManagementAddress(s.config.ManagementURL.String())
|
s.statusRecorder.UpdateManagementAddress(s.config.ManagementURL.String())
|
||||||
s.statusRecorder.UpdateRosenpass(s.config.RosenpassEnabled, s.config.RosenpassPermissive)
|
s.statusRecorder.UpdateRosenpass(s.config.RosenpassEnabled, s.config.RosenpassPermissive)
|
||||||
|
|
||||||
runningChan := make(chan error)
|
timeoutCtx, cancel := context.WithTimeout(callerCtx, 50*time.Second)
|
||||||
go s.connectWithRetryRuns(ctx, s.config, s.statusRecorder, runningChan)
|
defer cancel()
|
||||||
|
|
||||||
|
runningChan := make(chan struct{}, 1) // buffered channel to do not lose the signal
|
||||||
|
go s.connectWithRetryRuns(ctx, s.config, s.statusRecorder, runningChan)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case err := <-runningChan:
|
case <-runningChan:
|
||||||
if err != nil {
|
return &proto.UpResponse{}, nil
|
||||||
log.Debugf("waiting for engine to become ready failed: %s", err)
|
|
||||||
} else {
|
|
||||||
return &proto.UpResponse{}, nil
|
|
||||||
}
|
|
||||||
case <-callerCtx.Done():
|
case <-callerCtx.Done():
|
||||||
log.Debug("context done, stopping the wait for engine to become ready")
|
log.Debug("context done, stopping the wait for engine to become ready")
|
||||||
return nil, callerCtx.Err()
|
return nil, callerCtx.Err()
|
||||||
|
case <-timeoutCtx.Done():
|
||||||
|
log.Debug("up is timed out, stopping the wait for engine to become ready")
|
||||||
|
return nil, timeoutCtx.Err()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |